summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--ChangeLog268
-rw-r--r--HACKING3
-rw-r--r--Makefile.am90
-rw-r--r--Makefile.in171
-rw-r--r--NEWS28
-rw-r--r--buildrun.cxx4
-rwxr-xr-xconfigure92
-rw-r--r--configure.ac30
-rw-r--r--cscope.files43
-rw-r--r--doc/.gitignore8
-rw-r--r--doc/ChangeLog8
-rw-r--r--doc/Makefile.in1
-rw-r--r--doc/tutorial.tex6
-rw-r--r--elaborate.cxx185
-rw-r--r--elaborate.h2
-rwxr-xr-xgit_version.sh348
-rw-r--r--main.cxx200
-rw-r--r--runtime/.gitignore1
-rw-r--r--runtime/ChangeLog140
-rw-r--r--runtime/autoconf-module-nsections.c8
-rw-r--r--runtime/copy.c34
-rw-r--r--runtime/debug.h60
-rw-r--r--runtime/map.c1
-rw-r--r--runtime/print.c1
-rw-r--r--runtime/print_new.c12
-rw-r--r--runtime/print_old.c12
-rw-r--r--runtime/probes.c12
-rw-r--r--runtime/regs.c394
-rw-r--r--runtime/regs.h4
-rw-r--r--runtime/runtime.h25
-rw-r--r--runtime/stack-arm.c4
-rw-r--r--runtime/stack-i386.c76
-rw-r--r--runtime/stack-x86_64.c42
-rw-r--r--runtime/stack.c29
-rw-r--r--runtime/staprun/ChangeLog57
-rw-r--r--runtime/staprun/cap.c78
-rw-r--r--runtime/staprun/common.c46
-rw-r--r--runtime/staprun/ctl.c35
-rw-r--r--runtime/staprun/mainloop.c296
-rw-r--r--runtime/staprun/stapio.c17
-rw-r--r--runtime/staprun/staprun.c173
-rw-r--r--runtime/staprun/staprun.h10
-rw-r--r--runtime/staprun/staprun_funcs.c104
-rw-r--r--runtime/staprun/symbols.c333
-rw-r--r--runtime/staprun/unwind_data.c97
-rw-r--r--runtime/sym.c11
-rw-r--r--runtime/sym.h25
-rw-r--r--runtime/task_finder.c250
-rw-r--r--runtime/time.c7
-rw-r--r--runtime/transport/ChangeLog48
-rw-r--r--runtime/transport/control.c226
-rw-r--r--runtime/transport/procfs.c2
-rw-r--r--runtime/transport/symbols.c640
-rw-r--r--runtime/transport/transport.c164
-rw-r--r--runtime/transport/transport.h20
-rw-r--r--runtime/transport/transport_msgs.h63
-rw-r--r--runtime/unwind.c964
-rw-r--r--runtime/unwind/i386.h135
-rw-r--r--runtime/unwind/unwind.h146
-rw-r--r--runtime/unwind/x86_64.h150
-rw-r--r--runtime/vsprintf.c6
-rw-r--r--session.h5
-rw-r--r--stap.1.in14
-rw-r--r--stapex.5.in6
-rw-r--r--stapprobes.5.in40
-rw-r--r--staprun.8.in9
-rw-r--r--staptree.cxx8
-rw-r--r--staptree.h4
-rw-r--r--systemtap.spec.in12
-rw-r--r--tapset/ChangeLog21
-rw-r--r--tapset/context.stp4
-rw-r--r--tapset/i686/registers.stp69
-rw-r--r--tapset/ioblock.stp2
-rw-r--r--tapset/scsi.stp5
-rw-r--r--tapset/tcp.stp65
-rw-r--r--tapset/x86_64/registers.stp99
-rw-r--r--tapsets.cxx736
-rw-r--r--testsuite/.gitignore4
-rw-r--r--testsuite/ChangeLog63
-rwxr-xr-xtestsuite/parseko/utrace01.stp4
-rwxr-xr-xtestsuite/semko/twelve.stp4
-rwxr-xr-xtestsuite/semko/utrace01.stp4
-rwxr-xr-xtestsuite/semko/utrace03.stp4
-rwxr-xr-xtestsuite/semko/utrace04.stp4
-rwxr-xr-xtestsuite/semko/utrace05.stp4
-rwxr-xr-xtestsuite/semko/utrace06.stp4
-rwxr-xr-xtestsuite/semko/utrace07.stp4
-rwxr-xr-xtestsuite/semko/utrace08.stp4
-rwxr-xr-xtestsuite/semko/utrace09.stp4
-rwxr-xr-xtestsuite/semko/utrace10.stp4
-rwxr-xr-xtestsuite/semko/utrace11.stp4
-rwxr-xr-xtestsuite/semko/utrace12.stp4
-rwxr-xr-xtestsuite/semko/utrace13.stp4
-rwxr-xr-xtestsuite/semok/optimize.stp18
-rwxr-xr-xtestsuite/semok/twenty.stp2
-rw-r--r--testsuite/systemtap.base/cache.exp4
-rw-r--r--testsuite/systemtap.base/cmd_parse.exp9
-rw-r--r--testsuite/systemtap.base/maxactive.exp6
-rw-r--r--testsuite/systemtap.base/utrace_p4.exp106
-rw-r--r--testsuite/systemtap.base/utrace_p5.exp140
-rw-r--r--testsuite/systemtap.base/warnings.exp4
-rw-r--r--testsuite/systemtap.context/backtrace.stp27
-rw-r--r--testsuite/systemtap.context/backtrace.tcl123
-rw-r--r--testsuite/systemtap.examples/ChangeLog (renamed from examples/ChangeLog)20
-rw-r--r--testsuite/systemtap.examples/README (renamed from examples/README)0
-rw-r--r--testsuite/systemtap.examples/check.exp75
-rw-r--r--testsuite/systemtap.examples/futexes.meta13
-rwxr-xr-xtestsuite/systemtap.examples/futexes.stp (renamed from examples/futexes.stp)0
-rw-r--r--testsuite/systemtap.examples/futexes.txt (renamed from examples/futexes.txt)0
-rw-r--r--testsuite/systemtap.examples/helloworld.meta13
-rwxr-xr-xtestsuite/systemtap.examples/helloworld.stp (renamed from examples/helloworld.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/iostat-scsi.stp (renamed from examples/iostat-scsi.stp)0
-rw-r--r--testsuite/systemtap.examples/iostat-scsi.txt (renamed from examples/iostat-scsi.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/iotime.stp (renamed from examples/iotime.stp)0
-rw-r--r--testsuite/systemtap.examples/nettop.meta13
-rwxr-xr-xtestsuite/systemtap.examples/nettop.stp (renamed from examples/nettop.stp)0
-rw-r--r--testsuite/systemtap.examples/nettop.txt (renamed from examples/nettop.txt)0
-rw-r--r--testsuite/systemtap.examples/pf2.meta13
-rwxr-xr-xtestsuite/systemtap.examples/pf2.stp (renamed from examples/pf2.stp)4
-rw-r--r--testsuite/systemtap.examples/pf2.txt (renamed from examples/pf2.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/sig_by_pid.stp (renamed from examples/sig_by_pid.stp)0
-rw-r--r--testsuite/systemtap.examples/sig_by_pid.txt (renamed from examples/sig_by_pid.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/sig_by_proc.stp (renamed from examples/sig_by_proc.stp)0
-rw-r--r--testsuite/systemtap.examples/sig_by_proc.txt (renamed from examples/sig_by_proc.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/sigmon.stp (renamed from examples/sigmon.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/sleeptime.stp (renamed from examples/sleeptime.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/ansi_colors.stp (renamed from examples/small_demos/ansi_colors.stp)0
-rw-r--r--testsuite/systemtap.examples/small_demos/click.wav (renamed from examples/small_demos/click.wav)bin1290 -> 1290 bytes
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/close.stp (renamed from examples/small_demos/close.stp)0
-rw-r--r--testsuite/systemtap.examples/small_demos/demo_script.txt (renamed from examples/small_demos/demo_script.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/fileopen.stp (renamed from examples/small_demos/fileopen.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/key.stp (renamed from examples/small_demos/key.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/keyhack.stp (renamed from examples/small_demos/keyhack.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/kmalloc.stp (renamed from examples/small_demos/kmalloc.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/kmalloc2.stp (renamed from examples/small_demos/kmalloc2.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/proc_snoop.stp (renamed from examples/small_demos/proc_snoop.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/prof.stp (renamed from examples/small_demos/prof.stp)0
-rw-r--r--testsuite/systemtap.examples/small_demos/return.wav (renamed from examples/small_demos/return.wav)bin6584 -> 6584 bytes
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/rwtiming.stp (renamed from examples/small_demos/rwtiming.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/sched_snoop.stp (renamed from examples/small_demos/sched_snoop.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/sys.stp (renamed from examples/small_demos/sys.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/small_demos/top.stp (renamed from examples/small_demos/top.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/socket-trace.stp (renamed from examples/socket-trace.stp)0
-rwxr-xr-xtestsuite/systemtap.examples/socktop (renamed from examples/socktop)0
-rw-r--r--testsuite/systemtap.examples/socktop.txt (renamed from examples/socktop.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/syscalls_by_pid.stp (renamed from examples/syscalls_by_pid.stp)0
-rw-r--r--testsuite/systemtap.examples/syscalls_by_pid.txt (renamed from examples/syscalls_by_pid.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/syscalls_by_proc.stp (renamed from examples/syscalls_by_proc.stp)0
-rw-r--r--testsuite/systemtap.examples/syscalls_by_proc.txt (renamed from examples/syscalls_by_proc.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/syscalltimes (renamed from examples/syscalltimes)0
-rw-r--r--testsuite/systemtap.examples/syscalltimes.txt (renamed from examples/syscalltimes.txt)0
-rwxr-xr-xtestsuite/systemtap.examples/wait4time.stp (renamed from examples/wait4time.stp)0
-rw-r--r--testsuite/systemtap.pass1-4/buildok.exp2
-rw-r--r--testsuite/systemtap.samples/args.exp4
-rwxr-xr-xtestsuite/transok/eight.stp3
-rw-r--r--translate.cxx188
-rw-r--r--vim/syntax/stap.vim83
158 files changed, 6100 insertions, 2448 deletions
diff --git a/.gitignore b/.gitignore
index 69bd5e97..b70c9e21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
.#*
autom4te.*
cscope*out
-Makefile
config.h
config.log
config.status
@@ -18,3 +17,13 @@ systemtap.spec
testresults
stapio
stap_merge
+CVS
+.checkstyle
+.cproject
+.metadata
+.project
+.settings
+SNAPSHOT
+*.o
+git_version.h
+Makefile
diff --git a/ChangeLog b/ChangeLog
index dbaf527b..e913e76b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,24 @@
-2008-05-06 Jim Keniston <jkenisto@us.ibm.com>
+2008-05-12 Jim Keniston <jkenisto@us.ibm.com>
PR 4311 - Function boundary tracing without debuginfo: Phase II
+ Merged dwarfless branch into mainline. But first...
+ * runtime/regs.c: Removed register name:value lookup facility.
+ Moved basically all register-lookup code to the i686 and x86_64
+ registers.stp tapsets. Args stuff shared between i386 and
+ x86_64 remains in regs.c.
+ * tapset/{i686,x86_64}/registers.stp: Moved register-lookup
+ code from runtime/regs.c to here.
+
+2008-05-12 Jim Keniston <jkenisto@us.ibm.com>
+
+ (2008-05-06 in dwarfless branch)
+ PR 4311 - Function boundary tracing without debuginfo: Phase II
* stapfuncs.5.in: Added sections on CPU REGISTERS and
NUMBERED FUNCTION ARGUMENTS.
-2008-05-05 Jim Keniston <jkenisto@us.ibm.com>
+2008-05-12 Jim Keniston <jkenisto@us.ibm.com>
+ (2008-05-05 in dwarfless branch)
PR 4311 - Function boundary tracing without debuginfo: Phase II
* runtime/regs.c: Added register name:value lookup facility.
Added support for register and arg lookup for i386 and x86_64.
@@ -16,8 +29,9 @@
* tapset/nd_syscall.stp: syscall.stp migrating toward numbered
args rather than named args.
-2008-04-18 Jim Keniston <jkenisto@us.ibm.com>
+2008-05-12 Jim Keniston <jkenisto@us.ibm.com>
+ (2008-04-18 in dwarfless branch)
PR 4311 - Function boundary tracing without debuginfo: Phase I
* tapsets.cxx: Major rework of dwflpp, dwarf_query, and related
code to make do with elf info if dwarf info is absent, or
@@ -29,6 +43,254 @@
--ignore-vmlinux, and --ignore-dwarf.
* testsuite/{semok,semko}/nodwf*.stp
+2008-05-07 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6492.
+ * main.cxx (main): let -l imply -w.
+
+2008-05-05 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 444886. From <crquan@gmail.com>:
+ * tapsets.cxx, translate.cxx: Add .../build/... to default debuginfo
+ path, to ease search for hand-built kernels.
+
+2008-05-01 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6474
+ * configure.ac (--enable-pie): Add default option.
+ * Makefile.am (stap* binaries): Use -fpie/-z relro/-z now as
+ applicable.
+ * configure, aclocal.m4, Makefile.in, doc/Makefile.in: Regenerated.
+
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 6008
+ * main.cxx (main): Increase the limitation of buffer size to 4095MB.
+ * staprun.8.in: Ditto.
+
+2008-04-29 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6466
+ * elaborate.cxx
+ (dead_stmtexpr_remover): Expand scope to kill far more
+ side-effect-free statemnets, including if/for/foreach.
+ (semantic_pass_opt4): Warn on elided function/probe bodies.
+ (typeresolution_info::visit_target_symbol): Dump parse tree of
+ resolution-challenged functions/probes.
+ (*): Adapt to probe->body being a statement*
+ rather than a block*.
+ * tapsets.cxx (*): Ditto.
+ * staptree.cxx (block::block ctor): New cons constructor.
+ * staptree.h: Corresponding changes.
+
+2008-04-29 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (utrace_derived_probe_group::emit_probe_decl): Added
+ death event handlers to ensure that for every utrace_attach there
+ is a corresponding utrace_detach.
+ (utrace_derived_probe_group::emit_module_decls): Ditto.
+
+2008-04-28 Frank Ch. Eigler <fche@elastic.org>
+
+ * translate.cxx (translate_pass): Don't #define TEST_MODE.
+
+2008-04-26 Frank Ch. Eigler <fche@elastic.org>
+
+ * tapsets.cxx (common_probe_entryfn_prologue): Undo
+ clear of overload-related context vars; add explanation why.
+
+2008-04-25 Frank Ch. Eigler <fche@elastic.org>
+
+ * 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.
+ * tapsets.cxx (mark_builder::build): Handles markers with no
+ format string.
+
+2008-04-24 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6454.
+ * main.cxx (printscript): Avoid string truncation heuristics, and
+ also avoid plain probe::printsig. Hold nose and dig down into
+ raw location lists instead.
+
+2008-04-24 Will Cohen <wcohen@redhat.com>
+
+ * aclocal.m4: Regenerated.
+ * Makefile.am (example/*): Moved to testsuite/systemtap.examples.
+ * Makefile.in: Regenerated.
+
+2008-04-23 Frank Ch. Eigler <fche@elastic.org>
+
+ From: Srinivasa DS <srinivasa@in.ibm.com>
+ * tapsets.cxx (blacklisted_p): Blacklist more init/exit sections.
+
+2008-04-23 Frank Ch. Eigler <fche@elastic.org>
+
+ * tapsets.cxx (common_probe_entryfn_prologue): Clear
+ overload-related context vars.
+
+2008-04-22 hunt <hunt@redhat.com>
+
+ * staprun.8.in: Add documentation for -d option.
+
+2008-04-22 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (utrace_derived_probe_group::emit_module_decls):
+ Removed debug statements.
+
+2008-04-18 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (struct utrace_builder): Added exec probes.
+ (utrace_derived_probe_group::emit_probe_decl): Ditto.
+ (utrace_derived_probe_group::emit_module_decls): Ditto.
+ (register_standard_tapsets): Ditto.
+ * stapprobes.5.in: Added information about exec probes.
+ * NEWS: Added information about utrace probes.
+
+ * stapprobes.5.in: Added information about utrace probes.
+
+2008-04-17 Josh Stone <joshua.i.stone@intel.com>
+
+ * tapsets.cxx (build_blacklist): Fix regexps for atomics.
+ * vim/syntax/stap.vim: Recognize the 'limit' keyword and script arguments,
+ allow '$' in variable names, and highlight $target variables.
+
+2008-04-17 David Smith <dsmith@redhat.com>
+
+ * tapsets.cxx (utrace_builder::build): Make sure that the PATH of
+ 'process("PATH")' probes is an absolute path.
+ (utrace_derived_probe_group::emit_module_decls): Made calls to
+ utrace probe handler functions conditional on which types of
+ utrace probes are going to be output.
+
+2008-04-16 Frank Ch. Eigler <fche@elastic.org>
+
+ * tapsets.cxx (task_finder_derived_probe): Add dummy constructor
+ for old (RHEL4) gcc compatibility.
+
+2008-04-16 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6417: From Srinivasa DS <srinivasa@in.ibm.com>:
+ * tapsets.cxx (build_blacklist): Extend.
+
+2008-04-15 David Smith <dsmith@redhat.com>
+
+ * session.h (struct systemtap_session): Added utrace_derived_probe
+ group and task_finder_derived_probe_group members.
+ * elaborate.cxx (systemtap_session::systemtap_session): Added
+ initialization of utrace_derived_probes and
+ task_finder_derived_probes.
+ * tapsets.cxx (struct task_finder_derived_probe_group): New
+ derived_probe_group to handle task_finder framework.
+ (struct utrace_derived_probe_group): New derived_probe_group to
+ handle utrace probes.
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6405 cont'd.
+ * Makefile.am (AM_CFLAGS): Remove -Wshadow, as it triggers for
+ new stapio (modname global vs. dwfl headers).
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6405
+ * buildrun.cxx (compile_pass): Add STAPCONF_MODULE_NSECTIONS.
+
+2008-04-14 David Smith <dsmith@redhat.com>
+
+ * elaborate.h (struct derived_probe_group): Removed
+ emit_module_header virtual function.
+ * translate.cxx (c_unparser::emit_common_header): Removed calls to
+ emit_module_header function.
+ * tapsets.cxx (be_derived_probe>): Removed emit_module_header function.
+ (struct timer_derived_probe_group): Ditto.
+ (struct profile_derived_probe_group): Ditto.
+ (struct procfs_derived_probe_group): Ditto.
+ (struct hrtimer_derived_probe_group): Ditto.
+ (struct perfmon_derived_probe_group): Ditto.
+ (dwarf_derived_probe_group::emit_module_decls): Moved kernel check
+ back from deleted emit_module_header function.
+ (uprobe_derived_probe_group::emit_module_decls): Ditto.
+ (mark_derived_probe_group::join_group): Moved marker
+ kernel check (to a new embedded code section) from deleted
+ emit_module_header function.
+
+2008-04-14 Frank Ch. Eigler <fche@elastic.org>
+
+ * Makefile.am (stapio_*): Become able to link/compile against
+ bundled elfutils.
+ * Makefile.in: Regenerated.
+
+2008-04-09 Martin Hunt <hunt@dragon>
+
+ * buildrun.cxx (run_pass): Remove unused "-d" option
+ passed to staprun.
+
+ * translate.cxx (emit_symbol_data): When available,
+ grab symbols from debuginfo instead of /proc/kallsyms.
+
+2008-04-11 David Smith <dsmith@redhat.com>
+
+ * elaborate.h (struct derived_probe_group): Added
+ emit_module_header virtual function.
+ * translate.cxx (c_unparser::emit_common_header): Calls each probe
+ group's emit_module_header function.
+ (translate_pass): Moved inclusion of linux/marker.h to
+ mark_derived_probe_group::emit_module_header().
+ * tapsets.cxx (struct be_derived_probe_group): Added empty
+ emit_module_header function.
+ (struct timer_derived_probe_group): Ditto.
+ (struct profile_derived_probe_group): Ditto.
+ (struct procfs_derived_probe_group): Ditto.
+ (struct hrtimer_derived_probe_group): Ditto.
+ (struct perfmon_derived_probe_group): Ditto.
+ (dwarf_derived_probe_group::emit_module_header): Moved kprobes
+ kernel check from emit_module_decls() to here.
+ (uprobe_derived_probe_group::emit_module_header): Moved uprobe
+ kernel check from emit_module_decls() to here.
+ (uprobe_derived_probe_group::emit_module_decls): Moved uprobe
+ kernel check to emit_module_header().
+ (mark_derived_probe_group::emit_module_header): Moved marker
+ kernel check from emit_module_decls and translate_pass() to here.
+ (uprobe_derived_probe_group::emit_module_decls): Moved marker
+ kernel check to emit_module_header().
+
+2008-04-10 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 2949.
+ * session.h (listing_mode): New field.
+ * main.cxx (main): Test it. Enjoy it.
+ (printscript): Do it.
+ (usage): Document it.
+ * stap.1.in, stapex.5.in: Ditto.
+ * elaborate.cxx (print_error): Disable error messages in listing mode.
+
+2008-04-10 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6393 cont'd.
+ * Makefile.am: Also copy RadeonHD.am fragment to force
+ git_version.h regeneration at every make, and also special
+ tagging for "make dist". Thanks <ndim>.
+
+2008-04-10 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6393.
+ * git_version.sh: New file, copied from radeonhd.
+ * configure.ac: No longer generate $builddir/SNAPSHOT.
+ * Makefile.am: Generate $builddir/git_version.h.
+ (EXTRA_DIST): Add git_version.h and git_version.sh.
+ * main.cxx (version): Print generated GIT_MESSAGE therefrom.
+ * Makefile.in, configure: Regenerated.
+
+2008-04-09 David Smith <dsmith@redhat.com>
+
+ * .gitignore: Added more files to ignore.
+
2008-04-04 Masami Hiramatsu <mhiramat@redhat.com>
PR 6028
diff --git a/HACKING b/HACKING
index 267f008a..de8b94b4 100644
--- a/HACKING
+++ b/HACKING
@@ -36,6 +36,9 @@ the <systemtap@sources.redhat.com> mailing list.
Some subdirectories have ChangeLog files of their own, so make sure
you find the correct ones to prepend.
+ In the git commit message, make the first line an brief summary of
+ the patch. There is no need to transcribe the ChangeLog entries there.
+
- test suites
As far as practicable, changes should be accompanied by test cases
diff --git a/Makefile.am b/Makefile.am
index 1fc4dbec..4eb1335b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,7 +7,7 @@ pkglibexecdir = ${libexecdir}/${PACKAGE}
AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"'
-AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wshadow -Wunused -Wformat=2 -W
+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
@@ -18,11 +18,55 @@ stap_SOURCES = main.cxx \
cache.cxx util.cxx coveragedb.cxx
stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@
+BUILT_SOURCES =
+CLEANFILES =
+
+# Arrange for git_version.h to be regenerated at every "make".
+# Code fragment is based upon RadeonHD.am.
+
+# The stamp file which is never created ensures that git_version.h is updated
+# before every build. Having git_version.h in foo_SOURCES ensures a recompile
+# 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
+CLEANFILES += git_version.h
+GIT_VERSION_CMD = $(SHELL) $(top_srcdir)/git_version.sh
+git_version.stamp:
+ @if test -f "$(srcdir)/git_version.h"; then \
+ if test -f "git_version.h"; then :; \
+ else \
+ cp "$(srcdir)/git_version.h" "git_version.h"; \
+ fi; \
+ fi
+ $(GIT_VERSION_CMD) -k -s $(top_srcdir) -o git_version.h
+ @if test -s "$(srcdir)/git_version.h"; then \
+ if cmp "$(srcdir)/git_version.h" "git_version.h"; then :; \
+ else \
+ echo "Error: $(srcdir)/git_version.h and git_version.h differ."; \
+ echo " You probably want to remove the former."; \
+ exit 1; \
+ fi; \
+ fi
+
+dist-gitversion: git_version.stamp
+ if test -f "git_version.h"; then \
+ sed -e 's|^#undef GIT_IS_DIST.*|#define GIT_IS_DIST 1|' \
+ "git_version.h" > "$(distdir)/git_version.h"; \
+ fi
+
+
+git_version.h:
+ $(srcdir)/git_version.sh -k --srcdir $(srcdir) -o git_version.h
+
+
+
stap_CXXFLAGS = $(AM_CXXFLAGS)
stap_CPPFLAGS = $(AM_CPPFLAGS)
-stap_LDFLAGS = $(AM_LDFLAGS)
-
-CLEANFILES =
+stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
+staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
+stapio_CPPFLAGS = $(AM_CPPFLAGS)
+stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
if BUILD_ELFUTILS
# This tells automake's "make distcheck" what we need to compile.
@@ -31,7 +75,12 @@ 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)
-BUILT_SOURCES = stamp-elfutils
+stapio_CPPFLAGS += -Iinclude-elfutils
+stapio_LDFLAGS += -Llib-elfutils -Wl,-rpath-link,lib-elfutils \
+ -Wl,--enable-new-dtags,-rpath,$(pkglibdir)
+
+
+BUILT_SOURCES += stamp-elfutils
CLEANFILES += stamp-elfutils
stamp-elfutils: config.status
$(MAKE) $(AM_MAKEFLAGS) -C build-elfutils all
@@ -53,19 +102,18 @@ endif
staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\
runtime/staprun/ctl.c runtime/staprun/common.c \
- runtime/staprun/cap.c runtime/staprun/symbols.c
+ runtime/staprun/cap.c
staprun_CPPFLAGS = $(AM_CPPFLAGS)
-staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS)
-staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ -lpthread
+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/ctl.c runtime/staprun/unwind_data.c \
runtime/staprun/relay.c runtime/staprun/relay_old.c
-
stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS)
-stapio_LDADD = @PROCFLAGS@ -lpthread
+stapio_LDADD = @PROCFLAGS@ -ldw -lpthread
install-exec-hook:
if [ `id -u` -eq 0 ]; then chmod 04111 "$(DESTDIR)$(bindir)/staprun"; fi
@@ -102,9 +150,13 @@ LDADD =
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 \
- examples testsuite systemtap.spec runtime tapset
+ testsuite systemtap.spec runtime tapset \
+ git_version.h git_version.sh
+
+EXAMPLE_DEST_DIR = $(distdir)/examples
+SAMPLE_DEST_DIR = $(EXAMPLE_DEST_DIR)/samples
-SAMPLE_DEST_DIR = $(distdir)/examples/samples
+EXAMPLE_SRC = $(srcdir)/testsuite/systemtap.examples
SAMPLE_SRC = $(srcdir)/testsuite/systemtap.samples/iotask.stp \
$(srcdir)/testsuite/systemtap.samples/kmalloc-stacks.stp \
@@ -114,21 +166,27 @@ SAMPLE_SRC = $(srcdir)/testsuite/systemtap.samples/iotask.stp \
$(srcdir)/testsuite/systemtap.samples/tcp_connections.stp \
$(srcdir)/testsuite/systemtap.samples/topsys.stp
+dist-add-examples: $(EXAMPLE_SRC)
+ rm -rf $(EXAMPLE_DEST_DIR)
+ mkdir -p $(EXAMPLE_DEST_DIR)
+ cp -a $(EXAMPLE_SRC)/* $(EXAMPLE_DEST_DIR)/.
+
# Copy some of the testsuite sample scripts to the distdir
# 'examples/samples' directory.
-dist-add-samples: $(SAMPLE_SRC)
+dist-add-samples: $(SAMPLE_SRC) dist-add-examples
rm -rf $(SAMPLE_DEST_DIR)
mkdir -p $(SAMPLE_DEST_DIR)
cp $(SAMPLE_SRC) $(SAMPLE_DEST_DIR)
-dist-hook: dist-add-samples
+dist-hook: dist-add-samples dist-gitversion
find $(distdir) -name CVS -o -name '*~' -o -name '.#*' | xargs rm -rf
find $(distdir) -name '*.o' -o -name '*.ko' -o -name '*.cmd' -o -name '*.mod.c' -o -name '.??*' | xargs rm -rf
find $(distdir) -name 'stap' -o -name '*.log' -o -name '*.sum' -o -name 'site.exp' | xargs rm -rf
install-data-local:
-# mkdir -p $(DESTDIR)$(pkgdatadir)/runtime/transport $(DESTDIR)$(pkgdatadir)/tapset
(cd $(srcdir)/runtime; for f in *.[ch]; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/$$f; done)
+ (cd $(srcdir)/runtime/unwind; find . \( -name '*.[ch]' \) -print \
+ | while read f; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/unwind/$$f; done)
(cd $(srcdir)/runtime/transport; for f in *.[ch]; \
do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/transport/$$f; done)
(cd $(srcdir)/runtime/uprobes; for f in Makefile *.[ch]; \
diff --git a/Makefile.in b/Makefile.in
index e82d66a3..8ff882b4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -37,7 +37,12 @@ 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 = stamp-elfutils
+@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_FALSE@stap_DEPENDENCIES =
pkglibexec_PROGRAMS = stapio$(EXEEXT)
noinst_PROGRAMS = loc2c-test$(EXEEXT)
@@ -102,18 +107,18 @@ 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-relay.$(OBJEXT) stapio-relay_old.$(OBJEXT)
+ stapio-unwind_data.$(OBJEXT) stapio-relay.$(OBJEXT) \
+ stapio-relay_old.$(OBJEXT)
stapio_OBJECTS = $(am_stapio_OBJECTS)
stapio_DEPENDENCIES =
-stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(stapio_LDFLAGS) \
$(LDFLAGS) -o $@
am_staprun_OBJECTS = staprun-staprun.$(OBJEXT) \
staprun-staprun_funcs.$(OBJEXT) staprun-ctl.$(OBJEXT) \
- staprun-common.$(OBJEXT) staprun-cap.$(OBJEXT) \
- staprun-symbols.$(OBJEXT)
+ staprun-common.$(OBJEXT) staprun-cap.$(OBJEXT)
staprun_OBJECTS = $(am_staprun_OBJECTS)
staprun_DEPENDENCIES =
-staprun_LINK = $(CCLD) $(staprun_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+staprun_LINK = $(CCLD) $(staprun_CFLAGS) $(CFLAGS) $(staprun_LDFLAGS) \
$(LDFLAGS) -o $@
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -204,6 +209,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
+PIELDFLAGS = @PIELDFLAGS@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
@@ -266,7 +272,7 @@ top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = dist-bzip2
pkglibexecdir = ${libexecdir}/${PACKAGE}
AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"'
-AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wshadow -Wunused -Wformat=2 -W
+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
stap_SOURCES = main.cxx \
@@ -275,29 +281,42 @@ stap_SOURCES = main.cxx \
cache.cxx util.cxx coveragedb.cxx
stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@
+
+# Arrange for git_version.h to be regenerated at every "make".
+# Code fragment is based upon RadeonHD.am.
+
+# The stamp file which is never created ensures that git_version.h is updated
+# before every build. Having git_version.h in foo_SOURCES ensures a recompile
+# 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)
+GIT_VERSION_CMD = $(SHELL) $(top_srcdir)/git_version.sh
stap_CXXFLAGS = $(AM_CXXFLAGS)
stap_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_1)
-stap_LDFLAGS = $(AM_LDFLAGS) $(am__append_2)
-CLEANFILES = $(am__append_3) $(pkglibexec_PROGRAMS)
+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)
# This tells automake's "make distcheck" what we need to compile.
@BUILD_ELFUTILS_TRUE@DISTCHECK_CONFIGURE_FLAGS = --with-elfutils=$(elfutils_abs_srcdir)
-@BUILD_ELFUTILS_TRUE@BUILT_SOURCES = stamp-elfutils
@BUILD_ELFUTILS_TRUE@stap_DEPENDENCIES = lib-elfutils/libdw.so
staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\
runtime/staprun/ctl.c runtime/staprun/common.c \
- runtime/staprun/cap.c runtime/staprun/symbols.c
+ runtime/staprun/cap.c
staprun_CPPFLAGS = $(AM_CPPFLAGS)
-staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS)
-staprun_LDADD = @PROCFLAGS@ @cap_LIBS@ -lpthread
+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/ctl.c runtime/staprun/unwind_data.c \
runtime/staprun/relay.c runtime/staprun/relay_old.c
stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS)
-stapio_LDADD = @PROCFLAGS@ -lpthread
+stapio_LDADD = @PROCFLAGS@ -ldw -lpthread
loc2c_test_SOURCES = loc2c-test.c loc2c.c
loc2c_test_CPPFLAGS = $(stap_CPPFLAGS)
loc2c_test_LDFLAGS = $(stap_LDFLAGS)
@@ -311,9 +330,12 @@ LDADD =
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 \
- examples testsuite systemtap.spec runtime tapset
+ testsuite systemtap.spec runtime tapset \
+ git_version.h git_version.sh
-SAMPLE_DEST_DIR = $(distdir)/examples/samples
+EXAMPLE_DEST_DIR = $(distdir)/examples
+SAMPLE_DEST_DIR = $(EXAMPLE_DEST_DIR)/samples
+EXAMPLE_SRC = $(srcdir)/testsuite/systemtap.examples
SAMPLE_SRC = $(srcdir)/testsuite/systemtap.samples/iotask.stp \
$(srcdir)/testsuite/systemtap.samples/kmalloc-stacks.stp \
$(srcdir)/testsuite/systemtap.samples/kmalloc-top \
@@ -505,12 +527,12 @@ 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@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-staprun.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-staprun_funcs.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-symbols.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -583,88 +605,102 @@ stap-mdfour.obj: mdfour.c
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stap-mdfour.obj `if test -f 'mdfour.c'; then $(CYGPATH_W) 'mdfour.c'; else $(CYGPATH_W) '$(srcdir)/mdfour.c'; fi`
stapio-stapio.o: runtime/staprun/stapio.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-stapio.o -MD -MP -MF $(DEPDIR)/stapio-stapio.Tpo -c -o stapio-stapio.o `test -f 'runtime/staprun/stapio.c' || echo '$(srcdir)/'`runtime/staprun/stapio.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-stapio.o -MD -MP -MF $(DEPDIR)/stapio-stapio.Tpo -c -o stapio-stapio.o `test -f 'runtime/staprun/stapio.c' || echo '$(srcdir)/'`runtime/staprun/stapio.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-stapio.Tpo $(DEPDIR)/stapio-stapio.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/stapio.c' object='stapio-stapio.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-stapio.o `test -f 'runtime/staprun/stapio.c' || echo '$(srcdir)/'`runtime/staprun/stapio.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-stapio.o `test -f 'runtime/staprun/stapio.c' || echo '$(srcdir)/'`runtime/staprun/stapio.c
stapio-stapio.obj: runtime/staprun/stapio.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-stapio.obj -MD -MP -MF $(DEPDIR)/stapio-stapio.Tpo -c -o stapio-stapio.obj `if test -f 'runtime/staprun/stapio.c'; then $(CYGPATH_W) 'runtime/staprun/stapio.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/stapio.c'; fi`
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-stapio.obj -MD -MP -MF $(DEPDIR)/stapio-stapio.Tpo -c -o stapio-stapio.obj `if test -f 'runtime/staprun/stapio.c'; then $(CYGPATH_W) 'runtime/staprun/stapio.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/stapio.c'; fi`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-stapio.Tpo $(DEPDIR)/stapio-stapio.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/stapio.c' object='stapio-stapio.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-stapio.obj `if test -f 'runtime/staprun/stapio.c'; then $(CYGPATH_W) 'runtime/staprun/stapio.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/stapio.c'; fi`
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-stapio.obj `if test -f 'runtime/staprun/stapio.c'; then $(CYGPATH_W) 'runtime/staprun/stapio.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/stapio.c'; fi`
stapio-mainloop.o: runtime/staprun/mainloop.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-mainloop.o -MD -MP -MF $(DEPDIR)/stapio-mainloop.Tpo -c -o stapio-mainloop.o `test -f 'runtime/staprun/mainloop.c' || echo '$(srcdir)/'`runtime/staprun/mainloop.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-mainloop.o -MD -MP -MF $(DEPDIR)/stapio-mainloop.Tpo -c -o stapio-mainloop.o `test -f 'runtime/staprun/mainloop.c' || echo '$(srcdir)/'`runtime/staprun/mainloop.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-mainloop.Tpo $(DEPDIR)/stapio-mainloop.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/mainloop.c' object='stapio-mainloop.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-mainloop.o `test -f 'runtime/staprun/mainloop.c' || echo '$(srcdir)/'`runtime/staprun/mainloop.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-mainloop.o `test -f 'runtime/staprun/mainloop.c' || echo '$(srcdir)/'`runtime/staprun/mainloop.c
stapio-mainloop.obj: runtime/staprun/mainloop.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-mainloop.obj -MD -MP -MF $(DEPDIR)/stapio-mainloop.Tpo -c -o stapio-mainloop.obj `if test -f 'runtime/staprun/mainloop.c'; then $(CYGPATH_W) 'runtime/staprun/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/mainloop.c'; fi`
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-mainloop.obj -MD -MP -MF $(DEPDIR)/stapio-mainloop.Tpo -c -o stapio-mainloop.obj `if test -f 'runtime/staprun/mainloop.c'; then $(CYGPATH_W) 'runtime/staprun/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/mainloop.c'; fi`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-mainloop.Tpo $(DEPDIR)/stapio-mainloop.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/mainloop.c' object='stapio-mainloop.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-mainloop.obj `if test -f 'runtime/staprun/mainloop.c'; then $(CYGPATH_W) 'runtime/staprun/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/mainloop.c'; fi`
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-mainloop.obj `if test -f 'runtime/staprun/mainloop.c'; then $(CYGPATH_W) 'runtime/staprun/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/mainloop.c'; fi`
stapio-common.o: runtime/staprun/common.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-common.o -MD -MP -MF $(DEPDIR)/stapio-common.Tpo -c -o stapio-common.o `test -f 'runtime/staprun/common.c' || echo '$(srcdir)/'`runtime/staprun/common.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-common.o -MD -MP -MF $(DEPDIR)/stapio-common.Tpo -c -o stapio-common.o `test -f 'runtime/staprun/common.c' || echo '$(srcdir)/'`runtime/staprun/common.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-common.Tpo $(DEPDIR)/stapio-common.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/common.c' object='stapio-common.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-common.o `test -f 'runtime/staprun/common.c' || echo '$(srcdir)/'`runtime/staprun/common.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-common.o `test -f 'runtime/staprun/common.c' || echo '$(srcdir)/'`runtime/staprun/common.c
stapio-common.obj: runtime/staprun/common.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-common.obj -MD -MP -MF $(DEPDIR)/stapio-common.Tpo -c -o stapio-common.obj `if test -f 'runtime/staprun/common.c'; then $(CYGPATH_W) 'runtime/staprun/common.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/common.c'; fi`
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-common.obj -MD -MP -MF $(DEPDIR)/stapio-common.Tpo -c -o stapio-common.obj `if test -f 'runtime/staprun/common.c'; then $(CYGPATH_W) 'runtime/staprun/common.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/common.c'; fi`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-common.Tpo $(DEPDIR)/stapio-common.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/common.c' object='stapio-common.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-common.obj `if test -f 'runtime/staprun/common.c'; then $(CYGPATH_W) 'runtime/staprun/common.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/common.c'; fi`
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-common.obj `if test -f 'runtime/staprun/common.c'; then $(CYGPATH_W) 'runtime/staprun/common.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/common.c'; fi`
stapio-ctl.o: runtime/staprun/ctl.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-ctl.o -MD -MP -MF $(DEPDIR)/stapio-ctl.Tpo -c -o stapio-ctl.o `test -f 'runtime/staprun/ctl.c' || echo '$(srcdir)/'`runtime/staprun/ctl.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-ctl.o -MD -MP -MF $(DEPDIR)/stapio-ctl.Tpo -c -o stapio-ctl.o `test -f 'runtime/staprun/ctl.c' || echo '$(srcdir)/'`runtime/staprun/ctl.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-ctl.Tpo $(DEPDIR)/stapio-ctl.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/ctl.c' object='stapio-ctl.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-ctl.o `test -f 'runtime/staprun/ctl.c' || echo '$(srcdir)/'`runtime/staprun/ctl.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-ctl.o `test -f 'runtime/staprun/ctl.c' || echo '$(srcdir)/'`runtime/staprun/ctl.c
stapio-ctl.obj: runtime/staprun/ctl.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-ctl.obj -MD -MP -MF $(DEPDIR)/stapio-ctl.Tpo -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`
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-ctl.obj -MD -MP -MF $(DEPDIR)/stapio-ctl.Tpo -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`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-ctl.Tpo $(DEPDIR)/stapio-ctl.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/ctl.c' object='stapio-ctl.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_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`
+@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) $(AM_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@ $(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
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/relay.c' object='stapio-relay.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay.o `test -f 'runtime/staprun/relay.c' || echo '$(srcdir)/'`runtime/staprun/relay.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay.o `test -f 'runtime/staprun/relay.c' || echo '$(srcdir)/'`runtime/staprun/relay.c
stapio-relay.obj: runtime/staprun/relay.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay.obj -MD -MP -MF $(DEPDIR)/stapio-relay.Tpo -c -o stapio-relay.obj `if test -f 'runtime/staprun/relay.c'; then $(CYGPATH_W) 'runtime/staprun/relay.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay.c'; fi`
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay.obj -MD -MP -MF $(DEPDIR)/stapio-relay.Tpo -c -o stapio-relay.obj `if test -f 'runtime/staprun/relay.c'; then $(CYGPATH_W) 'runtime/staprun/relay.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay.c'; fi`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-relay.Tpo $(DEPDIR)/stapio-relay.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/relay.c' object='stapio-relay.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay.obj `if test -f 'runtime/staprun/relay.c'; then $(CYGPATH_W) 'runtime/staprun/relay.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay.c'; fi`
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay.obj `if test -f 'runtime/staprun/relay.c'; then $(CYGPATH_W) 'runtime/staprun/relay.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay.c'; fi`
stapio-relay_old.o: runtime/staprun/relay_old.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay_old.o -MD -MP -MF $(DEPDIR)/stapio-relay_old.Tpo -c -o stapio-relay_old.o `test -f 'runtime/staprun/relay_old.c' || echo '$(srcdir)/'`runtime/staprun/relay_old.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay_old.o -MD -MP -MF $(DEPDIR)/stapio-relay_old.Tpo -c -o stapio-relay_old.o `test -f 'runtime/staprun/relay_old.c' || echo '$(srcdir)/'`runtime/staprun/relay_old.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-relay_old.Tpo $(DEPDIR)/stapio-relay_old.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/relay_old.c' object='stapio-relay_old.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay_old.o `test -f 'runtime/staprun/relay_old.c' || echo '$(srcdir)/'`runtime/staprun/relay_old.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay_old.o `test -f 'runtime/staprun/relay_old.c' || echo '$(srcdir)/'`runtime/staprun/relay_old.c
stapio-relay_old.obj: runtime/staprun/relay_old.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay_old.obj -MD -MP -MF $(DEPDIR)/stapio-relay_old.Tpo -c -o stapio-relay_old.obj `if test -f 'runtime/staprun/relay_old.c'; then $(CYGPATH_W) 'runtime/staprun/relay_old.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay_old.c'; fi`
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -MT stapio-relay_old.obj -MD -MP -MF $(DEPDIR)/stapio-relay_old.Tpo -c -o stapio-relay_old.obj `if test -f 'runtime/staprun/relay_old.c'; then $(CYGPATH_W) 'runtime/staprun/relay_old.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay_old.c'; fi`
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stapio-relay_old.Tpo $(DEPDIR)/stapio-relay_old.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/relay_old.c' object='stapio-relay_old.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay_old.obj `if test -f 'runtime/staprun/relay_old.c'; then $(CYGPATH_W) 'runtime/staprun/relay_old.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay_old.c'; fi`
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stapio_CPPFLAGS) $(CPPFLAGS) $(stapio_CFLAGS) $(CFLAGS) -c -o stapio-relay_old.obj `if test -f 'runtime/staprun/relay_old.c'; then $(CYGPATH_W) 'runtime/staprun/relay_old.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/relay_old.c'; fi`
staprun-staprun.o: runtime/staprun/staprun.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-staprun.o -MD -MP -MF $(DEPDIR)/staprun-staprun.Tpo -c -o staprun-staprun.o `test -f 'runtime/staprun/staprun.c' || echo '$(srcdir)/'`runtime/staprun/staprun.c
@@ -736,20 +772,6 @@ staprun-cap.obj: runtime/staprun/cap.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-cap.obj `if test -f 'runtime/staprun/cap.c'; then $(CYGPATH_W) 'runtime/staprun/cap.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/cap.c'; fi`
-staprun-symbols.o: runtime/staprun/symbols.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-symbols.o -MD -MP -MF $(DEPDIR)/staprun-symbols.Tpo -c -o staprun-symbols.o `test -f 'runtime/staprun/symbols.c' || echo '$(srcdir)/'`runtime/staprun/symbols.c
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-symbols.Tpo $(DEPDIR)/staprun-symbols.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/symbols.c' object='staprun-symbols.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-symbols.o `test -f 'runtime/staprun/symbols.c' || echo '$(srcdir)/'`runtime/staprun/symbols.c
-
-staprun-symbols.obj: runtime/staprun/symbols.c
-@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-symbols.obj -MD -MP -MF $(DEPDIR)/staprun-symbols.Tpo -c -o staprun-symbols.obj `if test -f 'runtime/staprun/symbols.c'; then $(CYGPATH_W) 'runtime/staprun/symbols.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/symbols.c'; fi`
-@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-symbols.Tpo $(DEPDIR)/staprun-symbols.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/symbols.c' object='staprun-symbols.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -c -o staprun-symbols.obj `if test -f 'runtime/staprun/symbols.c'; then $(CYGPATH_W) 'runtime/staprun/symbols.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/symbols.c'; fi`
-
.cxx.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@@ -1458,6 +1480,31 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8
uninstall-man uninstall-man1 uninstall-man5 uninstall-man8 \
uninstall-pkglibexecPROGRAMS
+git_version.stamp:
+ @if test -f "$(srcdir)/git_version.h"; then \
+ if test -f "git_version.h"; then :; \
+ else \
+ cp "$(srcdir)/git_version.h" "git_version.h"; \
+ fi; \
+ fi
+ $(GIT_VERSION_CMD) -k -s $(top_srcdir) -o git_version.h
+ @if test -s "$(srcdir)/git_version.h"; then \
+ if cmp "$(srcdir)/git_version.h" "git_version.h"; then :; \
+ else \
+ echo "Error: $(srcdir)/git_version.h and git_version.h differ."; \
+ echo " You probably want to remove the former."; \
+ exit 1; \
+ fi; \
+ fi
+
+dist-gitversion: git_version.stamp
+ if test -f "git_version.h"; then \
+ sed -e 's|^#undef GIT_IS_DIST.*|#define GIT_IS_DIST 1|' \
+ "git_version.h" > "$(distdir)/git_version.h"; \
+ fi
+
+git_version.h:
+ $(srcdir)/git_version.sh -k --srcdir $(srcdir) -o git_version.h
@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 \
@@ -1485,21 +1532,27 @@ install-exec-hook:
@BUILD_CRASHMOD_TRUE@ $(MKDIR_P) $(DESTDIR)$(pkglibdir)
@BUILD_CRASHMOD_TRUE@ $(INSTALL) $(STAPLOG) $(DESTDIR)$(pkglibdir)
+dist-add-examples: $(EXAMPLE_SRC)
+ rm -rf $(EXAMPLE_DEST_DIR)
+ mkdir -p $(EXAMPLE_DEST_DIR)
+ cp -a $(EXAMPLE_SRC)/* $(EXAMPLE_DEST_DIR)/.
+
# Copy some of the testsuite sample scripts to the distdir
# 'examples/samples' directory.
-dist-add-samples: $(SAMPLE_SRC)
+dist-add-samples: $(SAMPLE_SRC) dist-add-examples
rm -rf $(SAMPLE_DEST_DIR)
mkdir -p $(SAMPLE_DEST_DIR)
cp $(SAMPLE_SRC) $(SAMPLE_DEST_DIR)
-dist-hook: dist-add-samples
+dist-hook: dist-add-samples dist-gitversion
find $(distdir) -name CVS -o -name '*~' -o -name '.#*' | xargs rm -rf
find $(distdir) -name '*.o' -o -name '*.ko' -o -name '*.cmd' -o -name '*.mod.c' -o -name '.??*' | xargs rm -rf
find $(distdir) -name 'stap' -o -name '*.log' -o -name '*.sum' -o -name 'site.exp' | xargs rm -rf
install-data-local:
-# mkdir -p $(DESTDIR)$(pkgdatadir)/runtime/transport $(DESTDIR)$(pkgdatadir)/tapset
(cd $(srcdir)/runtime; for f in *.[ch]; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/$$f; done)
+ (cd $(srcdir)/runtime/unwind; find . \( -name '*.[ch]' \) -print \
+ | while read f; do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/unwind/$$f; done)
(cd $(srcdir)/runtime/transport; for f in *.[ch]; \
do $(INSTALL_DATA) -D $$f $(DESTDIR)$(pkgdatadir)/runtime/transport/$$f; done)
(cd $(srcdir)/runtime/uprobes; for f in Makefile *.[ch]; \
diff --git a/NEWS b/NEWS
index fd9df29d..03fb7117 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,31 @@
+* What's new in version 0.7
+
+- 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.
+
+- A probe listing mode is available.
+ % stap -l vm.*
+ vm.brk
+ vm.mmap
+ vm.munmap
+ vm.oom_kill
+ vm.pagefault
+ vm.write_shared
+
+- 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).syscall { }
+ probe process("PATH").syscall { }
+ probe process(PID).syscall.return { }
+ probe process("PATH").syscall.return { }
+
* What's new in version 0.6
- A copy of the systemtap tutorial and language reference guide
diff --git a/buildrun.cxx b/buildrun.cxx
index f3e72272..76efe7c0 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -93,9 +93,9 @@ compile_pass (systemtap_session& s)
o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-tsc-khz.c, -DSTAPCONF_TSC_KHZ,)" << endl;
o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-ktime-get-real.c, -DSTAPCONF_KTIME_GET_REAL,)" << endl;
o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-x86-uniregs.c, -DSTAPCONF_X86_UNIREGS,)" << endl;
-
o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-nameidata.c, -DSTAPCONF_NAMEIDATA_CLEANUP,)" << endl;
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;
for (unsigned i=0; i<s.macros.size(); i++)
o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl;
@@ -254,8 +254,6 @@ run_pass (systemtap_session& s)
+ (s.verbose>2 ? "-v " : "")
+ (s.output_file.empty() ? "" : "-o " + s.output_file + " ");
- staprun_cmd += "-d " + stringify(getpid()) + " ";
-
if (s.cmd != "")
staprun_cmd += "-c " + cmdstr_quoted(s.cmd) + " ";
diff --git a/configure b/configure
index c8be8582..866e9b16 100755
--- a/configure
+++ b/configure
@@ -705,6 +705,7 @@ EGREP
U
ANSI2KNR
RANLIB
+PIELDFLAGS
sqlite3_LIBS
staplog_CPPFLAGS
BUILD_CRASHMOD_TRUE
@@ -1324,6 +1325,7 @@ Optional Features:
location).
--enable-prologues make -P prologue-searching default
--disable-ssp disable gcc stack-protector
+ --disable-pie disable position-independent-executable
--enable-sqlite build with sqlite support
--enable-crash[=DIRECTORY]
enable crash extension (default is disabled).
@@ -6007,6 +6009,67 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
+# Check whether --enable-pie was given.
+if test "${enable_pie+set}" = set; then
+ enableval=$enable_pie;
+fi
+
+if test "x$enable_pie" != xno; then
+
+ save_CFLAGS="$CFLAGS"
+ save_CXXFLAGS="$CXXFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ CFLAGS="$CFLAGS -fpie"
+ CXXFLAGS="$CXXFLAGS -fpie"
+ LDFLAGS="$LDFLAGS -pie -Wl,-z,relro -Wl,-z,now"
+ cat >conftest.$ac_ext <<_ACEOF
+void main () {}
+_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
+
+ { echo "$as_me:$LINENO: Compiling with gcc pie et al." >&5
+echo "$as_me: Compiling with gcc pie et al." >&6;}
+ # LDFLAGS is special since it may be passed down to bundled-elfutils,
+ # and interfere with the .so's built therein
+ PIELDFLAGS="$LDFLAGS -pie -Wl,-z,relro -Wl,-z,now"
+ LDFLAGS="$save_LDFLAGS"
+
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+ { echo "$as_me:$LINENO: Compiler does not support -pie et al." >&5
+echo "$as_me: Compiler does not support -pie et al." >&6;}
+ CFLAGS="$save_CFLAGS"
+ CXXFLAGS="$save_CXXFLAGS"
+ PIELDFLAGS=""
+ LDFLAGS="$save_LDFLAGS"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+
# Check whether --enable-sqlite was given.
if test "${enable_sqlite+set}" = set; then
enableval=$enable_sqlite;
@@ -6812,13 +6875,6 @@ cap_LIBS="$LIBS"
LIBS="$SAVE_LIBS"
CFLAGS="$SAVE_CFLAGS"
-if test -d $srcdir/.git -a ! -f $srcdir/SNAPSHOT; then
- snapshot=`cd $srcdir; git-rev-list --abbrev-commit --max-count=1 HEAD`
- echo $snapshot > SNAPSHOT
- { echo "$as_me:$LINENO: Created git SNAPSHOT $snapshot" >&5
-echo "$as_me: Created git SNAPSHOT $snapshot" >&6;}
-fi
-
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"
@@ -7620,12 +7676,12 @@ EGREP!$EGREP$ac_delim
U!$U$ac_delim
ANSI2KNR!$ANSI2KNR$ac_delim
RANLIB!$RANLIB$ac_delim
+PIELDFLAGS!$PIELDFLAGS$ac_delim
sqlite3_LIBS!$sqlite3_LIBS$ac_delim
staplog_CPPFLAGS!$staplog_CPPFLAGS$ac_delim
BUILD_CRASHMOD_TRUE!$BUILD_CRASHMOD_TRUE$ac_delim
BUILD_CRASHMOD_FALSE!$BUILD_CRASHMOD_FALSE$ac_delim
have_latex!$have_latex$ac_delim
-have_dvips!$have_dvips$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
@@ -7667,6 +7723,7 @@ _ACEOF
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
cat >conf$$subs.sed <<_ACEOF
+have_dvips!$have_dvips$ac_delim
have_ps2pdf!$have_ps2pdf$ac_delim
have_latex2html!$have_latex2html$ac_delim
BUILD_DOCS_TRUE!$BUILD_DOCS_TRUE$ac_delim
@@ -7683,7 +7740,7 @@ LIBOBJS!$LIBOBJS$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 14; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 15; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
@@ -8084,21 +8141,22 @@ echo "$as_me: $ac_file is unchanged" >&6;}
fi
rm -f "$tmp/out12"
# Compute $ac_file's index in $config_headers.
+_am_arg=$ac_file
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
- $ac_file | $ac_file:* )
+ $_am_arg | $_am_arg:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
-echo "timestamp for $ac_file" >`$as_dirname -- $ac_file ||
-$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X$ac_file : 'X\(//\)[^/]' \| \
- X$ac_file : 'X\(//\)$' \| \
- X$ac_file : 'X\(/\)' \| . 2>/dev/null ||
-echo X$ac_file |
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$_am_arg" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -8135,7 +8193,7 @@ echo "$as_me: executing $ac_file commands" >&6;}
# each Makefile.in and add a new line on top of each file to say so.
# Grep'ing the whole file is not good either: AIX grep has a line
# limit of 2048, but all sed's we know have understand at least 4000.
- if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
dirpart=`$as_dirname -- "$mf" ||
$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$mf" : 'X\(//\)[^/]' \| \
diff --git a/configure.ac b/configure.ac
index fa14516c..4d0a4263 100644
--- a/configure.ac
+++ b/configure.ac
@@ -81,6 +81,29 @@ AS_IF([test "x$enable_ssp" != xno],[
CFLAGS="$save_CFLAGS"
CXXFLAGS="$save_CXXFLAGS"])])
+AC_ARG_ENABLE([pie],
+ [AS_HELP_STRING([--disable-pie], [disable position-independent-executable])])
+AS_IF([test "x$enable_pie" != xno],[
+ save_CFLAGS="$CFLAGS"
+ save_CXXFLAGS="$CXXFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ 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.])
+ # LDFLAGS is special since it may be passed down to bundled-elfutils,
+ # and interfere with the .so's built therein
+ PIELDFLAGS="$LDFLAGS -pie -Wl,-z,relro -Wl,-z,now"
+ LDFLAGS="$save_LDFLAGS"
+ ],[
+ AC_MSG_NOTICE([Compiler does not support -pie et al.])
+ CFLAGS="$save_CFLAGS"
+ CXXFLAGS="$save_CXXFLAGS"
+ PIELDFLAGS=""
+ LDFLAGS="$save_LDFLAGS"])])
+AC_SUBST(PIELDFLAGS)
+
dnl Handle optional sqlite support. If enabled/disabled by the user,
dnl do the right thing. If not specified by the user, use it if
dnl present.
@@ -204,13 +227,6 @@ AC_SUBST(cap_LIBS)
LIBS="$SAVE_LIBS"
CFLAGS="$SAVE_CFLAGS"
-dnl Create SNAPSHOT file from git commit id if possible
-if test -d $srcdir/.git -a ! -f $srcdir/SNAPSHOT; then
- snapshot=`cd $srcdir; git-rev-list --abbrev-commit --max-count=1 HEAD`
- echo $snapshot > SNAPSHOT
- AC_MSG_NOTICE([Created git SNAPSHOT $snapshot])
-fi
-
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_SUBDIRS(testsuite)
diff --git a/cscope.files b/cscope.files
index e4f44b2c..d2d0e462 100644
--- a/cscope.files
+++ b/cscope.files
@@ -8,6 +8,7 @@
./coveragedb.h
./elaborate.cxx
./elaborate.h
+./git_version.h
./hash.cxx
./hash.h
./loc2c.c
@@ -20,11 +21,19 @@
./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
@@ -36,6 +45,7 @@
./runtime/map-gen.c
./runtime/map.h
./runtime/map-stat.c
+./runtime/mempool.c
./runtime/perf.c
./runtime/perf.h
./runtime/pmap-gen.c
@@ -61,6 +71,7 @@
./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
@@ -72,14 +83,19 @@
./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
@@ -87,6 +103,7 @@
./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
@@ -132,15 +149,27 @@
./runtime/transport/transport_msgs.h
./runtime/transport/utt.c
./runtime/transport/utt.h
-./runtime/user/alloc.c
-./runtime/user/copy.c
-./runtime/user/emul.h
-./runtime/user/io.c
-./runtime/user/print.c
-./runtime/user/runtime.h
-./runtime/user/test.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
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 00000000..d8a93302
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,8 @@
+*.aux
+*.glo
+*.idx
+*.log
+*.lot
+*.out
+*.pdf
+*.toc
diff --git a/doc/ChangeLog b/doc/ChangeLog
index e652078d..16a3c111 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,11 @@
+2008-04-24 Will Cohen <wcohen@redhat.com>
+
+ * Makefile.in: Regenerated.
+
+2008-04-09 David Smith <dsmith@redhat.com>
+
+ * .gitignore: New file.
+
2008-03-25 Frank Ch. Eigler <fche@elastic.org>
* langref.tex: Clarify utility of epilogue-type probe aliases.
diff --git a/doc/Makefile.in b/doc/Makefile.in
index e76f154d..a2700d3c 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -88,6 +88,7 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
+PIELDFLAGS = @PIELDFLAGS@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
diff --git a/doc/tutorial.tex b/doc/tutorial.tex
index 58673467..3a04900b 100644
--- a/doc/tutorial.tex
+++ b/doc/tutorial.tex
@@ -175,8 +175,10 @@ in a source file, say \verb+net/socket.c+ in the kernel. The
systemtap examines the kernel's debugging information to relate object
code to source code. It works like a debugger: if you can name or
place it, you can probe it. Use
-\verb+kernel.function("*@net/socket.c")+ for the function entries, and
-\verb+kernel.function("*@net/socket.c").return+ for the exits. Note
+\verb+kernel.function("*@net/socket.c").call+ for the function
+entries\footnote{Without the {\tt .call} qualifier, inlined function
+instances are also probed, but they have no corresponding {\tt .return}.},
+and \verb+kernel.function("*@net/socket.c").return+ for matching exits. Note
the use of wildcards in the function name part, and the subsequent
\verb+@FILENAME+ part. You can also put wildcards into the file name,
and even add a colon (\verb+:+) and a line number, if you want to
diff --git a/elaborate.cxx b/elaborate.cxx
index 2d9fa7bc..306baff1 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -492,7 +492,6 @@ alias_expansion_builder
// the token location of the alias,
n->tok = location->tok;
- n->body->tok = location->tok;
// and statements representing the concatenation of the alias'
// body with the use's.
@@ -503,25 +502,9 @@ alias_expansion_builder
// resulting variable.
if (alias->epilogue_style)
- {
- for (unsigned i = 0; i < use->body->statements.size(); ++i)
- n->body->statements.push_back
- (deep_copy_visitor::deep_copy(use->body->statements[i]));
-
- for (unsigned i = 0; i < alias->body->statements.size(); ++i)
- n->body->statements.push_back
- (deep_copy_visitor::deep_copy(alias->body->statements[i]));
- }
+ n->body = new block (use->body, alias->body);
else
- {
- for (unsigned i = 0; i < alias->body->statements.size(); ++i)
- n->body->statements.push_back
- (deep_copy_visitor::deep_copy(alias->body->statements[i]));
-
- for (unsigned i = 0; i < use->body->statements.size(); ++i)
- n->body->statements.push_back
- (deep_copy_visitor::deep_copy(use->body->statements[i]));
- }
+ n->body = new block (alias->body, use->body);
derive_probes (sess, n, finished_results, location->optional);
}
@@ -1041,7 +1024,7 @@ semantic_pass_conditions (systemtap_session & sess)
notex->tok = e->tok;
notex->operand = e;
ifs->condition = notex;
- p->body->statements.insert (p->body->statements.begin(), ifs);
+ p->body = new block (ifs, p->body);
}
}
@@ -1197,6 +1180,8 @@ systemtap_session::systemtap_session ():
be_derived_probes(0),
dwarf_derived_probes(0),
uprobe_derived_probes(0),
+ utrace_derived_probes(0),
+ task_finder_derived_probes(0),
timer_derived_probes(0),
profile_derived_probes(0),
mark_derived_probes(0),
@@ -1214,6 +1199,9 @@ systemtap_session::print_error (const semantic_error& e)
string message_str;
stringstream message;
+ // NB: we don't print error messages during listing mode.
+ if (listing_mode) return;
+
message << "semantic error: " << e.what ();
if (e.tok1 || e.tok2)
message << ": ";
@@ -1794,6 +1782,7 @@ struct dead_stmtexpr_remover: public traversing_visitor
session(s), relaxed_p(r), current_stmt(0) {}
void visit_block (block *s);
+ void visit_null_statement (null_statement *s);
void visit_if_statement (if_statement* s);
void visit_foreach_loop (foreach_loop *s);
void visit_for_loop (for_loop *s);
@@ -1804,15 +1793,44 @@ struct dead_stmtexpr_remover: public traversing_visitor
void
+dead_stmtexpr_remover::visit_null_statement (null_statement *s)
+{
+ // easy!
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free null statement " << *s->tok << endl;
+ *current_stmt = 0;
+}
+
+
+void
dead_stmtexpr_remover::visit_block (block *s)
{
- for (unsigned i=0; i<s->statements.size(); i++)
+ vector<statement*> new_stmts;
+ for (unsigned i=0; i<s->statements.size(); i++ )
{
statement** last_stmt = current_stmt;
current_stmt = & s->statements[i];
s->statements[i]->visit (this);
+ if (*current_stmt != 0)
+ new_stmts.push_back (*current_stmt);
current_stmt = last_stmt;
}
+ if (new_stmts.size() == 0)
+ {
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free empty block " << *s->tok << endl;
+ *current_stmt = 0;
+ }
+ else if (new_stmts.size() == 1)
+ {
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free singleton block " << *s->tok << endl;
+ *current_stmt = new_stmts[0];
+ }
+ else
+ {
+ s->statements = new_stmts;
+ }
}
void
@@ -1821,12 +1839,36 @@ dead_stmtexpr_remover::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);
+ // null *current_stmt is OK here.
}
current_stmt = last_stmt;
+
+ if (s->elseblock == 0 && 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 (session.verbose>2)
+ clog << "Eliding side-effect-free if statement " << *s->tok << endl;
+ *current_stmt = 0; // yeah, baby
+ return;
+ }
+ }
+
+ 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
@@ -1836,6 +1878,13 @@ dead_stmtexpr_remover::visit_foreach_loop (foreach_loop *s)
current_stmt = & s->block;
s->block->visit (this);
current_stmt = last_stmt;
+
+ if (s->block == 0)
+ {
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free foreach statement " << *s->tok << endl;
+ *current_stmt = 0; // yeah, baby
+ }
}
void
@@ -1845,6 +1894,27 @@ dead_stmtexpr_remover::visit_for_loop (for_loop *s)
current_stmt = & s->block;
s->block->visit (this);
current_stmt = last_stmt;
+
+ if (s->block == 0)
+ {
+ // We may be able to elide this statement, if the condition
+ // expression is side-effect-free.
+ varuse_collecting_visitor vct;
+ if (s->init) s->init->visit(& vct);
+ s->cond->visit(& vct);
+ if (s->incr) s->incr->visit(& vct);
+ if (vct.side_effect_free ())
+ {
+ if (session.verbose>2)
+ clog << "Eliding side-effect-free for statement " << *s->tok << endl;
+ *current_stmt = 0; // yeah, baby
+ return;
+ }
+
+ // Can't elide this whole statement; put a null in there.
+ s->block = new null_statement();
+ s->block->tok = s->tok;
+ }
}
@@ -1881,14 +1951,10 @@ dead_stmtexpr_remover::visit_expr_statement (expr_statement *s)
clog << "Eliding side-effect-free expression "
<< *s->tok << endl;
- null_statement* ns = new null_statement;
- ns->tok = s->tok;
- * current_stmt = ns;
- // XXX: A null_statement carries more weight in the translator's
- // output than a nonexistent statement. It might be nice to
- // work a little harder and completely eliminate all traces of
- // an elided statement.
-
+ // NB: this 0 pointer is invalid to leave around for any length of
+ // time, but the parent parse tree objects above handle it.
+ * current_stmt = 0;
+
relaxed_p = false;
}
}
@@ -1905,23 +1971,48 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
for (unsigned i=0; i<s.probes.size(); i++)
{
+ derived_probe* p = s.probes[i];
+
duv.focal_vars.clear ();
duv.focal_vars.insert (s.globals.begin(),
s.globals.end());
- duv.focal_vars.insert (s.probes[i]->locals.begin(),
- s.probes[i]->locals.end());
- s.probes[i]->body->visit (& duv);
+ duv.focal_vars.insert (p->locals.begin(),
+ p->locals.end());
+
+ duv.current_stmt = & p->body;
+ p->body->visit (& duv);
+ if (p->body == 0)
+ {
+ if (! s.suppress_warnings)
+ clog << "WARNING: side-effect-free probe '" << p->name << "' "
+ << *p->tok << endl;
+
+ p->body = new null_statement();
+ p->body->tok = p->tok;
+ }
}
for (unsigned i=0; i<s.functions.size(); i++)
{
+ functiondecl* fn = s.functions[i];
duv.focal_vars.clear ();
- duv.focal_vars.insert (s.functions[i]->locals.begin(),
- s.functions[i]->locals.end());
- duv.focal_vars.insert (s.functions[i]->formal_args.begin(),
- s.functions[i]->formal_args.end());
+ duv.focal_vars.insert (fn->locals.begin(),
+ fn->locals.end());
+ duv.focal_vars.insert (fn->formal_args.begin(),
+ fn->formal_args.end());
duv.focal_vars.insert (s.globals.begin(),
s.globals.end());
- s.functions[i]->body->visit (& duv);
+
+ duv.current_stmt = & fn->body;
+ fn->body->visit (& duv);
+ if (fn->body == 0)
+ {
+ if (! s.suppress_warnings)
+ clog << "WARNING: side-effect-free function '" << fn->name << "' "
+ << *fn->tok << endl;
+
+ fn->body = new null_statement();
+ fn->body->tok = fn->tok;
+ }
}
}
@@ -2504,6 +2595,26 @@ typeresolution_info::visit_target_symbol (target_symbol* e)
// later unused-expression-elimination pass didn't get rid of it
// either. So we have a target symbol that is believed to be of
// genuine use, yet unresolved by the provider.
+
+ if (session.verbose > 2)
+ {
+ clog << "Resolution problem with ";
+ if (current_function)
+ {
+ clog << "function " << current_function->name << endl;
+ current_function->body->print (clog);
+ clog << endl;
+ }
+ else if (current_probe)
+ {
+ clog << "probe " << current_probe->name << endl;
+ current_probe->body->print (clog);
+ clog << endl;
+ }
+ else
+ clog << "other" << endl;
+ }
+
if (e->saved_conversion_error)
throw (* (e->saved_conversion_error));
else
diff --git a/elaborate.h b/elaborate.h
index fc8fbbcb..30bf5bce 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -114,6 +114,8 @@ struct derived_probe: public probe
derived_probe (probe* b, probe_point* l);
probe* base; // the original parsed probe
virtual probe* basest () { return base->basest(); }
+ // XXX: might be helpful for listing and stepwise expansion, but aliases/wildcards don't show up right
+ // virtual probe* almost_basest () { probe* bb = base->basest(); return (bb == base) ? this : bb; }
virtual ~derived_probe () {}
virtual void join_group (systemtap_session& s) = 0;
virtual probe_point* sole_location () const;
diff --git a/git_version.sh b/git_version.sh
new file mode 100755
index 00000000..69eb0f24
--- /dev/null
+++ b/git_version.sh
@@ -0,0 +1,348 @@
+#!/bin/sh
+#
+# Generate some basic versioning information which can be piped to a header.
+#
+# Copyright (c) 2006-2007 Luc Verhaegen <libv@skynet.be>
+# Copyright (C) 2007 Hans Ulrich Niedermann <hun@n-dimensional.de>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# This script is based on the one written for xf86-video-unichrome by
+# Luc Verhaegen, but was rewritten almost completely by Hans Ulrich
+# Niedermann. The script contains a few bug fixes from Egbert Eich,
+# Matthias Hopf, Joerg Sonnenberger, and possibly others.
+#
+# The author thanks the nice people on #git for the assistance.
+#
+# Simple testing of this script:
+# /sbin/busybox sh git_version.sh --example > moo.c \
+# && gcc -Wall -Wextra -Wno-unused -o moo moo.c \
+# && ./moo
+# (bash should also do)
+#
+# For how to hook this up to your automake- and/or imake-based build
+# system, best take a look at how the RadeonHD.am and/or RadeonHD.tmpl
+# work in the xf86-video-radeonhd build system. For non-recursive make,
+# you can probably make things a little bit simpler.
+#
+# KNOWN BUGS:
+# * Uses hyphenated ("git-foo-bar") program names, which git upstream
+# have declared deprecated.
+#
+
+# Help messages
+USAGE="[<option>...]"
+LONG_USAGE="\
+Options:
+ -h, --help Print this help message.
+
+ -k, --keep-if-no-repo Keep old output file if no git repo found.
+ -o, --output FILENAME Set output file name.
+ -q, --quiet Quiet output.
+ -s, --srcdir DIRNAME Set source tree dir name.
+ -x, --example Print complete example program."
+
+# The caller may have set these for us
+SED="${SED-sed}"
+
+# Initialize
+working_dir="$(pwd)"
+
+# Who am I?
+self="$(basename "$0")"
+
+# Defaults
+ifndef_symbol="GIT_VERSION_H"
+outfile="-"
+print_example=false
+keep_if_no_repo=no
+quiet=false
+srcdir="$(pwd)"
+
+# Parse command line parameter, affecting defaults
+while [ "x$1" != "x" ]
+do
+ case "$1" in
+ -x|--example)
+ print_example=:
+ ;;
+ -o|--output)
+ if shift; then
+ outfile="$1"
+ if [ "x$outfile" = "x-" ]; then
+ : # keep default ifndef_symbol
+ else
+ ifndef_symbol=`basename "$outfile" | $SED 's|\.|_|g; s|[^A-Za-z0-9_]||g' | tr a-z A-Z`
+ fi
+ else
+ echo "$self: Fatal: \"$1\" option requires parameter." >&2
+ exit 1
+ fi
+ ;;
+ -q|--quiet)
+ quiet=:
+ ;;
+ -h|--help)
+ echo "Usage: ${self} $USAGE"
+ [ -n "$LONG_USAGE" ] && echo "$LONG_USAGE"
+ exit
+ ;;
+ -k|--keep-if-no-repo)
+ keep_if_no_repo=yes
+ ;;
+ -s|--srcdir)
+ if shift; then
+ if test -d "$1"; then
+ srcdir="$1"
+ else
+ echo "$self: Fatal: \"$1\" not a directory." >&2
+ exit 1
+ fi
+ else
+ echo "$self: Fatal: \"$1\" option requires directory parameter." >&2
+ exit 1
+ fi
+ ;;
+ *)
+ echo "$self: Fatal: Invalid command line paramenter: \"$1\"" >&2
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# If not printing to stdout, redirect stdout to output file
+rename_new_output=false
+if [ "x$outfile" = "x-" ]
+then
+ : # keep using stdout
+else
+ exec 1> "${outfile}.new"
+fi
+
+# Done with creating output files, so we can change to source dir
+abs_srcdir="$(cd "$srcdir" && pwd)"
+cd "$srcdir"
+
+# Write program header
+cat<<EOF
+/*
+ * Basic versioning gathered from the git repository.
+ * Automatically generated by $0.
+ */
+
+#ifndef ${ifndef_symbol}
+#define ${ifndef_symbol} 1
+
+/* whether this is a dist tarball or not */
+#undef GIT_IS_DIST
+
+EOF
+
+# Detect git tools (should work with old and new git versions)
+git_found=yes
+for git_tool in git-symbolic-ref git-rev-parse git-diff-files git-diff-index git
+do
+ if [ x`which $git_tool 2>/dev/null` = "x" ]; then
+ git_found="'$git_tool' not found"
+ break
+ fi
+done
+
+# Determine git specific defines
+unset git_errors ||:
+if [ "x$git_found" = "xyes" ]; then
+ git_version=`git --version`
+ if [ "x$git_version" = "x" ]; then
+ git_errors="${git_errors+${git_errors}; }error running 'git --version'"
+ fi
+fi
+
+git_repo=no
+# "git-rev-parse --git-dir" since git-0.99.7
+git_repo_dir="$(git-rev-parse --git-dir 2> /dev/null || true)"
+abs_repo_dir="$(cd "$git_repo_dir" && pwd)"
+# Only accept the found git repo iff it is in our top srcdir, as determined
+# by comparing absolute pathnames creaged by running pwd in the respective dir.
+if [ "x$git_repo_dir" != "x" ] && [ "x${abs_repo_dir}" = "x${abs_srcdir}/.git" ]; then
+ git_repo=yes
+ if [ "x$git_found" = "xyes" ]; then
+ # git-1.4 and probably earlier understand "git-rev-parse HEAD"
+ git_shaid=`git-rev-parse HEAD | $SED -n 's/^\(.\{8\}\).*/\1/p'`
+ if [ "x$git_shaid" = "x" ]; then
+ git_errors="${git_errors+${git_errors}; }error running 'git-rev-parse HEAD'"
+ fi
+ # git-1.4 and probably earlier understand "git-symbolic-ref HEAD"
+ git_branch=`git-symbolic-ref HEAD | $SED -n 's|^refs/heads/||p'`
+ if [ "x$git_branch" = "x" ]; then
+ # This happens, is OK, and "(no branch)" is what "git branch" prints.
+ git_branch="(no branch)"
+ fi
+ git_dirty=yes
+ # git-1.4 does not understand "git-diff-files --quiet"
+ # git-1.4 does not understand "git-diff-index --cached --quiet HEAD"
+ if [ "x$(git-diff-files)" = "x" ] && [ "x$(git-diff-index --cached HEAD)" = "x" ]; then
+ git_dirty=no
+ fi
+ fi
+fi
+
+# Write git specific defines
+if [ "x$git_errors" = "x" ]; then
+ echo "/* No errors occured while running git */"
+ echo "#undef GIT_ERRORS"
+else
+ echo "/* Some errors occured while running git */"
+ echo "#define GIT_ERRORS \"${git_errors}\""
+fi
+echo ""
+
+if [ "x$git_found" = "xyes" ]; then
+ echo "/* git utilities found */"
+ echo "#undef GIT_NOT_FOUND"
+ echo "#define GIT_VERSION \"${git_version}\""
+else
+ echo "/* git utilities not found */"
+ echo "#define GIT_NOT_FOUND \"${git_found}\""
+ echo "#undef GIT_VERSION"
+fi
+echo ""
+
+if [ "x$git_repo" = "xno" ]; then
+ echo "/* No git repo found, probably building from dist tarball */"
+ echo "#undef GIT_REPO"
+else
+ echo "/* git repo found */"
+ echo "#define GIT_REPO 1"
+ echo ""
+ if [ "x$git_found" = "xyes" ]; then
+ echo "/* Git SHA ID of last commit */"
+ echo "#define GIT_SHAID \"${git_shaid}\""
+ echo ""
+
+ echo "/* Branch this tree is on */"
+ echo "#define GIT_BRANCH \"$git_branch\""
+ echo ""
+
+ # Any uncommitted changes we should know about?
+ # Or technically: Are the working tree or index dirty?
+ if [ "x$git_dirty" = "xno" ]; then
+ echo "/* SHA-ID uniquely defines the state of this code */"
+ echo "#undef GIT_DIRTY"
+ else
+ echo "/* Local changes might be breaking things */"
+ echo "#define GIT_DIRTY 1"
+ fi
+ fi
+fi
+
+# Define a few immediately useful message strings
+cat<<EOF
+
+/* Define GIT_MESSAGE such that
+ * printf("%s: built from %s", argv[0], GIT_MESSAGE);
+ * forms a proper sentence.
+ */
+
+#ifdef GIT_DIRTY
+# define GIT_DIRTY_MSG " + changes"
+#else /* !GIT_DIRTY */
+# define GIT_DIRTY_MSG ""
+#endif /* GIT_DIRTY */
+
+#ifdef GIT_ERRORS
+# define GIT_ERROR_MSG " with error: " GIT_ERRORS
+#else /* !GIT_ERRORS */
+# define GIT_ERROR_MSG ""
+#endif /* GIT_ERRORS */
+
+#ifdef GIT_IS_DIST
+# define GIT_DIST_MSG "dist of "
+#else /* !GIT_IS_DIST */
+# define GIT_DIST_MSG ""
+#endif /* GIT_IS_DIST */
+
+#ifdef GIT_REPO
+# ifdef GIT_NOT_FOUND
+# define GIT_MESSAGE GIT_DIST_MSG "git sources without git: " GIT_NOT_FOUND
+# else /* !GIT_NOT_FOUND */
+# define GIT_MESSAGE \\
+ GIT_DIST_MSG \\
+ "git branch " GIT_BRANCH ", " \\
+ "commit " GIT_SHAID GIT_DIRTY_MSG \\
+ GIT_ERROR_MSG
+# endif /* GIT_NOT_FOUND */
+#else /* !GIT_REPO */
+# define GIT_MESSAGE GIT_DIST_MSG "non-git sources" GIT_ERROR_MSG
+#endif /* GIT_REPO */
+
+#endif /* ${ifndef_symbol} */
+EOF
+
+# Example program
+if "$print_example"
+then
+ cat<<EOF
+
+/* example program demonstrating the use of git_version.sh output */
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+int main(int argc, char *argv[])
+{
+ const char *const idx = strrchr(argv[0], '/');
+ const char *const prog = (idx)?(idx+1):(argv[0]);
+#ifdef PACKAGE_VERSION
+ printf("%s: version %s, built from %s\n", prog, PACKAGE_VERSION, GIT_MESSAGE);
+#elif defined(GIT_USED)
+ printf("%s: built from %s\n", prog, GIT_MESSAGE);
+#endif
+ return 0;
+}
+EOF
+fi
+
+# Change back to working dir for the remaining output file manipulations.
+cd "$working_dir"
+
+# If necessary, overwrite outdated output file with new one
+if [ "x$outfile" != "x-" ]
+then
+ if [ -f "$outfile" ]; then
+ if [ "x$keep_if_no_repo" = "xyes" ] && [ "x$git_repo" = "xno" ]; then
+ "$quiet" || echo "$self: Not a git repo, keeping existing $outfile" >&2
+ rm -f "$outfile.new"
+ elif cmp "$outfile" "$outfile.new" > /dev/null; then
+ "$quiet" || echo "$self: Output is unchanged, keeping $outfile" >&2
+ rm -f "$outfile.new"
+ else
+ echo "$self: Output has changed, updating $outfile" >&2
+ mv -f "$outfile.new" "$outfile"
+ fi
+ else
+ echo "$self: Output is new file, creating $outfile" >&2
+ mv -f "$outfile.new" "$outfile"
+ fi
+fi
+
+# THE END.
diff --git a/main.cxx b/main.cxx
index f547d13d..2a1c0dfb 100644
--- a/main.cxx
+++ b/main.cxx
@@ -19,6 +19,7 @@
#include "cache.h"
#include "util.h"
#include "coveragedb.h"
+#include "git_version.h"
#include <iostream>
#include <fstream>
@@ -48,7 +49,7 @@ version ()
clog
<< "SystemTap translator/driver "
<< "(version " << VERSION << "/" << dwfl_version (NULL)
- << " built " << DATE << ")" << endl
+ << " " << GIT_MESSAGE << ")" << endl
<< "Copyright (C) 2005-2008 Red Hat, Inc. and others" << endl
<< "This is free software; see the source for copying conditions." << endl;
}
@@ -65,9 +66,11 @@ usage (systemtap_session& s, int exitcode)
<< endl
<< " or: stap [options] -e SCRIPT Run given script."
<< endl
+ << " or: stap [options] -l PROBE List matching probes."
+ << endl
<< endl
<< "Options:" << endl
- << " -- no more options after this" << endl
+ << " -- end of translator options, script options follow" << endl
<< " -v increase verbosity [" << s.verbose << "]" << endl
<< " -h show help" << endl
<< " -V show version" << endl
@@ -124,75 +127,122 @@ usage (systemtap_session& s, int exitcode)
static void
printscript(systemtap_session& s, ostream& o)
{
- if (s.embeds.size() > 0)
- o << "# global embedded code" << endl;
- for (unsigned i=0; i<s.embeds.size(); i++)
+ if (s.listing_mode)
{
- embeddedcode* ec = s.embeds[i];
- ec->print (o);
- o << endl;
- }
+ // We go through some heroic measures to produce clean output.
+ set<string> seen;
- if (s.globals.size() > 0)
- o << "# globals" << endl;
- for (unsigned i=0; i<s.globals.size(); i++)
- {
- vardecl* v = s.globals[i];
- v->printsig (o);
- if (s.verbose && v->init)
+ for (unsigned i=0; i<s.probes.size(); i++)
{
- o << " = ";
- v->init->print(o);
+ derived_probe* p = s.probes[i];
+ // NB: p->basest() is not so interesting;
+ // p->almost_basest() doesn't quite work, so ...
+ vector<probe*> chain;
+ p->collect_derivation_chain (chain);
+ probe* second = (chain.size()>1) ? chain[chain.size()-2] : chain[0];
+
+ #if 0
+ cerr << "\tchain[" << chain.size() << "]:" << endl;
+ for (unsigned i=0; i<chain.size(); i++)
+ { cerr << "\t"; chain[i]->printsig(cerr); cerr << endl; }
+ #endif
+
+ stringstream tmps;
+ const probe_alias *a = second->get_alias();
+ if (a)
+ {
+ assert (a->alias_names.size() >= 1);
+ a->alias_names[0]->print(tmps); // XXX: [0] is arbitrary; perhaps print all
+ }
+ else
+ {
+ assert (second->locations.size() >= 1);
+ second->locations[0]->print(tmps); // XXX: [0] is less arbitrary here, but still ...
+ }
+ string pp = tmps.str();
+
+ // Now duplicate-eliminate. An alias may have expanded to
+ // several actual derived probe points, but we only want to
+ // print the alias head name once.
+ if (seen.find (pp) == seen.end())
+ {
+ o << pp << endl;
+ seen.insert (pp);
+ }
}
- o << endl;
}
-
- if (s.functions.size() > 0)
- o << "# functions" << endl;
- for (unsigned i=0; i<s.functions.size(); i++)
+ else
{
- functiondecl* f = s.functions[i];
- f->printsig (o);
- o << endl;
- if (f->locals.size() > 0)
- o << " # locals" << endl;
- for (unsigned j=0; j<f->locals.size(); j++)
+ if (s.embeds.size() > 0)
+ o << "# global embedded code" << endl;
+ for (unsigned i=0; i<s.embeds.size(); i++)
{
- vardecl* v = f->locals[j];
- o << " ";
- v->printsig (o);
- o << endl;
- }
- if (s.verbose)
+ embeddedcode* ec = s.embeds[i];
+ ec->print (o);
+ o << endl;
+ }
+
+ if (s.globals.size() > 0)
+ o << "# globals" << endl;
+ for (unsigned i=0; i<s.globals.size(); i++)
{
- f->body->print (o);
- o << endl;
- }
- }
-
- if (s.probes.size() > 0)
- o << "# probes" << endl;
- for (unsigned i=0; i<s.probes.size(); i++)
- {
- derived_probe* p = s.probes[i];
- p->printsig (o);
- o << endl;
- if (p->locals.size() > 0)
- o << " # locals" << endl;
- for (unsigned j=0; j<p->locals.size(); j++)
+ vardecl* v = s.globals[i];
+ v->printsig (o);
+ if (s.verbose && v->init)
+ {
+ o << " = ";
+ v->init->print(o);
+ }
+ o << endl;
+ }
+
+ if (s.functions.size() > 0)
+ o << "# functions" << endl;
+ for (unsigned i=0; i<s.functions.size(); i++)
{
- vardecl* v = p->locals[j];
- o << " ";
- v->printsig (o);
- o << endl;
- }
- if (s.verbose)
+ functiondecl* f = s.functions[i];
+ f->printsig (o);
+ o << endl;
+ if (f->locals.size() > 0)
+ o << " # locals" << endl;
+ for (unsigned j=0; j<f->locals.size(); j++)
+ {
+ vardecl* v = f->locals[j];
+ o << " ";
+ v->printsig (o);
+ o << endl;
+ }
+ if (s.verbose)
+ {
+ f->body->print (o);
+ o << endl;
+ }
+ }
+
+ if (s.probes.size() > 0)
+ o << "# probes" << endl;
+ for (unsigned i=0; i<s.probes.size(); i++)
{
- p->body->print (o);
- o << endl;
- }
+ derived_probe* p = s.probes[i];
+ p->printsig (o);
+ o << endl;
+ if (p->locals.size() > 0)
+ o << " # locals" << endl;
+ for (unsigned j=0; j<p->locals.size(); j++)
+ {
+ vardecl* v = p->locals[j];
+ o << " ";
+ v->printsig (o);
+ o << endl;
+ }
+ if (s.verbose)
+ {
+ p->body->print (o);
+ o << endl;
+ }
+ }
+ }
}
-}
int pending_interrupts;
@@ -232,6 +282,7 @@ main (int argc, char * const argv [])
s.bulk_mode = false;
s.unoptimized = false;
s.suppress_warnings = false;
+ s.listing_mode = false;
#ifdef ENABLE_PROLOGUES
s.prologue_searching = true;
@@ -318,7 +369,7 @@ main (int argc, char * const argv [])
{ "ignore-dwarf", 0, &long_opt, LONG_OPT_IGNORE_DWARF },
{ NULL, 0, NULL, 0 }
};
- int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqw",
+ int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:",
long_options, NULL);
if (grc < 0)
break;
@@ -345,6 +396,11 @@ main (int argc, char * const argv [])
break;
case 'p':
+ if (s.listing_mode)
+ {
+ cerr << "Listing (-l) mode implies pass 2." << endl;
+ usage (s, 1);
+ }
s.last_pass = atoi (optarg);
if (s.last_pass < 1 || s.last_pass > 5)
{
@@ -450,9 +506,9 @@ main (int argc, char * const argv [])
case 's':
s.buffer_size = atoi (optarg);
- if (s.buffer_size < 1 || s.buffer_size > 64)
+ if (s.buffer_size < 1 || s.buffer_size > 4095)
{
- cerr << "Invalid buffer size (should be 1-64)." << endl;
+ cerr << "Invalid buffer size (should be 1-4095)." << endl;
usage (s, 1);
}
break;
@@ -477,6 +533,20 @@ main (int argc, char * const argv [])
usage (s, 0);
break;
+ case 'l':
+ s.suppress_warnings = true;
+ s.listing_mode = true;
+ s.last_pass = 2;
+ if (have_script)
+ {
+ cerr << "Only one script can be given on the command line."
+ << endl;
+ usage (s, 1);
+ }
+ cmdline_script = string("probe ") + string(optarg) + " {}";
+ have_script = true;
+ break;
+
case 0:
switch (long_opt)
{
@@ -785,7 +855,7 @@ main (int argc, char * const argv [])
// PASS 2: ELABORATION
rc = semantic_pass (s);
- if (rc == 0 && s.last_pass == 2)
+ if (s.listing_mode || (rc == 0 && s.last_pass == 2))
printscript(s, cout);
times (& tms_after);
@@ -834,7 +904,7 @@ main (int argc, char * const argv [])
}
}
- if (rc || s.last_pass == 2 || pending_interrupts) goto cleanup;
+ if (rc || s.listing_mode || s.last_pass == 2 || pending_interrupts) goto cleanup;
// PASS 3: TRANSLATION
diff --git a/runtime/.gitignore b/runtime/.gitignore
new file mode 100644
index 00000000..ceddd64c
--- /dev/null
+++ b/runtime/.gitignore
@@ -0,0 +1 @@
+!staprun
diff --git a/runtime/ChangeLog b/runtime/ChangeLog
index ee191022..f0f65215 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,117 @@
+2008-05-06 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 5648
+ * print_old.c (stp_print_flush): Fix unaligned access warning on
+ ia64.
+ * print_new.c (stp_print_flush): Ditto.
+
+2008-05-06 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 5648
+ * vsprintf.c (_stp_vsnprintf): Fix memcpy's endianess issue.
+
+2008-05-05 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6481.
+ * time.c (__stp_time_timer_callback): Reenable irq's before
+ mod_timer.
+
+2008-05-05 David Smith <dsmith@redhat.com>
+
+ * task_finder.c (stap_utrace_detach_ops): Make sure we ignore
+ /sbin/init.
+ (__stp_utrace_attach): Added function to handle details of
+ attaching a utrace engine.
+ (__stp_utrace_task_finder_report_clone): Calls
+ __stp_utrace_attach.
+ (__stp_utrace_task_finder_report_exec): Ditto.
+ (stap_start_task_finder): Ditto.
+
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 5648
+ From Shaohua Li <shaohua.li@intel.com>
+ * vsprintf.c (_stp_vsnprintf): Fix unaligned access warning on ia64.
+
+2008-04-29 David Smith <dsmith@redhat.com>
+
+ * task_finder.c: Made more robust by ensuring that all utrace
+ attaches have a corresponding utrace detach.
+
+2008-04-28 Frank Ch. Eigler <fche@elastic.org>
+
+ * runtime.h (TEST_MODE): Remove.
+
+2008-04-25 David Smith <dsmith@redhat.com>
+
+ From Srinivasa <srinivasa@in.ibm.com>
+ * task_finder.c (__stp_get_mm_path): Fixed kernel 2.6.25 change.
+
+2008-04-24 David Smith <dsmith@redhat.com>
+
+ * task_finder.c (__stp_get_mm_path): Made kernel 2.6.25 changes.
+
+2008-04-16 David Smith <dsmith@redhat.com>
+
+ * task_finder.c (__stp_get_mm_path): Made kernel 2.6.18 changes.
+
+2008-04-15 David Smith <dsmith@redhat.com>
+
+ PR 5961 (partial)
+ * task_finder.c (stap_start_task_finder): When an interesting
+ thread is found that is already running, make sure to set up
+ thread death notification.
+
+2008-04-15 hunt <hunt@redhat.com>
+ * print.c (_stp_pbuf_full): Delete.
+
+2008-04-15 hunt <hunt@redhat.com>
+ * stack-x86_64.c (_stp_stack_print_fallback): Add levels.
+ (__stp_stack_print): Count levels properly.
+
+2008-04-15 Martin Hunt <hunt@redhat.com>
+
+ Finish support for limits on backtrace depth.
+ * runtime.h (MAXTRACE): Default to 20.
+ * stack.c (_stp_stack_print): Call __stp_stack_print
+ with levels set properly.
+ * sym.c (_stp_func_print): Return a value indicating
+ if something was printed.
+
+ Support for i386 and x86_64 on 2.6.25 kernel
+ * unwind/i386.h: Support unified registers on 2.6.25.
+ Remove unused frame stuff, including STACK_*.
+ * stack-i386.c (__stp_stack_print): Support unified
+ registers on 2.6.25.
+ * regs.h (REG_FP): Define for i386.
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6410.
+ * unwind.c, unwind.h: Make body conditional in STP_USE_DWARF_UNWINDER.
+ * stack-x86_64.c (__stp_stack_print): Tolerate !unwinder.
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6405
+ * autoconf-module-nsections.c: New file.
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ * unwind/i386.h (STACK_BOTTOM, STACK_TOP): Comment out these
+ unused definitions, for they collide with some kernels
+ (2.6.25-0.121.rc5.git4 rawhide).
+
+2008-04-13 Frank Ch. Eigler <fche@elastic.org>
+
+ * print.c (_stp_pbuf_full): New function to note full print buffer.
+ * stack-{i386,x86_64}.c: Use it in all stack-searching loops, to
+ impose another limit against unbounded iteration.
+
+2008-03-31 Martin Hunt <hunt@redhat.com>
+
+ * runtime.h (STP_USE_DWARF_UNWINDER): Define.
+
2008-04-04 Masami Hiramatsu <mhiramat@redhat.com>
PR 6028
@@ -6,11 +120,37 @@
* regs-ia64.c (ia64_fetch_register): Don't unwind stack if it has
already unwound stack in same probe.
+2008-03-30 Martin Hunt <hunt@redhat.com>
+
+ * runtime.h (STP_USE_FRAME_POINTER): Define when frame pointers
+ are available in the kernel and can be used.
+ * stack-arm.c: Use STP_USE_FRAME_POINTER.
+ * stack-i386.c: Ditto.
+ * unwind/i386.h: Ditto.
+ * unwind/x86_64.h: Ditto.
+
2008-04-04 David Smith <dsmith@redhat.com>
PR 5961 (partial)
* task_finder.c: New file.
+2008-03-28 Martin Hunt <hunt@redhat.com>
+
+ * copy.c (_stp_read_address): New function. Safely read
+ kernel or userspace.
+
+2008-03-26 Martin Hunt <hunt@redhat.com>
+ Fixes to get i386 working.
+ * unwind.c (unwind): Fix types in debug print.
+ * stack-i386.c (_stp_stack_print_fallback): New function.
+ (__stp_stack_print): Call _stp_stack_print_fallback() if unwinder
+ appears to fail.
+
+2008-03-25 Martin Hunt <hunt@redhat.com>
+
+ * unwind.c (unwind): Return a positive number to indicate
+ that unwinding is done.
+
2008-04-01 Frank Ch. Eigler <fche@elastic.org>
* lket/*: Belatedly remove retired LKET code.
diff --git a/runtime/autoconf-module-nsections.c b/runtime/autoconf-module-nsections.c
new file mode 100644
index 00000000..c1ce58b7
--- /dev/null
+++ b/runtime/autoconf-module-nsections.c
@@ -0,0 +1,8 @@
+#include <linux/module.h>
+
+struct module_sect_attrs x;
+
+void foo (void)
+{
+ (void) x.nsections;
+}
diff --git a/runtime/copy.c b/runtime/copy.c
index ef3fd223..6bb22762 100644
--- a/runtime/copy.c
+++ b/runtime/copy.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* Copy from user space functions
- * Copyright (C) 2005, 2006, 2007 Red Hat Inc.
+ * Copyright (C) 2005-2008 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
*
* This file is part of systemtap, and is free software. You can
@@ -9,11 +9,10 @@
* later version.
*/
-#ifndef _COPY_C_ /* -*- linux-c -*- */
+#ifndef _COPY_C_ /* -*- linux-c -*- */
#define _COPY_C_
#include "string.c"
-
/** @file copy.c
* @brief Functions to copy from user space.
*/
@@ -26,6 +25,28 @@
* @{
*/
+/** Safely read from userspace or kernelspace.
+ * On success, returns 0. Returns -EFAULT on error.
+ *
+ * This uses __get_user() to read from userspace or
+ * kernelspace. Will not sleep or cause pagefaults when
+ * called from within a kprobe context.
+ *
+ * @param segment . KERNEL_DS for kernel access
+ * USER_DS for userspace.
+ */
+
+#define _stp_read_address(x, ptr, segment) \
+ ({ \
+ long ret; \
+ mm_segment_t ofs = get_fs(); \
+ set_fs(segment); \
+ ret = __stp_get_user(x, ptr); \
+ set_fs(ofs); \
+ ret; \
+ })
+
+
long _stp_strncpy_from_user(char *dst, const char __user *src, long count);
//static long __stp_strncpy_from_user(char *dst, const char __user *src, long count);
@@ -110,8 +131,7 @@ do { \
* <i>count</i> bytes and returns <i>count</i>.
*/
-long
-_stp_strncpy_from_user(char *dst, const char __user *src, long count)
+long _stp_strncpy_from_user(char *dst, const char __user *src, long count)
{
long res = -EFAULT;
if (access_ok(VERIFY_READ, src, count))
@@ -119,7 +139,6 @@ _stp_strncpy_from_user(char *dst, const char __user *src, long count)
return res;
}
-
/** Copy a block of data from user space.
*
* If some data could not be copied, this function will pad the copied
@@ -133,8 +152,7 @@ _stp_strncpy_from_user(char *dst, const char __user *src, long count)
*
*/
-unsigned long
-_stp_copy_from_user (char *dst, const char __user *src, unsigned long count)
+unsigned long _stp_copy_from_user(char *dst, const char __user *src, unsigned long count)
{
if (count) {
if (access_ok(VERIFY_READ, src, count))
diff --git a/runtime/debug.h b/runtime/debug.h
index 8f877ede..9b2fe5c5 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -14,6 +14,8 @@
* _dbug() writes to systemtap stderr.
* errk() writes to the system log.
*/
+int _stp_transport_state = 0;
+
#define _dbug(args...) _stp_dbug(__FUNCTION__, __LINE__, args)
#define errk(args...) do { \
@@ -21,46 +23,42 @@
printk(args); \
} while (0)
-#ifdef DEBUG_TRANSPORT
-#undef DEBUG_TRANSPORT
-#define DEBUG_TRANSPORT 1
-#else
-#define DEBUG_TRANSPORT 0
-#endif
+/*
+ * To use these, enable them from the command line when compiling.
+ * For example, "stap -DDEBUG_UNWIND=3"
+ * will activate dbug_unwind() and print messages with level <= 3.
+ */
-#ifdef DEBUG_UNWIND
-#undef DEBUG_UNWIND
-#define DEBUG_UNWIND 2
-#else
-#define DEBUG_UNWIND 0
-#endif
+/* Note: DEBUG_MEM is implemented in alloc.c */
-#ifdef DEBUG_SYMBOLS
-#undef DEBUG_SYMBOLS
-#define DEBUG_SYMBOLS 4
+#ifdef DEBUG_TRANS /* transport */
+/* Note: transport is debugged using printk() */
+#define dbug_trans(level, args...) do { \
+ if ((level) <= DEBUG_TRANS) { \
+ printk("%s:%d ",__FUNCTION__, __LINE__); \
+ printk(args); \
+ } \
+ } while (0)
#else
-#define DEBUG_SYMBOLS 0
+#define dbug_trans(level, args...) ;
#endif
-#define DEBUG_TYPE (DEBUG_TRANSPORT|DEBUG_UNWIND|DEBUG_SYMBOLS)
-
-#if DEBUG_TYPE > 0
-
-#define dbug(type, args...) do { \
- if ((type) & DEBUG_TYPE) \
+#ifdef DEBUG_UNWIND /* stack unwinder */
+#define dbug_unwind(level, args...) do { \
+ if ((level) <= DEBUG_UNWIND) \
_stp_dbug(__FUNCTION__, __LINE__, args); \
} while (0)
+#else
+#define dbug_unwind(level, args...) ;
+#endif
-#define kbug(type, args...) do { \
- if ((type) & DEBUG_TYPE) { \
- printk("%s:%d ",__FUNCTION__, __LINE__); \
- printk(args); \
- } \
+#ifdef DEBUG_SYMBOLS
+#define dbug_sym(level, args...) do { \
+ if ((level) <= DEBUG_SYMBOLS) \
+ _stp_dbug(__FUNCTION__, __LINE__, args); \
} while (0)
-
#else
-#define dbug(type, args...) ;
-#define kbug(type, args...) ;
-#endif /* DEBUG_TYPE > 0 */
+#define dbug_sym(level, args...) ;
+#endif
#endif /* _STP_DEBUG_H_ */
diff --git a/runtime/map.c b/runtime/map.c
index 513e27df..a436d7ed 100644
--- a/runtime/map.c
+++ b/runtime/map.c
@@ -15,7 +15,6 @@
* @brief Implements maps (associative arrays) and lists
*/
-#include "alloc.c"
#include "sym.c"
#include "stat-common.c"
#include "map-stat.c"
diff --git a/runtime/print.c b/runtime/print.c
index 0442ba09..14a0820b 100644
--- a/runtime/print.c
+++ b/runtime/print.c
@@ -243,7 +243,6 @@ void _stp_print_char (const char c)
pb->len ++;
}
-
/* This function is used when printing maps or stats. */
/* Probably belongs elsewhere, but is here for now. */
/* It takes a format specification like those used for */
diff --git a/runtime/print_new.c b/runtime/print_new.c
index 75bbd82b..07af2e33 100644
--- a/runtime/print_new.c
+++ b/runtime/print_new.c
@@ -40,11 +40,13 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb)
else
atomic_inc (&_stp_transport_failures);
#else
- struct _stp_trace *t = relay_reserve(_stp_utt->rchan, sizeof(*t) + len);
- if (likely(t)) {
- t->sequence = _stp_seq_inc();
- t->pdu_len = len;
- memcpy((void *) t + sizeof(*t), pb->buf, len);
+ void *buf = relay_reserve(_stp_utt->rchan,
+ sizeof(struct _stp_trace) + len);
+ if (likely(buf)) {
+ struct _stp_trace t = { .sequence = _stp_seq_inc(),
+ .pdu_len = len};
+ memcpy(buf, &t, sizeof(t)); // prevent unaligned access
+ memcpy(buf + sizeof(t), pb->buf, len);
} else
atomic_inc (&_stp_transport_failures);
#endif
diff --git a/runtime/print_old.c b/runtime/print_old.c
index 5ee050b5..5c117e5f 100644
--- a/runtime/print_old.c
+++ b/runtime/print_old.c
@@ -35,11 +35,13 @@ void EXPORT_FN(stp_print_flush) (_stp_pbuf *pb)
else
atomic_inc (&_stp_transport_failures);
#else
- struct _stp_trace *t = relay_reserve(_stp_utt->rchan, sizeof(*t) + len);
- if (likely(t)) {
- t->sequence = _stp_seq_inc();
- t->pdu_len = len;
- memcpy((void *) t + sizeof(*t), pb->buf, len);
+ void *buf = relay_reserve(_stp_utt->rchan,
+ sizeof(struct _stp_trace) + len);
+ if (likely(buf)) {
+ struct _stp_trace t = { .sequence = _stp_seq_inc(),
+ .pdu_len = len};
+ memcpy(buf, &t, sizeof(t)); // prevent unaligned access
+ memcpy(buf + sizeof(t), pb->buf, len);
} else
atomic_inc (&_stp_transport_failures);
#endif
diff --git a/runtime/probes.c b/runtime/probes.c
index 19539044..6fe844fb 100644
--- a/runtime/probes.c
+++ b/runtime/probes.c
@@ -25,7 +25,7 @@ void _stp_unregister_jprobes (struct jprobe *probes, int num_probes)
int i;
for (i = 0; i < num_probes; i++)
unregister_jprobe(&probes[i]);
- dbug("All jprobes removed\n");
+ // dbug("All jprobes removed\n");
}
/** Register a group of jprobes.
@@ -46,7 +46,7 @@ int _stp_register_jprobes (struct jprobe *probes, int num_probes)
ret = -1; /* FIXME */
goto out;
}
- dbug("inserting jprobe at %s (%p)\n", probes[i].kp.addr, addr);
+ // dbug("inserting jprobe at %s (%p)\n", probes[i].kp.addr, addr);
probes[i].kp.addr = (kprobe_opcode_t *)addr;
ret = register_jprobe(&probes[i]);
if (ret)
@@ -69,7 +69,7 @@ void _stp_unregister_kprobes (struct kprobe *probes, int num_probes)
int i;
for (i = 0; i < num_probes; i++)
unregister_kprobe(&probes[i]);
- dbug("All kprobes removed\n");
+ // dbug("All kprobes removed\n");
}
@@ -83,7 +83,7 @@ void _stp_unregister_kretprobes (struct kretprobe *probes, int num_probes)
int i;
for (i = 0; i < num_probes; i++)
unregister_kretprobe(&probes[i]);
- dbug("All return probes removed\n");
+ // dbug("All return probes removed\n");
}
#endif
@@ -104,7 +104,7 @@ int _stp_register_kprobes (struct kprobe *probes, int num_probes)
ret = -1;
goto out;
}
- dbug("inserting kprobe at %s (%p)\n", probes[i].addr, addr);
+ // dbug("inserting kprobe at %s (%p)\n", probes[i].addr, addr);
probes[i].addr = (kprobe_opcode_t *)addr;
ret = register_kprobe(&probes[i]);
if (ret)
@@ -136,7 +136,7 @@ int _stp_register_kretprobes (struct kretprobe *probes, int num_probes)
ret = -1; /* FIXME */
goto out;
}
- dbug("inserting kretprobe at %s (%p)\n", probes[i].kp.addr, addr);
+ // dbug("inserting kretprobe at %s (%p)\n", probes[i].kp.addr, addr);
probes[i].kp.addr = (kprobe_opcode_t *)addr;
ret = register_kretprobe(&probes[i]);
if (ret)
diff --git a/runtime/regs.c b/runtime/regs.c
index 2daeaa3c..5821f7e7 100644
--- a/runtime/regs.c
+++ b/runtime/regs.c
@@ -383,317 +383,60 @@ void _stp_print_regs(struct pt_regs * regs)
#endif
-/*
- * (Theoretically) arch-independent scheme for binary lookup of register
- * values (from pt_regs) by register name. A register may be called by
- * more than one name.
- */
-struct _stp_register_desc {
- const char *name;
- unsigned short size; // in bytes
- unsigned short offset; // in bytes, from start of pt_regs
-};
-
-struct _stp_register_table {
- struct _stp_register_desc *registers;
- unsigned nr_registers;
- unsigned nr_slots; // capacity
-};
-
-static DEFINE_SPINLOCK(_stp_register_table_lock);
-static void _stp_populate_register_table(void);
-
-/*
- * If the named register is in the list, return its slot number and *found=1.
- * Else *found=0 and return the slot number where the name should be inserted.
- */
-static int _stp_lookup_register(const char *name,
- struct _stp_register_table *table, int *found)
-{
- unsigned begin, mid, end;
-
- *found = 0;
- end = table->nr_registers;
- if (end == 0)
- return 0;
- begin = 0;
- mid = -1;
- for (;;) {
- int cmp;
- int prev_mid = mid;
- mid = (begin + end) / 2;
- if (mid == prev_mid)
- break;
- cmp = strcmp(name, table->registers[mid].name);
- if (cmp == 0) {
- *found = 1;
- return mid;
- } else if (cmp < 0)
- end = mid;
- else
- begin = mid;
- }
- if (begin == 0 && strcmp(name, table->registers[0].name) < 0)
- return 0;
- return begin + 1;
-}
-
-/*
- * If found, return 1 and the size and/or offset in the pt_regs array.
- * Else return 0.
- */
-static int _stp_find_register(const char *name,
- struct _stp_register_table *table, size_t *size, size_t *offset)
-{
- int slot, found;
- if (unlikely(table->nr_registers == 0)) {
- unsigned long flags;
- /*
- * Should we do this at the beginning of time to avoid
- * the possibility of spending too long in a handler?
- */
- spin_lock_irqsave(&_stp_register_table_lock, flags);
- if (table->nr_registers == 0)
- _stp_populate_register_table();
- spin_unlock_irqrestore(&_stp_register_table_lock, flags);
- }
- slot = _stp_lookup_register(name, table, &found);
- if (found) {
- if (size)
- *size = table->registers[slot].size;
- if (offset)
- *offset = table->registers[slot].offset;
- return 1;
- }
- return 0;
-}
-
-/*
- * Add name to the register-lookup table. Note that the name pointer
- * is merely copied, not strdup-ed.
- */
-void _stp_add_register(const char *name, struct _stp_register_table *table,
- size_t size, size_t offset)
-{
- int idx, found;
- struct _stp_register_desc *slot;
-
- idx = _stp_lookup_register(name, table, &found);
- if (found)
- _stp_error("stap runtime internal error: "
- "register name %s used twice\n", name);
- if (table->nr_registers >= table->nr_slots)
- _stp_error("stap runtime internal error: "
- "register table overflow\n");
- slot = &table->registers[idx];
-
- // Move the slots later in the array out of the way.
- if (idx < table->nr_registers)
- memmove(slot+1, slot,
- sizeof(*slot) * (table->nr_registers - idx));
- table->nr_registers++;
- slot->name = name;
- slot->size = size;
- slot->offset = offset;
-}
-
-#if defined(__i386__) || defined(__x86_64__)
-/*
- * This register set is used for i386 kernel and apps, and for 32-bit apps
- * running on x86_64. For the latter case, this allows the user to use
- * things like reg("eax") as well as the standard x86_64 pt_regs names.
- */
-
-/*
- * x86_64 and i386 are especially ugly because the pt_reg member names
- * changed as part of the x86 merge. We allow (and use, as needed)
- * either the pre-merge name or the post-merge name.
- */
-
-// I count 32 different names, but add a fudge factor.
-static struct _stp_register_desc i386_registers[32+8];
-static struct _stp_register_table i386_register_table = {
- .registers = i386_registers,
- .nr_slots = ARRAY_SIZE(i386_registers)
-};
-
-/*
- * sizeof(long) is indeed what we want here, for both i386 and x86_64.
- * Unlike function args, x86_64 pt_regs is the same even if the int3
- * was in an -m32 app.
- */
-#define ADD_PT_REG(name, member) \
- _stp_add_register(name, &i386_register_table, \
- sizeof(long), offsetof(struct pt_regs, member))
-#define ADD2NAMES(nm1, nm2, member) \
- do { \
- ADD_PT_REG(nm1, member); \
- ADD_PT_REG(nm2, member); \
- } while (0)
-
-#ifdef STAPCONF_X86_UNIREGS
-/* Map "ax" and "eax" to regs->ax, and "cs" and "xcs" to regs->cs */
-#define ADD_EREG(nm) ADD2NAMES(#nm, "e" #nm, nm)
-#define ADD_XREG(nm) ADD2NAMES(#nm, "x" #nm, nm)
-#define ADD_FLAGS_REG() ADD_EREG(flags)
-#define EREG(nm, regs) ((regs)->nm)
-#define RREG(nm, regs) ((regs)->nm)
+/* Function arguments */
-#else /* ! STAPCONF_X86_UNIREGS */
+#define _STP_REGPARM 0x8000
+#define _STP_REGPARM_MASK ((_STP_REGPARM) - 1)
-#ifdef __i386__
-#define ADD_EREG(nm) ADD2NAMES(#nm, "e" #nm, e##nm)
-#define ADD_XREG(nm) ADD2NAMES(#nm, "x" #nm, x##nm)
-#define ADD_FLAGS_REG() ADD_EREG(flags)
-#define EREG(nm, regs) ((regs)->e##nm)
-#else /* __x86_64__ */
/*
- * Map "eax" to regs->rax and "xcs" to regs->cs. Other mappings are
- * handled in x86_64_register_table.
+ * x86_64 and i386 are especially ugly because:
+ * 1) the pt_reg member names changed as part of the x86 merge. We use
+ * either the pre-merge name or the post-merge name, as needed.
+ * 2) -m32 apps on x86_64 look like i386 apps, so we need to support
+ * those semantics on both i386 and x86_64.
*/
-#define ADD_EREG(nm) ADD_PT_REG("e" #nm, r##nm)
-#define ADD_XREG(nm) ADD_PT_REG("x" #nm, nm)
-#define ADD_FLAGS_REG() ADD2NAMES("flags", "eflags", eflags)
-/* Note: After a store to %eax, %rax holds the ZERO-extended %eax. */
-#define EREG(nm, regs) ((regs)->r##nm)
-#define RREG(nm, regs) ((regs)->r##nm)
-#endif /* __x86_64__ */
-
-#endif /* ! STAPCONF_X86_UNIREGS */
-static void _stp_populate_i386_register_table(void)
-{
- /*
- * The order here is the same as in i386 struct pt_regs.
- * It's a different order from x86_64 pt_regs; but that doesn't
- * matter -- even when compiling for x86_64 -- because the
- * offsets are determined by offsetof(), not the calling order.
- */
- ADD_EREG(bx);
- ADD_EREG(cx);
- ADD_EREG(dx);
- ADD_EREG(si);
- ADD_EREG(di);
- ADD_EREG(bp);
- ADD_EREG(ax);
#ifdef __i386__
- ADD_XREG(ds);
- ADD_XREG(es);
- ADD_XREG(fs);
- /* gs not saved */
-#endif
#ifdef STAPCONF_X86_UNIREGS
- ADD2NAMES("orig_ax", "orig_eax", orig_ax);
+#define EREG(nm, regs) ((regs)->nm)
#else
-#ifdef __i386__
- ADD2NAMES("orig_ax", "orig_eax", orig_eax);
-#else /* __x86_64__ */
- ADD2NAMES("orig_ax", "orig_eax", orig_rax);
+#define EREG(nm, regs) ((regs)->e##nm)
#endif
-#endif /* STAPCONF_X86_UNIREGS */
- ADD_EREG(ip);
- ADD_XREG(cs);
- ADD_FLAGS_REG();
- ADD_EREG(sp);
- ADD_XREG(ss);
-}
-/*
- * For x86_64, this gets a copy of the saved 64-bit register (e.g., regs->rax).
- * After a store to %eax, %rax holds the ZERO-extended %eax.
- */
-static long
-_stp_get_reg32_by_name(const char *name, struct pt_regs *regs)
+static long _stp_get_sp(struct pt_regs *regs)
{
- size_t offset = 0;
- long value; // works for i386 or x86_64
- BUG_ON(!name);
- if (!regs)
- _stp_error("Register values not available in this context.\n");
-#ifdef __i386__
- if (!user_mode(regs)) {
- /* esp and ss aren't saved on trap from kernel mode. */
- if (!strcmp(name,"esp") || !strcmp(name, "sp"))
- return (long) &EREG(sp, regs);
- if (!strcmp(name,"xss") || !strcmp(name, "ss")) {
- /*
- * Assume ss register hasn't changed since we took
- * the trap.
- */
- unsigned short ss;
- asm volatile("movw %%ss, %0" : : "m" (ss));
- return ss;
- }
- }
-#endif
- if (!_stp_find_register(name, &i386_register_table, NULL, &offset))
- _stp_error("Unknown register name: %s\n", name);
- (void) memcpy(&value, ((char*)regs) + offset, sizeof(value));
- return value;
+ if (!user_mode(regs))
+ return (long) &EREG(sp, regs);
+ return EREG(sp, regs);
}
-#endif /* __i386__ || __x86_64__ */
-
-#ifdef __i386__
-static void _stp_populate_register_table(void)
+static int _stp_get_regparm(int regparm, struct pt_regs *regs)
{
- _stp_populate_i386_register_table();
+ if (regparm == 0) {
+ /* Default */
+ if (user_mode(regs))
+ return 0;
+ else
+ // Kernel is built with -mregparm=3.
+ return 3;
+ } else
+ return (regparm & _STP_REGPARM_MASK);
}
#endif /* __i386__ */
#ifdef __x86_64__
-// I count 32 different names (not the same 32 as i386), but add a fudge factor.
-static struct _stp_register_desc x86_64_registers[32+8];
-static struct _stp_register_table x86_64_register_table = {
- .registers = x86_64_registers,
- .nr_slots = ARRAY_SIZE(x86_64_registers)
-};
-
-/* NB: Redefining ADD_PT_REG here. ADD2NAMES and such change accordingly. */
-#undef ADD_PT_REG
-#define ADD_PT_REG(name, member) \
- _stp_add_register(name, &x86_64_register_table, \
- sizeof(unsigned long), offsetof(struct pt_regs, member))
-
-#define ADD_NREG(nm) ADD_PT_REG(#nm, nm)
-
#ifdef STAPCONF_X86_UNIREGS
-#define ADD_RREG(nm) ADD2NAMES(#nm, "r" #nm, nm)
+#define EREG(nm, regs) ((regs)->nm)
+#define RREG(nm, regs) ((regs)->nm)
#else
-#define ADD_RREG(nm) ADD2NAMES(#nm, "r" #nm, r##nm)
+#define EREG(nm, regs) ((regs)->r##nm)
+#define RREG(nm, regs) ((regs)->r##nm)
#endif
-static void _stp_populate_register_table(void)
+static long _stp_get_sp(struct pt_regs *regs)
{
- /* Same order as in struct pt_regs */
- ADD_NREG(r15);
- ADD_NREG(r14);
- ADD_NREG(r13);
- ADD_NREG(r12);
- ADD_RREG(bp);
- ADD_RREG(bx);
- ADD_NREG(r11);
- ADD_NREG(r10);
- ADD_NREG(r9);
- ADD_NREG(r8);
- ADD_RREG(ax);
- ADD_RREG(cx);
- ADD_RREG(dx);
- ADD_RREG(si);
- ADD_RREG(di);
-#ifdef STAPCONF_X86_UNIREGS
- ADD2NAMES("orig_ax", "orig_rax", orig_ax);
-#else
- ADD2NAMES("orig_ax", "orig_rax", orig_rax);
-#endif
- ADD_RREG(ip);
- ADD_NREG(cs);
- ADD_FLAGS_REG();
- ADD_RREG(sp);
- ADD_NREG(ss);
-
- _stp_populate_i386_register_table();
+ return RREG(sp, regs);
}
static int _stp_probing_32bit_app(struct pt_regs *regs)
@@ -704,54 +447,26 @@ static int _stp_probing_32bit_app(struct pt_regs *regs)
}
/* Ensure that the upper 32 bits of val are a sign-extension of the lower 32. */
-static long _stp_sign_extend32(long val)
+static int64_t __stp_sign_extend32(int64_t val)
{
int32_t *val_ptr32 = (int32_t*) &val;
return *val_ptr32;
}
-/*
- * Get the value of the 64-bit register with the specified name. "rax",
- * "ax", and "eax" all get you regs->[r]ax. Sets *reg32=1 if the name
- * designates a 32-bit register (e.g., "eax"), 0 otherwise.
- */
-static unsigned long
-_stp_get_reg64_by_name(const char *name, struct pt_regs *regs, int *reg32)
+static int _stp_get_regparm(int regparm, struct pt_regs *regs)
{
- size_t offset = 0;
- unsigned long value;
- BUG_ON(!name);
- if (!regs) {
- _stp_error("Register values not available in this context.\n");
- return 0;
- }
- if (_stp_find_register(name, &x86_64_register_table, NULL, &offset)) {
- if (reg32)
- *reg32 = 0;
- (void) memcpy(&value, ((char*)regs) + offset, sizeof(value));
- return value;
- }
- if (reg32)
- *reg32 = 1;
- return _stp_get_reg32_by_name(name, regs);
+ if (regparm == 0) {
+ /* Default */
+ if (_stp_probing_32bit_app(regs))
+ return 0;
+ else
+ return 6;
+ } else
+ return (regparm & _STP_REGPARM_MASK);
}
-#endif /* __x86_64__ */
-
-/* Function arguments */
-
-#define _STP_REGPARM 0x8000
-#define _STP_REGPARM_MASK ((_STP_REGPARM) - 1)
+#endif /* __x86_64__ */
#if defined(__i386__) || defined(__x86_64__)
-static long _stp_get_sp(struct pt_regs *regs)
-{
-#ifdef __i386__
- if (!user_mode(regs))
- return (long) &EREG(sp, regs);
-#endif
- return EREG(sp, regs);
-}
-
/*
* Use this for i386 kernel and apps, and for 32-bit apps running on x86_64.
* Does arch-specific work for fetching function arg #argnum (1 = first arg).
@@ -792,21 +507,6 @@ static int _stp_get_arg32_by_number(int n, int nr_regargs,
}
#endif /* __i386__ || __x86_64__ */
-#ifdef __i386__
-static int _stp_get_regparm(int regparm, struct pt_regs *regs)
-{
- if (regparm == 0) {
- /* Default */
- if (user_mode(regs))
- return 0;
- else
- // Kernel is built with -mregparm=3.
- return 3;
- } else
- return (regparm & _STP_REGPARM_MASK);
-}
-#endif
-
#ifdef __x86_64__
/* See _stp_get_arg32_by_number(). */
static int _stp_get_arg64_by_number(int n, int nr_regargs,
@@ -835,18 +535,6 @@ static int _stp_get_arg64_by_number(int n, int nr_regargs,
return 0;
}
}
-
-static int _stp_get_regparm(int regparm, struct pt_regs *regs)
-{
- if (regparm == 0) {
- /* Default */
- if (_stp_probing_32bit_app(regs))
- return 0;
- else
- return 6;
- } else
- return (regparm & _STP_REGPARM_MASK);
-}
#endif /* __x86_64__ */
/** @} */
diff --git a/runtime/regs.h b/runtime/regs.h
index c1e2344b..4954020f 100644
--- a/runtime/regs.h
+++ b/runtime/regs.h
@@ -1,5 +1,5 @@
/* common register includes used in multiple modules
- * Copyright (C) 2005 Red Hat Inc.
+ * Copyright (C) 2005-2008 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
*
* This file is part of systemtap, and is free software. You can
@@ -14,6 +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;
#elif defined (__x86_64__)
@@ -24,6 +25,7 @@
#define REG_IP(regs) regs->eip
#define REG_SP(regs) regs->esp
+#define REG_FP(regs) regs->ebp;
#elif defined (__ia64__)
#define REG_IP(regs) ((regs)->cr_iip +ia64_psr(regs)->ri)
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 318d3038..2711f531 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -58,25 +58,32 @@ static struct
#define _stp_seq_inc() (atomic_inc_return(&_stp_seq.seq))
-/* TEST_MODE is always defined by systemtap */
-#ifdef TEST_MODE
-#define SYSTEMTAP 1
-#else
-#define MAXTRYLOCK 1000
-#define TRYLOCKDELAY 100
-#endif
-
#ifndef MAXSTRINGLEN
#define MAXSTRINGLEN 128
#endif
+#ifndef MAXTRACE
+#define MAXTRACE 20
+#endif
+
+#ifdef CONFIG_FRAME_POINTER
+/* Just because frame pointers are available does not mean we can trust them. */
+#if defined (__i386__) || defined (__arm__)
+#define STP_USE_FRAME_POINTER
+#endif
+#endif
+
+/* dwarf unwinder only tested so far on i386 and x86_64 */
+#if !defined(STP_USE_FRAME_BUFFER) && (defined(__i386__) || defined(__x86_64__))
+#define STP_USE_DWARF_UNWINDER
+#endif
+
#include "alloc.c"
#include "print.c"
#include "string.c"
#include "io.c"
#include "arith.c"
#include "copy.c"
-#include "sym.h"
#include "sym.c"
#ifdef STP_PERFMON
#include "perf.c"
diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c
index 0c8ce450..9b0b772d 100644
--- a/runtime/stack-arm.c
+++ b/runtime/stack-arm.c
@@ -33,7 +33,7 @@ static int __init find_str_pc_offset(void)
static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
{
-#if defined(CONFIG_FRAME_POINTER)
+#ifdef STP_USE_FRAME_POINTER
int pc_offset = find_str_pc_offset();
unsigned long *fp = (unsigned long *)regs->ARM_fp;
unsigned long *next_fp, *pc;
@@ -68,5 +68,5 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
fp = next_fp;
}
-#endif
+#endif /* STP_USE_FRAME_POINTER */
}
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c
index b46ff06b..ad101889 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -8,40 +8,68 @@
* later version.
*/
-static inline int _stp_valid_stack_ptr(unsigned long context, unsigned long p)
+static int _stp_valid_stack_ptr(unsigned long context, unsigned long p)
{
return p > context && p < context + THREAD_SIZE - 3;
}
+/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */
+static void _stp_stack_print_fallback(unsigned long context, unsigned long stack, int verbose, int levels)
+{
+ unsigned long addr;
+ while (levels && _stp_valid_stack_ptr(context, stack)) {
+ if (unlikely(_stp_read_address(addr, (unsigned long *)stack, KERNEL_DS))) {
+ /* cannot access stack. give up. */
+ return;
+ }
+ if (_stp_func_print(addr, verbose, 0))
+ levels--;
+ stack++;
+ }
+}
+
static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
{
- unsigned long *stack = (unsigned long *)&REG_SP(regs);
- unsigned long context = (unsigned long)stack & ~(THREAD_SIZE - 1);
+ unsigned long context = (unsigned long)&REG_SP(regs) & ~(THREAD_SIZE - 1);
+
+#ifdef STP_USE_FRAME_POINTER
unsigned long addr;
+ unsigned long next_fp, fp = REG_FP(regs);
-#ifdef CONFIG_FRAME_POINTER
- {
- #ifdef STAPCONF_X86_UNIREGS
- unsigned long ebp = regs->bp;
- #else
- unsigned long ebp = regs->ebp;
- #endif
-
- while (_stp_valid_stack_ptr(context, (unsigned long)ebp)) {
- addr = *(unsigned long *)(ebp + 4);
- if (verbose) {
- _stp_print_char(' ');
- _stp_symbol_print (addr);
- _stp_print_char('\n');
- } else
- _stp_printf ("0x%08lx ", addr);
- ebp = *(unsigned long *)ebp;
+ while (levels && _stp_valid_stack_ptr(context, (unsigned long)fp)) {
+ if (unlikely(_stp_read_address(addr, (unsigned long *)(fp + 4), KERNEL_DS))) {
+ /* cannot access stack. give up. */
+ return;
+ }
+ _stp_func_print(addr, verbose, 1);
+ if (unlikely(_stp_read_address(next_fp, (unsigned long *)fp, KERNEL_DS))) {
+ /* cannot access stack. give up. */
+ return;
}
+ levels--;
+
+ /* frame pointers move upwards */
+ if (next_fp <= fp)
+ break;
+ fp = next_fp;
}
#else
- while (_stp_valid_stack_ptr(context, (unsigned long)stack)) {
- addr = *stack++;
- _stp_func_print(addr, verbose, 1);
+ struct unwind_frame_info info;
+ arch_unw_init_frame_info(&info, regs);
+
+ while (levels && !arch_unw_user_mode(&info)) {
+ int ret = unwind(&info);
+ dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info));
+ if (ret == 0) {
+ _stp_func_print(UNW_PC(&info), verbose, 1);
+ levels--;
+ continue;
+ }
+ /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */
+ /* FIXME: is there a way to unwind across kretprobe trampolines? */
+ if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ _stp_stack_print_fallback(context, UNW_SP(&info), verbose, levels);
+ break;
}
-#endif
+#endif /* STP_USE_FRAME_POINTER */
}
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c
index 186b2ad4..783e72bd 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* x86_64 stack tracing functions
- * Copyright (C) 2005, 2006, 2007 Red Hat Inc.
+ * Copyright (C) 2005-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
@@ -8,13 +8,43 @@
* later version.
*/
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+/* DWARF unwinder failed. Just dump intereting addresses on kernel stack. */
+static void _stp_stack_print_fallback(unsigned long stack, int verbose, int levels)
{
- unsigned long *stack = (unsigned long *)REG_SP(regs);
unsigned long addr;
+ while (levels && stack & (THREAD_SIZE - 1)) {
+ if (unlikely(_stp_read_address(addr, (unsigned long *)stack, KERNEL_DS))) {
+ /* cannot access stack. give up. */
+ return;
+ }
+ if (_stp_func_print(addr, verbose, 0))
+ levels--;
+ stack++;
+ }
+}
+
+static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels)
+{
+#ifdef STP_USE_DWARF_UNWINDER
+ // FIXME: large stack allocation
+ struct unwind_frame_info info;
+ arch_unw_init_frame_info(&info, regs);
- while ((long)stack & (THREAD_SIZE-1)) {
- addr = *stack++;
- _stp_func_print(addr, verbose, 1);
+ while (levels && !arch_unw_user_mode(&info)) {
+ int ret = unwind(&info);
+ dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info));
+ if (ret == 0) {
+ _stp_func_print(UNW_PC(&info), verbose, 1);
+ levels--;
+ continue;
+ }
+ /* If an error happened or we hit a kretprobe trampoline, use fallback backtrace */
+ /* FIXME: is there a way to unwind across kretprobe trampolines? */
+ if (ret < 0 || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ _stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
+ break;
}
+#else /* ! STP_USE_DWARF_UNWINDER */
+ _stp_stack_print_fallback(REG_SP(regs), verbose);
+#endif
}
diff --git a/runtime/stack.c b/runtime/stack.c
index 9c01d65c..23ac2edc 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* Stack tracing functions
- * Copyright (C) 2005, 2006, 2007 Red Hat Inc.
+ * Copyright (C) 2005-2008 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
*
* This file is part of systemtap, and is free software. You can
@@ -23,6 +23,7 @@
#include "sym.c"
#include "regs.h"
+#include "unwind.c"
#define MAXBACKTRACE 20
@@ -46,7 +47,7 @@
* @param regs A pointer to the struct pt_regs.
*/
-void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi)
+void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
{
if (verbose) {
/* print the current address */
@@ -57,12 +58,15 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
} else {
_stp_print_char(' ');
- _stp_symbol_print (REG_IP(regs));
+ _stp_symbol_print(REG_IP(regs));
}
_stp_print_char('\n');
- } else
- _stp_printf ("%p ", (int64_t)REG_IP(regs));
- __stp_stack_print (regs, verbose, 0);
+ } else if (pi)
+ _stp_printf("%p %p ", (int64_t)(long)_stp_ret_addr_r(pi), (int64_t) REG_IP(regs));
+ else
+ _stp_printf("%p ", (int64_t) REG_IP(regs));
+
+ __stp_stack_print(regs, verbose, levels);
}
/** Writes stack backtrace to a string
@@ -71,31 +75,30 @@ void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instan
* @param regs A pointer to the struct pt_regs.
* @returns void
*/
-void _stp_stack_snprint (char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi)
+void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
{
/* To get a string, we use a simple trick. First flush the print buffer, */
/* then call _stp_stack_print, then copy the result into the output string */
/* and clear the print buffer. */
_stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
_stp_print_flush();
- _stp_stack_print(regs, verbose, pi);
+ _stp_stack_print(regs, verbose, pi, levels);
strlcpy(str, pb->buf, size < (int)pb->len ? size : (int)pb->len);
pb->len = 0;
}
-
/** Prints the user stack backtrace
* @param str string
* @returns Same string as was input with trace info appended,
* @note Currently limited to a depth of two. Works from jprobes and kprobes.
*/
#if 0
-void _stp_ustack_print (char *str)
+void _stp_ustack_print(char *str)
{
- struct pt_regs *nregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) current->thread_info)) - 1;
- _stp_printf ("%p : [user]\n", (int64_t)REG_IP(nregs));
+ struct pt_regs *nregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)current->thread_info)) - 1;
+ _stp_printf("%p : [user]\n", (int64_t) REG_IP(nregs));
if (REG_SP(nregs))
- _stp_printf ("%p : [user]\n", (int64_t)(*(unsigned long *)REG_SP(nregs)));
+ _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
}
#endif /* 0 */
diff --git a/runtime/staprun/ChangeLog b/runtime/staprun/ChangeLog
index e9ef2e2d..969c299d 100644
--- a/runtime/staprun/ChangeLog
+++ b/runtime/staprun/ChangeLog
@@ -1,3 +1,60 @@
+2008-05-05 Martin Hunt <hunt@redhat.com>
+
+ * mainloop.c (child_proc): Handle sig_chld
+ in the proper thread.
+ (signal_thread): Don't call send_request()
+ because it isn't thread-safe.
+
+2008-05-05 Martin Hunt <hunt@redhat.com>
+
+ * mainloop.c (signal_thread): New thread to handle signals
+ better.
+ (setup_main_signals): Create signal thread.
+
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 6008
+ * common.c (parse_args): Increase the limitation of the buffer size
+ to 4095MB.
+ * common.c (usage): Ditto.
+
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ * stapio.c (main): Fix a typo in a debug message.
+ * staprun.c (main): Ditto.
+
+2008-04-24 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6451.
+ * common.c (control_channel): Initialize to -1.
+ * ctl.c (close_ctl_channel): Tolerate fd=0.
+
+2008-04-22 Martin Hunt <hunt@redhat.com>
+
+ * cap.c (init_cap): Detect capabilities failure and
+ run with them disabled.
+
+2008-04-22 Martin Hunt <hunt@redhat.com>
+
+ * mainloop.c (send_request): Move here from common.c
+ staprun no longer send any messages.
+
+2008-04-22 hunt <hunt@redhat.com>
+
+ * common.c (usage): Add -d option.
+
+2008-04-21 Martin Hunt <hunt@redhat.com>
+
+ * staprun.c, stapio.c, staprun.h, mainloop.c, staprun_funcs.c,
+ ctl.c, common.c: Add "-d" option to have staprun remove
+ modules. Have staprun exec stapio and then have stapio
+ exec "staprun -d" to remove the module when finished.
+
+2008-04-16 Martin Hunt <hunt@redhat.com>
+
+ * ctl.c (init_ctl_channel): Remove unused parameter.
+ Just opens one channel now.
+
2008-02-21 David Smith <dsmith@redhat.com>
* staprun_funcs.c (check_path): Small security fix.
diff --git a/runtime/staprun/cap.c b/runtime/staprun/cap.c
index 6f22dfc9..6ac6701f 100644
--- a/runtime/staprun/cap.c
+++ b/runtime/staprun/cap.c
@@ -23,6 +23,8 @@
#include "staprun.h"
#include <sys/prctl.h>
+static int _stp_no_caps = 0;
+
/* like perror, but exits */
#define ferror(msg) { \
_perr(msg); \
@@ -54,10 +56,10 @@
* CAP_CHOWN - allows chown
*/
-int init_cap(void)
+void init_cap(void)
{
cap_t caps = cap_init();
- cap_value_t capv[] = {CAP_SYS_MODULE, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SETUID, CAP_SETGID, CAP_DAC_OVERRIDE};
+ cap_value_t capv[] = { CAP_SYS_MODULE, CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SETUID, CAP_SETGID, CAP_DAC_OVERRIDE };
const int numcaps = sizeof(capv) / sizeof(capv[0]);
uid_t uid = getuid();
gid_t gid = getgid();
@@ -69,8 +71,11 @@ int init_cap(void)
if (cap_set_flag(caps, CAP_PERMITTED, numcaps, capv, CAP_SET) < 0)
ferror("cap_set_flag");
- if (cap_set_proc(caps) < 0)
- ferror("cap_set_proc");
+ if (cap_set_proc(caps) < 0) {
+ dbug(1, "Setting capabilities failed. Capabilities disabled.\n");
+ _stp_no_caps = 1;
+ return;
+ }
cap_free(caps);
@@ -82,8 +87,6 @@ int init_cap(void)
if (setresgid(gid, gid, gid) < 0)
ferror("setresgid");
-
- return 1;
}
void print_cap(char *text)
@@ -97,19 +100,18 @@ void print_cap(char *text)
perr("cap_get_proc");
return;
}
-
+
getresuid(&uid, &euid, &suid);
getresgid(&gid, &egid, &sgid);
printf("***** %s\n", text);
- if ((p=prctl(PR_GET_KEEPCAPS, 0, 0, 0, 0)) < 0)
+ if ((p = prctl(PR_GET_KEEPCAPS, 0, 0, 0, 0)) < 0)
perr("Couldn't get PR_SET_KEEPCAPS flag value");
- else
+ else
printf("KEEPCAPS: %d\n", p);
- printf("uid: %d, euid: %d, suid: %d\ngid: %d. egid: %d, sgid: %d\n",
- uid, euid, suid, gid, egid, sgid );
+ printf("uid: %d, euid: %d, suid: %d\ngid: %d. egid: %d, sgid: %d\n", uid, euid, suid, gid, egid, sgid);
printf("Caps: %s\n", cap_to_text(caps, NULL));
cap_free(caps);
printf("*****\n\n");
@@ -121,38 +123,44 @@ void print_cap(char *text)
*/
void drop_cap(cap_value_t cap)
{
- cap_t caps = cap_get_proc();
- if (caps == NULL)
- ferror("cap_get_proc failed");
- if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) < 0)
- ferror("Could not clear effective capabilities");
- if (cap_set_proc(caps) < 0)
- ferror("Could not apply capability set");
- cap_free(caps);
+ if (_stp_no_caps == 0) {
+ cap_t caps = cap_get_proc();
+ if (caps == NULL)
+ ferror("cap_get_proc failed");
+ if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) < 0)
+ ferror("Could not clear effective capabilities");
+ if (cap_set_proc(caps) < 0)
+ ferror("Could not apply capability set");
+ cap_free(caps);
+ }
}
/* add_cap() adds a permitted capability to the effective set. */
void add_cap(cap_value_t cap)
{
- cap_t caps = cap_get_proc();
- if (caps == NULL)
- ferror("cap_get_proc failed");
- if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0)
- ferror("Could not set effective capabilities");
- if (cap_set_proc(caps) < 0)
- ferror("Could not apply capability set");
- cap_free(caps);
+ if (_stp_no_caps == 0) {
+ cap_t caps = cap_get_proc();
+ if (caps == NULL)
+ ferror("cap_get_proc failed");
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_SET) < 0)
+ ferror("Could not set effective capabilities");
+ if (cap_set_proc(caps) < 0)
+ ferror("Could not apply capability set");
+ cap_free(caps);
+ }
}
/* del_cap() deletes a permitted capability from the effective set. */
void del_cap(cap_value_t cap)
{
- cap_t caps = cap_get_proc();
- if (caps == NULL)
- ferror("cap_get_proc failed");
- if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) < 0)
- ferror("Could not clear effective capabilities");
- if (cap_set_proc(caps) < 0)
- ferror("Could not apply capability set");
- cap_free(caps);
+ if (_stp_no_caps == 0) {
+ cap_t caps = cap_get_proc();
+ if (caps == NULL)
+ ferror("cap_get_proc failed");
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) < 0)
+ ferror("Could not clear effective capabilities");
+ if (cap_set_proc(caps) < 0)
+ ferror("Could not apply capability set");
+ cap_free(caps);
+ }
}
diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c
index 47778efd..93da51d8 100644
--- a/runtime/staprun/common.c
+++ b/runtime/staprun/common.c
@@ -22,6 +22,7 @@ unsigned int buffer_size;
char *target_cmd;
char *outfile_name;
int attach_mod;
+int delete_mod;
int load_only;
int need_uprobes;
@@ -30,8 +31,7 @@ char *modname = NULL;
char *modpath = "";
char *modoptions[MAXMODOPTIONS];
-int initialized = 0;
-int control_channel = 0;
+int control_channel = -1; /* NB: fd==0 possible */
void parse_args(int argc, char **argv)
{
@@ -44,10 +44,11 @@ void parse_args(int argc, char **argv)
target_cmd = NULL;
outfile_name = NULL;
attach_mod = 0;
+ delete_mod = 0;
load_only = 0;
need_uprobes = 0;
- while ((c = getopt(argc, argv, "ALuvb:t:d:c:o:x:")) != EOF) {
+ while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:")) != EOF) {
switch (c) {
case 'u':
need_uprobes = 1;
@@ -57,8 +58,8 @@ void parse_args(int argc, char **argv)
break;
case 'b':
buffer_size = (unsigned)atoi(optarg);
- if (buffer_size < 1 || buffer_size > 64) {
- err("Invalid buffer size '%d' (should be 1-64).\n", buffer_size);
+ if (buffer_size < 1 || buffer_size > 4095) {
+ err("Invalid buffer size '%d' (should be 1-4095).\n", buffer_size);
usage(argv[0]);
}
break;
@@ -67,7 +68,8 @@ void parse_args(int argc, char **argv)
target_pid = atoi(optarg);
break;
case 'd':
- /* obsolete internal option used by stap */
+ /* delete module */
+ delete_mod = 1;
break;
case 'c':
target_cmd = optarg;
@@ -128,11 +130,14 @@ void usage(char *prog)
err("-o FILE Send output to FILE.\n");
err("-b buffer size The systemtap module specifies a buffer size.\n");
err(" Setting one here will override that value. The\n");
- err(" value should be an integer between 1 and 64\n");
+ err(" value should be an integer between 1 and 4095 \n");
err(" which be assumed to be the buffer size in MB.\n");
err(" That value will be per-cpu in bulk mode.\n");
err("-L Load module and start probes, then detach.\n");
err("-A Attach to loaded systemtap module.\n");
+ err("-d Delete a module. Only detached or unused modules\n");
+ err(" the user has permission to access will be deleted. Use \"*\"\n");
+ err(" (quoted) to delete all unused modules.\n");
err("MODULE can be either a module name or a module path. If a\n");
err("module name is used, it is looked for in the following\n");
err("directory: /lib/modules/`uname -r`/systemtap\n");
@@ -250,10 +255,7 @@ static void fatal_handler (int signum)
rc = write (STDERR_FILENO, ERR_MSG, sizeof(ERR_MSG));
rc = write (STDERR_FILENO, str, strlen(str));
rc = write (STDERR_FILENO, "\n", 1);
- if (initialized)
- _exit(3);
- else
- _exit(1);
+ _exit(1);
}
void setup_signals(void)
@@ -294,28 +296,6 @@ void setup_signals(void)
#endif
}
-/**
- * send_request - send request to kernel over control channel
- * @type: the relay-app command id
- * @data: pointer to the data to be sent
- * @len: length of the data to be sent
- *
- * Returns 0 on success, negative otherwise.
- */
-int send_request(int type, void *data, int len)
-{
- char buf[1024];
-
- /* Before doing memcpy, make sure 'buf' is big enough. */
- if ((len + 4) > (int)sizeof(buf)) {
- _err("exceeded maximum send_request size.\n");
- return -1;
- }
- memcpy(buf, &type, 4);
- memcpy(&buf[4], data, len);
- return write(control_channel, buf, len+4);
-}
-
/*
* set FD_CLOEXEC for any file descriptor
*/
diff --git a/runtime/staprun/ctl.c b/runtime/staprun/ctl.c
index af7e6c1a..4597bf72 100644
--- a/runtime/staprun/ctl.c
+++ b/runtime/staprun/ctl.c
@@ -12,45 +12,42 @@
#include "staprun.h"
-int init_ctl_channel(int symbols)
+int init_ctl_channel(const char *name, int verb)
{
- char *cname, buf[PATH_MAX];
+ char buf[PATH_MAX];
struct statfs st;
int old_transport = 0;
-
- if (symbols)
- cname = ".symbols";
- else
- cname = ".cmd";
- if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC) {
- if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/%s", modname, cname))
+ if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC) {
+ if (sprintf_chk(buf, "/sys/kernel/debug/systemtap/%s/.cmd", name))
return -1;
} else {
old_transport = 1;
- if (sprintf_chk(buf, "/proc/systemtap/%s/%s", modname, cname))
+ if (sprintf_chk(buf, "/proc/systemtap/%s/.cmd", name))
return -1;
}
-
- dbug(2, "Opening %s\n", buf);
+
+ dbug(2, "Opening %s\n", buf);
control_channel = open(buf, O_RDWR);
if (control_channel < 0) {
- if (attach_mod && errno == ENOENT)
- err("ERROR: Can not attach. Module %s not running.\n", modname);
- else
- perr("Couldn't open control channel '%s'", buf);
+ if (verb) {
+ if (attach_mod && errno == ENOENT)
+ err("ERROR: Can not attach. Module %s not running.\n", name);
+ else
+ perr("Couldn't open control channel '%s'", buf);
+ }
return -1;
}
if (set_clexec(control_channel) < 0)
return -1;
-
+
return old_transport;
}
void close_ctl_channel(void)
{
- if (control_channel > 0) {
+ if (control_channel >= 0) {
close(control_channel);
- control_channel = 0;
+ control_channel = -1;
}
}
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index 2e0c3c5c..61963743 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -15,39 +15,98 @@
/* globals */
int ncpus;
-int use_old_transport = 0;
+static int use_old_transport = 0;
+//enum _stp_sig_type { sig_none, sig_done, sig_detach };
+//static enum _stp_sig_type got_signal = sig_none;
-static void sigproc(int signum)
+/**
+ * send_request - send request to kernel over control channel
+ * @type: the relay-app command id
+ * @data: pointer to the data to be sent
+ * @len: length of the data to be sent
+ *
+ * Returns 0 on success, negative otherwise.
+ */
+int send_request(int type, void *data, int len)
{
- dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum));
-
- if (signum == SIGCHLD) {
- pid_t pid = waitpid(-1, NULL, WNOHANG);
- if (pid != target_pid)
- return;
- send_request(STP_EXIT, NULL, 0);
- } else if (signum == SIGQUIT)
- cleanup_and_exit(2);
- else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM)
- send_request(STP_EXIT, NULL, 0);
+ char buf[1024];
+
+ /* Before doing memcpy, make sure 'buf' is big enough. */
+ if ((len + 4) > (int)sizeof(buf)) {
+ _err("exceeded maximum send_request size.\n");
+ return -1;
+ }
+ memcpy(buf, &type, 4);
+ memcpy(&buf[4], data, len);
+ return write(control_channel, buf, len + 4);
}
-static void setup_main_signals(int cleanup)
+static void *signal_thread(void *arg)
{
- struct sigaction a;
- memset(&a, 0, sizeof(a));
- sigfillset(&a.sa_mask);
- if (cleanup == 0) {
- a.sa_handler = sigproc;
- sigaction(SIGCHLD, &a, NULL);
- } else
- a.sa_handler = SIG_IGN;
- sigaction(SIGINT, &a, NULL);
- sigaction(SIGTERM, &a, NULL);
- sigaction(SIGHUP, &a, NULL);
- sigaction(SIGQUIT, &a, NULL);
+ sigset_t *s = (sigset_t *) arg;
+ int signum, rc, btype = STP_EXIT;
+
+ while (1) {
+ if (sigwait(s, &signum) < 0) {
+ _perr("sigwait");
+ continue;
+ }
+ dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum));
+ if (signum == SIGQUIT)
+ cleanup_and_exit(1);
+ else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) {
+ // send STP_EXIT
+ rc = write(control_channel, &btype, sizeof(btype));
+ break;
+ }
+ }
+ return NULL;
+}
+
+static void chld_proc(int signum)
+{
+ int32_t rc, btype = STP_EXIT;
+ dbug(2, "chld_proc %d (%s)\n", signum, strsignal(signum));
+ pid_t pid = waitpid(-1, NULL, WNOHANG);
+ if (pid != target_pid)
+ return;
+ // send STP_EXIT
+ rc = write(control_channel, &btype, sizeof(btype));
}
+static void setup_main_signals(void)
+{
+ pthread_t tid;
+ struct sigaction sa;
+ sigset_t *s = malloc(sizeof(*s));
+ if (!s) {
+ _perr("malloc failed");
+ exit(1);
+ }
+ sigfillset(s);
+ pthread_sigmask(SIG_SETMASK, s, NULL);
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGQUIT, &sa, NULL);
+
+ sa.sa_handler = chld_proc;
+ sigaction(SIGCHLD, &sa, NULL);
+
+ sigemptyset(s);
+ sigaddset(s, SIGINT);
+ sigaddset(s, SIGTERM);
+ sigaddset(s, SIGHUP);
+ sigaddset(s, SIGQUIT);
+ pthread_sigmask(SIG_SETMASK, s, NULL);
+ if (pthread_create(&tid, NULL, signal_thread, s) < 0) {
+ _perr("failed to create thread");
+ exit(1);
+ }
+}
/*
* start_cmd forks the command given on the command line
@@ -75,7 +134,7 @@ void start_cmd(void)
a.sa_handler = SIG_IGN;
sigaction(SIGINT, &a, NULL);
- dbug (1, "execing target_cmd %s\n", target_cmd);
+ dbug(1, "execing target_cmd %s\n", target_cmd);
if ((pid = fork()) < 0) {
_perr("fork");
exit(1);
@@ -86,8 +145,8 @@ void start_cmd(void)
sigaction(SIGINT, &a, NULL);
/* commands we fork need to run at normal priority */
- setpriority (PRIO_PROCESS, 0, 0);
-
+ setpriority(PRIO_PROCESS, 0, 0);
+
/* wait here until signaled */
sigwait(&usrset, &signum);
@@ -107,11 +166,11 @@ void system_cmd(char *cmd)
{
pid_t pid;
- dbug (2, "system %s\n", cmd);
+ dbug(2, "system %s\n", cmd);
if ((pid = fork()) < 0) {
_perr("fork");
} else if (pid == 0) {
- setpriority (PRIO_PROCESS, 0, 0);
+ setpriority(PRIO_PROCESS, 0, 0);
if (execl("/bin/sh", "sh", "-c", cmd, NULL) < 0)
perr("%s", cmd);
_exit(1);
@@ -128,7 +187,7 @@ static void read_buffer_info(void)
if (!use_old_transport)
return;
- if (statfs("/sys/kernel/debug", &st) == 0 && (int) st.f_type == (int) DEBUGFS_MAGIC)
+ if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC)
return;
if (sprintf_chk(buf, "/proc/systemtap/%s/bufsize", modname))
@@ -152,7 +211,6 @@ static void read_buffer_info(void)
return;
}
-
/**
* init_stapio - initialize the app
* @print_summary: boolean, print summary or not at end of run
@@ -164,7 +222,7 @@ int init_stapio(void)
dbug(2, "init_stapio\n");
/* create control channel */
- use_old_transport = init_ctl_channel(0);
+ use_old_transport = init_ctl_channel(modname, 1);
if (use_old_transport < 0) {
err("Failed to initialize control channel.\n");
return -1;
@@ -177,7 +235,7 @@ int init_stapio(void)
if (init_oldrelayfs() < 0) {
close_ctl_channel();
return -1;
- }
+ }
} else {
if (init_relayfs() < 0) {
close_ctl_channel();
@@ -192,17 +250,12 @@ int init_stapio(void)
if (target_cmd)
start_cmd();
-
return 0;
}
-/* cleanup_and_exit() closed channels and frees memory
- * then exits with the following status codes:
- * 1 - failed to initialize.
- * 2 - disconnected
- * 3 - initialized
- */
-void cleanup_and_exit (int closed)
+/* cleanup_and_exit() closed channels, frees memory,
+ * removes the module (if necessary) and exits. */
+void cleanup_and_exit(int detach)
{
pid_t err;
static int exiting = 0;
@@ -211,32 +264,34 @@ void cleanup_and_exit (int closed)
return;
exiting = 1;
- setup_main_signals(1);
+ setup_main_signals();
- dbug(1, "CLEANUP AND EXIT closed=%d\n", closed);
+ dbug(1, "detach=%d\n", detach);
/* what about child processes? we will wait for them here. */
err = waitpid(-1, NULL, WNOHANG);
if (err >= 0)
err("\nWaiting for processes to exit\n");
- while(wait(NULL) > 0) ;
+ while (wait(NULL) > 0) ;
if (use_old_transport)
- close_oldrelayfs(closed == 2);
+ close_oldrelayfs(detach);
else
close_relayfs();
dbug(1, "closing control channel\n");
close_ctl_channel();
- if (initialized == 2 && closed == 2) {
- err("\nDisconnecting from systemtap module.\n" \
- "To reconnect, type \"staprun -A %s\"\n", modname);
- } else if (initialized)
- closed = 3;
- else
- closed = 1;
- exit(closed);
+ if (detach) {
+ err("\nDisconnecting from systemtap module.\n" "To reconnect, type \"staprun -A %s\"\n", modname);
+ } else {
+ dbug(2, "removing %s\n", modname);
+ if (execl(BINDIR "/staprun", "staprun", "-d", modname, NULL) < 0) {
+ perror(modname);
+ _exit(1);
+ }
+ }
+ _exit(0);
}
/**
@@ -247,90 +302,103 @@ int stp_main_loop(void)
{
ssize_t nb;
void *data;
- int type;
+ uint32_t type;
FILE *ofp = stdout;
char recvbuf[8196];
setvbuf(ofp, (char *)NULL, _IOLBF, 0);
- setup_main_signals(0);
+ setup_main_signals();
dbug(2, "in main loop\n");
send_request(STP_READY, NULL, 0);
- while (1) { /* handle messages from control channel */
+ /* handle messages from control channel */
+ while (1) {
nb = read(control_channel, recvbuf, sizeof(recvbuf));
+ dbug(2, "nb=%d\n", (int)nb);
if (nb <= 0) {
if (errno != EINTR)
_perr("Unexpected EOF in read (nb=%ld)", (long)nb);
continue;
}
-
- type = *(int *)recvbuf;
- data = (void *)(recvbuf + sizeof(int));
- switch (type) {
+ type = *(uint32_t *) recvbuf;
+ data = (void *)(recvbuf + sizeof(uint32_t));
+ nb -= sizeof(uint32_t);
+
+ switch (type) {
#ifdef STP_OLD_TRANSPORT
case STP_REALTIME_DATA:
- {
- ssize_t bw = write(out_fd[0], data, nb - sizeof(int));
- if (bw >= 0 && bw != (nb - (ssize_t)sizeof(int))) {
- nb = nb - bw;
- bw = write(out_fd[0], data, nb - sizeof(int));
+ {
+ ssize_t bw = write(out_fd[0], data, nb);
+ if (bw >= 0 && bw != nb) {
+ nb = nb - bw;
+ bw = write(out_fd[0], data, nb);
+ }
+ if (bw != nb) {
+ _perr("write error (nb=%ld)", (long)nb);
+ cleanup_and_exit(0);
+ }
+ break;
}
- if (bw != (nb - (ssize_t)sizeof(int))) {
- _perr("write error (nb=%ld)", (long)nb);
- cleanup_and_exit(1);
- }
- break;
- }
#endif
case STP_OOB_DATA:
- fputs ((char *)data, stderr);
- break;
- case STP_EXIT:
- {
- /* module asks us to unload it and exit */
- int *closed = (int *)data;
- dbug(2, "got STP_EXIT, closed=%d\n", *closed);
- cleanup_and_exit(*closed);
+ fputs((char *)data, stderr);
break;
- }
- case STP_START:
- {
- struct _stp_msg_start *t = (struct _stp_msg_start *)data;
- dbug(2, "probe_start() returned %d\n", t->res);
- if (t->res < 0) {
- if (target_cmd)
- kill (target_pid, SIGKILL);
- cleanup_and_exit(1);
- } else if (target_cmd)
- kill (target_pid, SIGUSR1);
- break;
- }
+ case STP_EXIT:
+ {
+ /* module asks us to unload it and exit */
+ dbug(2, "got STP_EXIT\n");
+ cleanup_and_exit(0);
+ break;
+ }
+ case STP_START:
+ {
+ struct _stp_msg_start *t = (struct _stp_msg_start *)data;
+ dbug(2, "probe_start() returned %d\n", t->res);
+ if (t->res < 0) {
+ if (target_cmd)
+ kill(target_pid, SIGKILL);
+ cleanup_and_exit(0);
+ } else if (target_cmd)
+ kill(target_pid, SIGUSR1);
+ break;
+ }
case STP_SYSTEM:
- {
- struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data;
- dbug(2, "STP_SYSTEM: %s\n", c->cmd);
- system_cmd(c->cmd);
- break;
- }
+ {
+ struct _stp_msg_cmd *c = (struct _stp_msg_cmd *)data;
+ dbug(2, "STP_SYSTEM: %s\n", c->cmd);
+ system_cmd(c->cmd);
+ break;
+ }
case STP_TRANSPORT:
- {
- struct _stp_msg_start ts;
- if (use_old_transport) {
- if (init_oldrelayfs() < 0)
- cleanup_and_exit(1);
- } else {
- if (init_relayfs() < 0)
+ {
+ struct _stp_msg_start ts;
+ if (use_old_transport) {
+ if (init_oldrelayfs() < 0)
+ cleanup_and_exit(0);
+ } else {
+ if (init_relayfs() < 0)
+ cleanup_and_exit(0);
+ }
+ ts.target = target_pid;
+ send_request(STP_START, &ts, sizeof(ts));
+ if (load_only)
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;
}
- ts.target = target_pid;
- initialized = 2;
- send_request(STP_START, &ts, sizeof(ts));
- if (load_only)
- cleanup_and_exit(2);
- break;
- }
default:
err("WARNING: ignored message of type %d\n", (type));
}
diff --git a/runtime/staprun/stapio.c b/runtime/staprun/stapio.c
index ee30a1a1..3c8c4f7f 100644
--- a/runtime/staprun/stapio.c
+++ b/runtime/staprun/stapio.c
@@ -27,24 +27,23 @@ char *__name__ = "stapio";
int main(int argc, char **argv)
{
setup_signals();
-
parse_args(argc, argv);
if (buffer_size)
- dbug(1, "Using a buffer of %u bytes.\n", buffer_size);
+ dbug(1, "Using a buffer of %u MB.\n", buffer_size);
if (optind < argc) {
parse_modpath(argv[optind++]);
dbug(2, "modpath=\"%s\", modname=\"%s\"\n", modpath, modname);
}
- if (optind < argc) {
+ if (optind < argc) {
if (attach_mod) {
err("ERROR: Cannot have module options with attach (-A).\n");
usage(argv[0]);
} else {
- unsigned start_idx = 3; /* reserve three slots in modoptions[] */
- while (optind < argc && start_idx+1 < MAXMODOPTIONS)
+ unsigned start_idx = 3; /* reserve three slots in modoptions[] */
+ while (optind < argc && start_idx + 1 < MAXMODOPTIONS)
modoptions[start_idx++] = argv[optind++];
modoptions[start_idx] = NULL;
}
@@ -57,13 +56,7 @@ int main(int argc, char **argv)
if (init_stapio())
exit(1);
-
- initialized = 1;
- if (attach_mod) {
- /* already started */
- initialized++;
- }
-
+
if (stp_main_loop()) {
err("ERROR: Couldn't enter main loop. Exiting.\n");
exit(1);
diff --git a/runtime/staprun/staprun.c b/runtime/staprun/staprun.c
index f4e67fdb..0291d01f 100644
--- a/runtime/staprun/staprun.c
+++ b/runtime/staprun/staprun.c
@@ -16,21 +16,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Copyright (C) 2005-2007 Red Hat, Inc.
+ * Copyright (C) 2005-2008 Red Hat, Inc.
*
*/
#include "staprun.h"
-int inserted_module = 0;
-
/* used in dbug, _err and _perr */
char *__name__ = "staprun";
extern long delete_module(const char *, unsigned int);
-static int
-run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
+static int run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
{
pid_t pid;
int rstatus;
@@ -42,14 +39,13 @@ run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
err("%s ", argv[i]);
i++;
}
- err("\n");
+ err("\n");
}
if ((pid = fork()) < 0) {
_perr("fork");
return -1;
- }
- else if (pid == 0) {
+ } else if (pid == 0) {
/* Make sure we run as the full user. If we're
* switching to a non-root user, this won't allow
* that process to switch back to root (since the
@@ -79,17 +75,6 @@ run_as(uid_t uid, gid_t gid, const char *path, char *const argv[])
return -1;
}
-/* Keep the uid and gid settings because we will likely */
-/* conditionally restore "-u" */
-static int run_stapio(char **argv)
-{
- uid_t uid = getuid();
- gid_t gid = getgid();
- argv[0] = PKGLIBDIR "/stapio";
-
- return run_as(uid, gid, argv[0], argv);
-}
-
/*
* Module to be inserted has one or more user-space probes. Make sure
* uprobes is enabled.
@@ -132,8 +117,7 @@ static int enable_uprobes(void)
dbug(2, "Inserting uprobes module from SystemTap runtime.\n");
argv[0] = NULL;
- return insert_module(PKGDATADIR "/runtime/uprobes/uprobes.ko",
- NULL, argv);
+ return insert_module(PKGDATADIR "/runtime/uprobes/uprobes.ko", NULL, argv);
}
static int insert_stap_module(void)
@@ -144,6 +128,66 @@ static int insert_stap_module(void)
return insert_module(modpath, bufsize_option, modoptions);
}
+static int remove_module(const char *name, int verb);
+
+static void remove_all_modules(void)
+{
+ char *base;
+ struct statfs st;
+ struct dirent *d;
+ DIR *moddir;
+
+ if (statfs("/sys/kernel/debug", &st) == 0 && (int)st.f_type == (int)DEBUGFS_MAGIC)
+ base = "/sys/kernel/debug/systemtap";
+ else
+ base = "/proc/systemtap";
+
+ moddir = opendir(base);
+ if (moddir) {
+ while ((d = readdir(moddir)))
+ if (remove_module(d->d_name, 0) == 0)
+ printf("Module %s removed.\n", d->d_name);
+ closedir(moddir);
+ }
+}
+
+static int remove_module(const char *name, int verb)
+{
+ int ret;
+ dbug(2, "%s\n", name);
+
+ if (strcmp(name, "*") == 0) {
+ remove_all_modules();
+ return 0;
+ }
+
+ /* Call init_ctl_channel() which actually attempts an open()
+ * of the control channel. This is better than using access() because
+ * an open on an already open channel will fail, preventing us from attempting
+ * to remove an in-use module.
+ */
+ if (init_ctl_channel(name, 0) < 0) {
+ if (verb)
+ err("Error accessing systemtap module %s: %s\n", name, strerror(errno));
+ return 1;
+ }
+ close_ctl_channel();
+
+ dbug(2, "removing module %s\n", name);
+
+ /* Don't remove module when priority is elevated. */
+ if (setpriority(PRIO_PROCESS, 0, 0) < 0)
+ _perr("setpriority");
+
+ ret = do_cap(CAP_SYS_MODULE, delete_module, name, 0);
+ if (ret != 0) {
+ err("Error removing module '%s': %s.\n", name, strerror(errno));
+ return 1;
+ }
+
+ dbug(1, "Module %s removed.\n", name);
+ return 0;
+}
int init_staprun(void)
{
@@ -154,71 +198,28 @@ int init_staprun(void)
/* We're done with CAP_SYS_ADMIN. */
drop_cap(CAP_SYS_ADMIN);
-
- if (!attach_mod) {
+
+ if (delete_mod)
+ exit(remove_module(modname, 1));
+ else if (!attach_mod) {
if (need_uprobes && enable_uprobes() != 0)
return -1;
if (insert_stap_module() < 0)
return -1;
- else
- inserted_module = 1;
}
-
return 0;
}
-
-static void cleanup(int rc)
-{
- /* Only cleanup once. */
- static int done = 0;
- if (done == 0)
- done = 1;
- else
- return;
-
- dbug(2, "rc=%d, inserted_module=%d\n", rc, inserted_module);
-
- if (setpriority (PRIO_PROCESS, 0, 0) < 0)
- _perr("setpriority");
-
- stop_symbol_thread();
-
- /* rc == 2 means disconnected */
- if (rc == 2)
- return;
-
- /* If we inserted the module and did not get rc==2, then */
- /* we really want to remove it. */
- if (inserted_module || rc == 3) {
- long ret;
- dbug(2, "removing module %s\n", modname);
- ret = do_cap(CAP_SYS_MODULE, delete_module, modname, 0);
- if (ret != 0)
- err("Error removing module '%s': %s\n", modname, moderror(errno));
- }
-}
-
-static void exit_cleanup(void)
-{
- dbug(2, "something exited...\n");
- cleanup(1);
-}
int main(int argc, char **argv)
{
int rc;
- if (atexit(exit_cleanup)) {
- _perr("cannot set exit function");
- exit(1);
- }
-
- /* NB: Don't do the geteuid()!=0 check here, since we want to
- test command-line error-handling while running non-root. */
+ /* NB: Don't do the geteuid()!=0 check here, since we want to
+ test command-line error-handling while running non-root. */
/* Get rid of a few standard environment variables (which */
/* might cause us to do unintended things). */
rc = unsetenv("IFS") || unsetenv("CDPATH") || unsetenv("ENV")
- || unsetenv("BASH_ENV");
+ || unsetenv("BASH_ENV");
if (rc) {
_perr("unsetenv failed");
exit(-1);
@@ -229,20 +230,20 @@ int main(int argc, char **argv)
parse_args(argc, argv);
if (buffer_size)
- dbug(2, "Using a buffer of %u bytes.\n", buffer_size);
+ dbug(2, "Using a buffer of %u MB.\n", buffer_size);
if (optind < argc) {
parse_modpath(argv[optind++]);
dbug(2, "modpath=\"%s\", modname=\"%s\"\n", modpath, modname);
}
- if (optind < argc) {
+ if (optind < argc) {
if (attach_mod) {
err("ERROR: Cannot have module options with attach (-A).\n");
usage(argv[0]);
} else {
unsigned start_idx = 0;
- while (optind < argc && start_idx+1 < MAXMODOPTIONS)
+ while (optind < argc && start_idx + 1 < MAXMODOPTIONS)
modoptions[start_idx++] = argv[optind++];
modoptions[start_idx] = NULL;
}
@@ -254,14 +255,13 @@ int main(int argc, char **argv)
}
if (geteuid() != 0) {
- err("ERROR: The effective user ID of staprun must be set to the root user.\n"
- " Check permissions on staprun and ensure it is a setuid root program.\n");
+ err("ERROR: The effective user ID of staprun must be set to the root user.\n"
+ " Check permissions on staprun and ensure it is a setuid root program.\n");
exit(1);
}
- if (!init_cap())
- exit(1);
-
+ init_cap();
+
if (check_permissions() != 1)
usage(argv[0]);
@@ -277,11 +277,14 @@ int main(int argc, char **argv)
if (init_staprun())
exit(1);
- setup_staprun_signals();
- start_symbol_thread();
-
- rc = run_stapio(argv);
- cleanup(rc);
-
+ argv[0] = PKGLIBDIR "/stapio";
+ if (execv(argv[0], argv) < 0) {
+ perror(argv[0]);
+ goto err;
+ }
return 0;
+
+err:
+ remove_module(modname, 1);
+ return 1;
}
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index 1128fb4c..60bab391 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -103,8 +103,6 @@ extern char *__name__;
#define STP_OLD_TRANSPORT
#include "../transport/transport_msgs.h"
-extern int use_old_transport;
-
#define RELAYFS_MAGIC 0xF0B4A981
#define DEBUGFS_MAGIC 0x64626720
#define DEBUGFSDIR "/sys/kernel/debug"
@@ -118,9 +116,8 @@ int init_stapio(void);
int stp_main_loop(void);
int send_request(int type, void *data, int len);
void cleanup_and_exit (int);
-int do_module(void *);
-int do_kernel_symbols(void);
-int init_ctl_channel(int);
+void send_unwind_data(const char *name);
+int init_ctl_channel(const char *name, int verb);
void close_ctl_channel(void);
int init_relayfs(void);
void close_relayfs(void);
@@ -129,7 +126,7 @@ void close_oldrelayfs(int);
void setup_signals(void);
/* cap.c */
void print_cap(char *text);
-int init_cap(void);
+void init_cap(void);
void add_cap(cap_value_t cap);
void del_cap(cap_value_t cap);
void drop_cap(cap_value_t cap);
@@ -169,6 +166,7 @@ extern int target_pid;
extern char *target_cmd;
extern char *outfile_name;
extern int attach_mod;
+extern int delete_mod;
extern int load_only;
extern int need_uprobes;
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
index 34e12c25..c1cb92b7 100644
--- a/runtime/staprun/staprun_funcs.c
+++ b/runtime/staprun/staprun_funcs.c
@@ -16,18 +16,6 @@
#include <grp.h>
#include <pwd.h>
-void setup_staprun_signals(void)
-{
- struct sigaction a;
- memset(&a, 0, sizeof(a));
- sigfillset(&a.sa_mask);
- a.sa_handler = SIG_IGN;
- sigaction(SIGINT, &a, NULL);
- sigaction(SIGTERM, &a, NULL);
- sigaction(SIGHUP, &a, NULL);
- sigaction(SIGQUIT, &a, NULL);
-}
-
extern long init_module(void *, unsigned long, const char *);
/* Module errors get translated. */
@@ -401,95 +389,3 @@ int check_permissions(void)
* is in that directory. */
return check_path();
}
-
-pthread_t symbol_thread_id = (pthread_t)0;
-int kernel_ptr_size = 0;
-
-/* Symbol handling thread */
-void *handle_symbols(void __attribute__((unused)) *arg)
-{
- ssize_t nb;
- void *data;
- int32_t type;
- char recvbuf[8192];
-
- dbug(2, "waiting for symbol requests\n");
-
- /* handle messages from control channel */
- while (1) {
- nb = read(control_channel, recvbuf, sizeof(recvbuf));
- if (nb <= 0) {
- if (errno != EINTR)
- _perr("Unexpected EOF in read (nb=%ld)", (long)nb);
- continue;
- }
-
- type = *(int32_t *)recvbuf;
- data = (void *)(recvbuf + sizeof(int32_t));
-
- switch (type) {
- case STP_MODULE:
- {
- dbug(2, "STP_MODULES request received\n");
- if (do_module(data) < 0)
- goto done;
- break;
- }
- case STP_SYMBOLS:
- {
- struct _stp_msg_symbol *req = (struct _stp_msg_symbol *)data;
- dbug(2, "STP_SYMBOLS request received\n");
- if (req->endian != 0x1234) {
- err("ERROR: staprun is compiled with different endianess than the kernel!\n");
- goto done;
- }
- kernel_ptr_size = req->ptr_size;
- if (kernel_ptr_size != 4 && kernel_ptr_size != 8) {
- err("ERROR: invalid kernel pointer size %d\n", kernel_ptr_size);
- goto done;
- }
- if (do_kernel_symbols() < 0)
- goto done;
- break;
- }
- default:
- err("WARNING: ignored message of type %d\n", (type));
- }
- }
-
-done:
- /* signal stapio we're done */
- kill(0, SIGINT);
-
- return NULL;
-}
-
-void start_symbol_thread(void)
-{
- int status;
-
- /* create symbol control channel */
- status = do_cap(CAP_DAC_OVERRIDE, init_ctl_channel, 1);
- drop_cap(CAP_DAC_OVERRIDE);
- if (status < 0) {
- err("Failed to initialize control channel.\n");
- exit(1);
- }
- status = pthread_create(&symbol_thread_id, NULL, handle_symbols, NULL);
- if (status) {
- perr("Failed to create symbol thread.\n");
- exit(1);
- }
-}
-
-void stop_symbol_thread(void)
-{
-
- if (symbol_thread_id) {
- dbug(2, "Stopping symbol thread.\n");
- pthread_cancel(symbol_thread_id);
- pthread_join(symbol_thread_id, NULL);
- }
- close_ctl_channel();
-}
-
diff --git a/runtime/staprun/symbols.c b/runtime/staprun/symbols.c
deleted file mode 100644
index c7362d9e..00000000
--- a/runtime/staprun/symbols.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/* -*- linux-c -*-
- * Symbols and modules functions for staprun.
- *
- * Copyright (C) 2006-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"
-
-/* send symbol data */
-static int send_data(int32_t type, void *data, int len)
-{
- if (write(control_channel, &type, 4) <= 0)
- return -1;
- return write(control_channel, data, len);
-}
-
-
-/* Get the sections for a module. Put them in the supplied buffer */
-/* in the following order: */
-/* [struct _stp_msg_module][struct _stp_symbol sections ...][string data][unwind data] */
-/* Return the total length of all the data. */
-
-#define SECDIR "/sys/module/%s/sections"
-static int get_sections(char *name, char *data_start, int datalen)
-{
- char dir[STP_MODULE_NAME_LEN + sizeof(SECDIR)];
- char filename[STP_MODULE_NAME_LEN + 256];
- char buf[32], strdata_start[32768];
- char *strdata=strdata_start, *data=data_start;
- int fd, len, res, unwind_data_len=0;
- struct _stp_msg_module *mod = (struct _stp_msg_module *)data_start;
-
- struct dirent *d;
- DIR *secdir;
- void *sec;
- int struct_symbol_size = kernel_ptr_size == 8 ? sizeof(struct _stp_symbol64) : sizeof(struct _stp_symbol32);
- uint64_t sec_addr;
-
- /* start of data is a struct _stp_msg_module */
- data += sizeof(struct _stp_msg_module);
-
- res = snprintf(dir, sizeof(dir), SECDIR, name);
- if (res >= (int)sizeof(dir)) {
- _err("Couldn't fit module \"%s\" into dir buffer.\n" \
- "This should never happen. Please file a bug report.\n", name);
- return -1;
- }
-
- if ((secdir = opendir(dir)) == NULL)
- return 0;
-
- /* Initialize mod. */
- memset(mod, 0, sizeof(struct _stp_msg_module));
-
- /* Copy name in and check for overflow. */
- strncpy(mod->name, name, STP_MODULE_NAME_LEN);
- if (mod->name[STP_MODULE_NAME_LEN - 1] != '\0') {
- _err("Couldn't fit module \"%s\" into mod->name buffer.\n" \
- "This should never happen. Please file a bug report.\n", name);
- return -1;
- }
-
- /* FIXME: optionally fill in unwind data here */
- mod->unwind_len = unwind_data_len;
-
- while ((d = readdir(secdir))) {
- char *secname = d->d_name;
-
- /* Copy filename in and check for overflow. */
- res = snprintf(filename, sizeof(filename), "/sys/module/%s/sections/%s", name, secname);
- if (res >= (int)sizeof(filename)) {
- _err("Couldn't fit secname \"%s\" into filename buffer.\n" \
- "This should never happen. Please file a bug report.\n", secname);
- closedir(secdir);
- return -1;
- }
-
- /* filter out some non-useful stuff */
- if (!strncmp(secname,"__",2)
- || !strcmp(secname,".")
- || !strcmp(secname,"..")
- || !strcmp(secname,".module_sig")
- || !strcmp(secname,".modinfo")
- || !strcmp(secname,".strtab")
- || !strcmp(secname,".symtab") ) {
- continue;
- }
- if (!strncmp(secname, ".gnu.linkonce", 13)
- && strcmp(secname, ".gnu.linkonce.this_module"))
- continue;
-
- if ((fd = open(filename,O_RDONLY)) >= 0) {
- if (read(fd, buf, 32) > 0) {
- /* create next section */
- sec = data;
- if (data - data_start + struct_symbol_size > datalen)
- goto err1;
- data += struct_symbol_size;
-
- sec_addr = (uint64_t)strtoull(buf,NULL,16);
- if (kernel_ptr_size == 8) {
- ((struct _stp_symbol64 *)sec)->addr = sec_addr;
- ((struct _stp_symbol64 *)sec)->symbol = (uint64_t)(strdata - strdata_start);
- } else {
- ((struct _stp_symbol32 *)sec)->addr = (uint32_t)sec_addr;
- ((struct _stp_symbol32 *)sec)->symbol = (uint32_t)(strdata - strdata_start);
- }
- mod->num_sections++;
-
- /* now create string data for the
- * section (checking for overflow) */
- if ((strdata - strdata_start + strlen(strdata))
- >= sizeof(strdata_start))
- goto err1;
- strcpy(strdata, secname);
- strdata += strlen(secname) + 1;
-
- /* These sections are used a lot so keep the values handy */
- if (!strcmp(secname, ".data") || !strncmp(secname, ".rodata", 7)) {
- if (mod->data == 0 || sec_addr < mod->data)
- mod->data = sec_addr;
- }
- if (!strcmp(secname, ".text"))
- mod->text = sec_addr;
- if (!strcmp(secname, ".gnu.linkonce.this_module"))
- mod->module = sec_addr;
- }
- close(fd);
- }
- }
- closedir(secdir);
-
- /* consolidate buffers */
- len = strdata - strdata_start;
- if ((len + data - data_start) > datalen)
- goto err0;
- strdata = strdata_start;
- while (len--)
- *data++ = *strdata++;
-
-#if 0
- if (unwind_data_len) {
- if ((unwind_data_len + data - data_start) > datalen)
- goto err0;
- memcpy(data, unwind_data, unwind_data_len);
- data += unwind_data_len;
- }
-#endif
- return data - data_start;
-
-err1:
- close(fd);
- closedir(secdir);
-err0:
- /* if this happens, something went seriously wrong. */
- _err("Unexpected error. Overflowed buffers.\n");
- return -1;
-}
-#undef SECDIR
-
-/*
- * For modules, we send the name, section names, and offsets
- */
-static int send_module (char *mname)
-{
- char data[65536];
- int len;
- len = get_sections(mname, data, sizeof(data));
- if (len > 0) {
- if (send_data(STP_MODULE, data, len) < 0) {
- _err("Loading of module %s failed. Exiting...\n", mname);
- return -1;
- }
- }
- return len;
-}
-
-/*
- * Send either all modules, or a specific one.
- * Returns:
- * >=0 : OK
- * -1 : serious error (exit)
- */
-int do_module (void *data)
-{
- struct _stp_msg_module *mod = (struct _stp_msg_module *)data;
-
- if (mod->name[0] == 0) {
- struct dirent *d;
- DIR *moddir = opendir("/sys/module");
- if (moddir) {
- while ((d = readdir(moddir)))
- if (send_module(d->d_name) < 0) {
- closedir(moddir);
- return -1;
- }
- closedir(moddir);
- }
- send_request(STP_MODULE, data, 1);
- return 0;
- }
-
- return send_module(mod->name);
-}
-
-#define MAX_SYMBOLS 32*1024
-
-/*
- * Read /proc/kallsyms and send all kernel symbols to the
- * systemtap module. Ignore module symbols; the systemtap module
- * can access them directly.
- */
-int do_kernel_symbols(void)
-{
- FILE *kallsyms=NULL;
- char *name, *mod, *dataptr, *datamax, type, *data_base=NULL;
- unsigned long long addr;
- void *syms = NULL;
- int ret, num_syms, i = 0, struct_symbol_size;
- int max_syms= MAX_SYMBOLS, data_basesize = MAX_SYMBOLS*32;
-
- if (kernel_ptr_size == 8)
- struct_symbol_size = sizeof(struct _stp_symbol64);
- else
- struct_symbol_size = sizeof(struct _stp_symbol32);
-
- syms = malloc(max_syms * struct_symbol_size);
- data_base = malloc(data_basesize);
- if (data_base == NULL || syms == NULL) {
- _err("Failed to allocate memory for symbols\n");
- goto err;
- }
- dataptr = data_base;
- datamax = data_base + data_basesize;
-
- kallsyms = fopen ("/proc/kallsyms", "r");
- if (!kallsyms) {
- _perr("Fatal error: Unable to open /proc/kallsyms");
- goto err;
- }
-
- /* put empty string in data */
- *dataptr++ = 0;
-
- while ((ret = fscanf(kallsyms, "%llx %c %as [%as", &addr, &type, &name, &mod))>0
- && dataptr < datamax) {
- if (ret < 3)
- continue;
- if (ret > 3) {
- /* ignore modules */
- free(name);
- free(mod);
- /* modules are loaded above the kernel, so if we */
- /* are getting modules, then we're done. */
- break;
- }
-
- if (type == 't' || type == 'T' || type == 'A') {
- if (kernel_ptr_size == 8) {
- ((struct _stp_symbol64 *)syms)[i].addr = (uint64_t)addr;
- ((struct _stp_symbol64 *)syms)[i].symbol = (uint64_t)(dataptr - data_base);
- } else {
- ((struct _stp_symbol32 *)syms)[i].addr = (uint32_t)addr;
- ((struct _stp_symbol32 *)syms)[i].symbol = (uint32_t)(dataptr - data_base);
- }
- if (dataptr >= datamax - strlen(name)) {
- char *db;
- data_basesize *= 2;
- db = realloc(data_base, data_basesize);
- if (db == NULL) {
- _err("Could not allocate enough space for symbols.\n");
- goto err;
- }
- dataptr = db + (dataptr - data_base);
- datamax = db + data_basesize;
- data_base = db;
- }
- strcpy(dataptr, name);
- dataptr += strlen(name) + 1;
- free(name);
- i++;
- if (i >= max_syms) {
- max_syms *= 2;
- syms = realloc(syms, max_syms*struct_symbol_size);
- if (syms == NULL) {
- _err("Could not allocate enough space for symbols.\n");
- goto err;
- }
- }
- }
- }
- num_syms = i;
- if (num_syms <= 0)
- goto err;
-
-
- /* send header */
- struct _stp_msg_symbol_hdr smsh;
- smsh.num_syms = num_syms;
- smsh.sym_size = (uint32_t)(dataptr - data_base);
- smsh.unwind_size = (uint32_t)0;
- if (send_request(STP_SYMBOLS, &smsh, sizeof(smsh)) <= 0)
- goto err;
-
- /* send syms */
- if (send_data(STP_SYMBOLS, syms, num_syms*struct_symbol_size) < 0)
- goto err;
-
- /* send data */
- if (send_data(STP_SYMBOLS, data_base, dataptr-data_base) < 0)
- goto err;
-
- free(data_base);
- free(syms);
- fclose(kallsyms);
- return 0;
-
-err:
- if (data_base)
- free(data_base);
- if (syms)
- free(syms);
- if (kallsyms)
- fclose(kallsyms);
-
- _err("Loading of symbols failed. Exiting...\n");
- return -1;
-}
diff --git a/runtime/staprun/unwind_data.c b/runtime/staprun/unwind_data.c
new file mode 100644
index 00000000..ed27cc20
--- /dev/null
+++ b/runtime/staprun/unwind_data.c
@@ -0,0 +1,97 @@
+/* -*- 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/sym.c b/runtime/sym.c
index 3c2f859a..7163bf92 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -33,7 +33,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
return 0;
}
- dbug(DEBUG_SYMBOLS, "%s, %s, %lx\n", module, section, offset);
+ dbug_sym(1, "%s, %s, %lx\n", module, section, offset);
STP_RLOCK_MODULES;
if (!module || !strcmp(section, "") /* absolute, unrelocated address */
@@ -47,7 +47,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
if (!strcmp(module, last->name) && !strcmp(section, last_sec->symbol)) {
offset += last_sec->addr;
STP_RUNLOCK_MODULES;
- dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset);
+ dbug_sym(1, "offset = %lx\n", offset);
return offset;
}
}
@@ -72,7 +72,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi
if (!strcmp(section, last_sec->symbol)) {
offset += last_sec->addr;
STP_RUNLOCK_MODULES;
- dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset);
+ dbug_sym(1, "offset = %lx\n", offset);
return offset;
}
}
@@ -223,8 +223,7 @@ void _stp_symbol_print(unsigned long address)
}
/* Like _stp_symbol_print, except only print if the address is a valid function address */
-
-void _stp_func_print(unsigned long address, int verbose, int exact)
+int _stp_func_print(unsigned long address, int verbose, int exact)
{
char *modname;
const char *name;
@@ -247,7 +246,9 @@ void _stp_func_print(unsigned long address, int verbose, int exact)
_stp_printf(" %p : %s+%#lx/%#lx%s\n", (int64_t) address, name, offset, size, exstr);
} else
_stp_printf("%p ", (int64_t) address);
+ return 1;
}
+ return 0;
}
void _stp_symbol_snprint(char *str, size_t len, unsigned long address)
diff --git a/runtime/sym.h b/runtime/sym.h
index b124882a..0bb64c13 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -7,8 +7,8 @@
* later version.
*/
-#ifndef _STAP_SYMBOLS_H_
-#define _STAP_SYMBOLS_H_
+#ifndef _STP_SYM_H_
+#define _STP_SYM_H_
#define STP_MODULE_NAME_LEN 64
@@ -16,11 +16,6 @@ struct _stp_symbol {
unsigned long addr;
const char *symbol;
};
-struct stap_symbol {
- unsigned long addr;
- const char *symbol;
- const char *module;
-};
DEFINE_RWLOCK(_stp_module_lock);
#define STP_RLOCK_MODULES read_lock_irqsave(&_stp_module_lock, flags)
@@ -50,8 +45,14 @@ struct _stp_module {
/* how many sections this module has */
uint32_t num_sections;
- /* how the symbol_data below was allocated */
- int32_t allocated; /* 0 = kmalloc, 1 = vmalloc */
+ /* how the data below was allocated */
+ /* 0 = kmalloc, 1 = vmalloc */
+ struct {
+ unsigned symbols :1;
+ unsigned symbol_data :1;
+ unsigned unwind_data :1;
+ unsigned unwind_hdr :1;
+ } allocated;
struct _stp_symbol *sections;
@@ -63,7 +64,10 @@ struct _stp_module {
/* the stack unwind data for this module */
void *unwind_data;
+ void *unwind_hdr;
uint32_t unwind_data_len;
+ uint32_t unwind_hdr_len;
+ uint32_t unwind_is_ehframe; /* unwind data comes from .eh_frame */
rwlock_t lock; /* lock while unwinding is happening */
};
@@ -80,7 +84,8 @@ struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES];
/* the number of modules in the arrays */
int _stp_num_modules = 0;
+static unsigned long _stp_kretprobe_trampoline = 0;
unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset);
static struct _stp_module *_stp_get_unwind_info (unsigned long addr);
-#endif /* _STAP_SYMBOLS_H_ */
+#endif /* _STP_SYM_H_ */
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index d2e57a6b..6d79c98a 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -1,9 +1,16 @@
#include <linux/list.h>
+#include <linux/binfmts.h>
static LIST_HEAD(__stp_task_finder_list);
struct stap_task_finder_target;
+#define __STP_TF_STARTING 0
+#define __STP_TF_RUNNING 1
+#define __STP_TF_STOPPING 2
+#define __STP_TF_STOPPED 3
+atomic_t __stp_task_finder_state = ATOMIC_INIT(__STP_TF_STARTING);
+
typedef int (*stap_task_finder_callback)(struct task_struct *tsk,
int register_p,
struct stap_task_finder_target *tgt);
@@ -23,6 +30,10 @@ struct stap_task_finder_target {
stap_task_finder_callback callback;
};
+static u32
+__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
+ struct task_struct *tsk);
+
static int
stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
{
@@ -38,6 +49,11 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
else
new_tgt->pathlen = 0;
+ // Make sure everything is initialized properly.
+ 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;
+
// Search the list for an existing entry for pathname/pid.
list_for_each(node, &__stp_task_finder_list) {
tgt = list_entry(node, struct stap_task_finder_target, list);
@@ -62,7 +78,6 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
}
// Add this target to the callback list for this task.
- new_tgt->engine_attached = 0;
list_add_tail(&new_tgt->callback_list, &tgt->callback_list_head);
return 0;
}
@@ -78,6 +93,10 @@ stap_utrace_detach_ops(struct utrace_engine_ops *ops)
rcu_read_lock();
for_each_process(tsk) {
struct mm_struct *mm;
+
+ if (tsk->pid <= 1)
+ continue;
+
mm = get_task_mm(tsk);
if (mm) {
mmput(mm);
@@ -152,11 +171,12 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
vma = vma->vm_next;
}
if (vma) {
- struct vfsmount *mnt = mntget(vma->vm_file->f_path.mnt);
- struct dentry *dentry = dget(vma->vm_file->f_path.dentry);
- rc = d_path(dentry, mnt, buf, buflen);
- dput(dentry);
- mntput(mnt);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+ rc = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt,
+ buf, buflen);
+#else
+ rc = d_path(&(vma->vm_file->f_path), buf, buflen);
+#endif
}
else {
*buf = '\0';
@@ -167,76 +187,82 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
}
#define __STP_UTRACE_TASK_FINDER_EVENTS (UTRACE_EVENT(CLONE) \
- | UTRACE_EVENT(EXEC))
+ | UTRACE_EVENT(EXEC) \
+ | UTRACE_EVENT(DEATH))
#define __STP_UTRACE_ATTACHED_TASK_EVENTS (UTRACE_EVENT(DEATH))
-static u32
-__stp_utrace_task_finder_clone(struct utrace_attached_engine *engine,
- struct task_struct *parent,
- unsigned long clone_flags,
- struct task_struct *child)
+static int
+__stp_utrace_attach(struct task_struct *tsk,
+ const struct utrace_engine_ops *ops, void *data,
+ unsigned long event_flags)
{
- struct utrace_attached_engine *child_engine;
+ struct utrace_attached_engine *engine;
struct mm_struct *mm;
+ int rc = 0;
- // On clone, attach to the child. Ignore threads with no mm
- // (which are kernel threads).
- mm = get_task_mm(child);
- if (mm) {
- mmput(mm);
- child_engine = utrace_attach(child, UTRACE_ATTACH_CREATE,
- engine->ops, 0);
- if (IS_ERR(child_engine))
- _stp_error("attach to clone child %d failed: %ld",
- (int)child->pid, PTR_ERR(child_engine));
- else {
- utrace_set_flags(child, child_engine,
- __STP_UTRACE_TASK_FINDER_EVENTS);
+ // Ignore init
+ if (tsk->pid <= 1)
+ return EPERM;
+
+ // Ignore threads with no mm (which are kernel threads).
+ mm = get_task_mm(tsk);
+ if (! mm)
+ return EPERM;
+ mmput(mm);
+
+ engine = utrace_attach(tsk, UTRACE_ATTACH_CREATE, ops, data);
+ if (IS_ERR(engine)) {
+ int error = -PTR_ERR(engine);
+ if (error != ENOENT) {
+ _stp_error("utrace_attach returned error %d on pid %d",
+ error, (int)tsk->pid);
+ rc = error;
}
}
- return UTRACE_ACTION_RESUME;
+ else if (unlikely(engine == NULL)) {
+ _stp_error("utrace_attach returned NULL on pid %d",
+ (int)tsk->pid);
+ rc = EFAULT;
+ }
+ else {
+ utrace_set_flags(tsk, engine, event_flags);
+ }
+ return rc;
}
static u32
-__stp_utrace_task_finder_death(struct utrace_attached_engine *engine,
- struct task_struct *tsk)
+__stp_utrace_task_finder_report_clone(struct utrace_attached_engine *engine,
+ struct task_struct *parent,
+ unsigned long clone_flags,
+ struct task_struct *child)
{
- struct stap_task_finder_target *tgt = engine->data;
-
- // The first implementation of this added a
- // UTRACE_EVENT(DEATH) handler to
- // __stp_utrace_task_finder_ops. However, dead threads don't
- // have a mm_struct, so we can't find the exe's path. So, we
- // don't know which callback(s) to call.
- //
- // So, now when an "interesting" thread is found, we add a
- // separate UTRACE_EVENT(DEATH) handler for every probe.
+ struct utrace_attached_engine *child_engine;
+ struct mm_struct *mm;
- if (tgt != NULL && tgt->callback != NULL) {
- int rc;
+ if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING)
+ return UTRACE_ACTION_RESUME;
- // Call the callback
- rc = tgt->callback(tsk, 0, tgt);
- if (rc != 0) {
- _stp_error("death callback for %d failed: %d",
- (int)tsk->pid, rc);
- }
- }
+ // On clone, attach to the child.
+ (void) __stp_utrace_attach(child, engine->ops, 0,
+ __STP_UTRACE_TASK_FINDER_EVENTS);
return UTRACE_ACTION_RESUME;
}
static u32
-__stp_utrace_task_finder_exec(struct utrace_attached_engine *engine,
- struct task_struct *tsk,
- const struct linux_binprm *bprm,
- struct pt_regs *regs)
+__stp_utrace_task_finder_report_exec(struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ const struct linux_binprm *bprm,
+ struct pt_regs *regs)
{
size_t filelen;
struct list_head *tgt_node;
struct stap_task_finder_target *tgt;
int found_node = 0;
+ 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;
@@ -258,6 +284,8 @@ __stp_utrace_task_finder_exec(struct utrace_attached_engine *engine,
struct list_head *cb_node;
list_for_each(cb_node, &tgt->callback_list_head) {
struct stap_task_finder_target *cb_tgt;
+ int rc;
+
cb_tgt = list_entry(cb_node,
struct stap_task_finder_target,
callback_list);
@@ -274,31 +302,59 @@ __stp_utrace_task_finder_exec(struct utrace_attached_engine *engine,
}
// Set up thread death notification.
- memset(&cb_tgt->ops, 0, sizeof(cb_tgt->ops));
- cb_tgt->ops.report_death
- = &__stp_utrace_task_finder_death;
-
- engine = utrace_attach(tsk,
- UTRACE_ATTACH_CREATE,
- &cb_tgt->ops, cb_tgt);
- if (IS_ERR(engine)) {
- _stp_error("attach to exec'ed %d failed: %ld",
- (int)tsk->pid,
- PTR_ERR(engine));
- }
- else {
- utrace_set_flags(tsk, engine,
+ rc = __stp_utrace_attach(tsk, &cb_tgt->ops, cb_tgt,
__STP_UTRACE_ATTACHED_TASK_EVENTS);
- cb_tgt->engine_attached = 1;
- }
+ if (rc != 0 && rc != EPERM)
+ break;
+ cb_tgt->engine_attached = 1;
}
}
return UTRACE_ACTION_RESUME;
}
+static u32
+stap_utrace_task_finder_report_death(struct utrace_attached_engine *engine,
+ struct task_struct *tsk)
+{
+ return UTRACE_ACTION_DETACH;
+}
+
+static u32
+__stp_utrace_task_finder_target_death(struct utrace_attached_engine *engine,
+ struct task_struct *tsk)
+{
+ struct stap_task_finder_target *tgt = engine->data;
+
+ if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
+ return UTRACE_ACTION_DETACH;
+ }
+
+ // The first implementation of this added a
+ // UTRACE_EVENT(DEATH) handler to
+ // __stp_utrace_task_finder_ops. However, dead threads don't
+ // have a mm_struct, so we can't find the exe's path. So, we
+ // don't know which callback(s) to call.
+ //
+ // So, now when an "interesting" thread is found, we add a
+ // separate UTRACE_EVENT(DEATH) handler for every probe.
+
+ if (tgt != NULL && tgt->callback != NULL) {
+ int rc;
+
+ // Call the callback
+ rc = tgt->callback(tsk, 0, tgt);
+ if (rc != 0) {
+ _stp_error("death callback for %d failed: %d",
+ (int)tsk->pid, rc);
+ }
+ }
+ return UTRACE_ACTION_DETACH;
+}
+
struct utrace_engine_ops __stp_utrace_task_finder_ops = {
- .report_clone = __stp_utrace_task_finder_clone,
- .report_exec = __stp_utrace_task_finder_exec,
+ .report_clone = __stp_utrace_task_finder_report_clone,
+ .report_exec = __stp_utrace_task_finder_report_exec,
+ .report_death = stap_utrace_task_finder_report_death,
};
int
@@ -314,44 +370,36 @@ stap_start_task_finder(void)
return ENOMEM;
}
+ atomic_set(&__stp_task_finder_state, __STP_TF_RUNNING);
+
rcu_read_lock();
for_each_process(tsk) {
- struct utrace_attached_engine *engine;
struct mm_struct *mm;
char *mmpath;
size_t mmpathlen;
struct list_head *tgt_node;
+ /* Attach to the thread */
+ rc = __stp_utrace_attach(tsk, &__stp_utrace_task_finder_ops, 0,
+ __STP_UTRACE_TASK_FINDER_EVENTS);
+ if (rc == EPERM) {
+ /* Ignore EPERM errors, which mean this wasn't
+ * a thread we can attach to. */
+ rc = 0;
+ continue;
+ }
+ else if (rc != 0) {
+ /* If we get a real error, quit. */
+ break;
+ }
+
+ /* Grab the path associated with this task. */
mm = get_task_mm(tsk);
if (! mm) {
/* If the thread doesn't have a mm_struct, it is
* a kernel thread which we need to skip. */
continue;
}
-
- /* Attach to the thread */
- engine = utrace_attach(tsk, UTRACE_ATTACH_CREATE,
- &__stp_utrace_task_finder_ops, 0);
- if (IS_ERR(engine)) {
- int error = -PTR_ERR(engine);
- if (error != ENOENT) {
- mmput(mm);
- _stp_error("utrace_attach returned error %d on pid %d",
- error, (int)tsk->pid);
- rc = error;
- break;
- }
- }
- else if (unlikely(engine == NULL)) {
- mmput(mm);
- _stp_error("utrace_attach returned NULL on pid %d",
- (int)tsk->pid);
- rc = EFAULT;
- break;
- }
- utrace_set_flags(tsk, engine, __STP_UTRACE_TASK_FINDER_EVENTS);
-
- /* Check the thread's exe's path/pid against our list. */
mmpath = __stp_get_mm_path(mm, mmpath_buf, PATH_MAX);
mmput(mm); /* We're done with mm */
if (IS_ERR(mmpath)) {
@@ -361,6 +409,7 @@ stap_start_task_finder(void)
break;
}
+ /* Check the thread's exe's path/pid against our list. */
mmpathlen = strlen(mmpath);
list_for_each(tgt_node, &__stp_task_finder_list) {
struct stap_task_finder_target *tgt;
@@ -394,10 +443,19 @@ stap_start_task_finder(void)
(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;
}
}
}
rcu_read_unlock();
+
_stp_kfree(mmpath_buf);
return rc;
}
@@ -405,6 +463,8 @@ stap_start_task_finder(void)
static void
stap_stop_task_finder(void)
{
+ atomic_set(&__stp_task_finder_state, __STP_TF_STOPPING);
stap_utrace_detach_ops(&__stp_utrace_task_finder_ops);
__stp_task_finder_cleanup();
+ atomic_set(&__stp_task_finder_state, __STP_TF_STOPPED);
}
diff --git a/runtime/time.c b/runtime/time.c
index 52a2edbb..8a0b6fad 100644
--- a/runtime/time.c
+++ b/runtime/time.c
@@ -131,10 +131,13 @@ __stp_time_timer_callback(unsigned long val)
time->base_cycles = cycles;
write_sequnlock(&time->lock);
+ local_irq_restore(flags);
+ /* PR6481: reenable IRQs before resetting the timer.
+ XXX: The worst that can probably happen is that we get
+ two consecutive timer resets. */
+
if (likely(stp_timer_reregister))
mod_timer(&time->timer, jiffies + 1);
-
- local_irq_restore(flags);
}
/* This is called as an IPI, with interrupts disabled. */
diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog
index c3837f86..9d0ba162 100644
--- a/runtime/transport/ChangeLog
+++ b/runtime/transport/ChangeLog
@@ -1,3 +1,51 @@
+2008-04-30 Masami Hiramatsu <mhiramat@redhat.com>
+
+ PR 5645
+ * transport.c (_stp_transport_init): Fix subbuffer size calculation
+ overflow.
+
+2008-04-21 hunt <hunt@redhat.com>
+
+ * control.c (_stp_ctl_write): Return len + sizeof(int) so
+ sending an empty command doesn't return 0 and look like a failure.
+ * transport.c: _stp_cleanup_and_exit(): Cleanup.
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6410
+ * symbols.c (_stp_do_unwind_data): Tolerate !STP_USE_DWARF_UNWINDER.
+
+2008-04-15 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6405
+ * symbols.c (_stp_load_module_symbols): Support older kernels
+ without module->sect_attrs->nsections.
+
+2008-04-09 Martin Hunt <hunt@dragon>
+
+ * symbols.c (_stp_init_kernel_symbols): Print error
+ messages and exit if symbol lookups fail.
+ (_stp_init_modules): Lookup modules_op.
+
+2008-03-31 Martin Hunt <hunt@redhat.com>
+
+ * symbols.c (_stp_init_modules): Use STP_USE_DWARF_UNWINDER.
+
+ * transport.c (_stp_get_root_dir): Remove misleading error message.
+
+2008-03-30 Martin Hunt <hunt@redhat.com>
+
+ * symbols.c (_stp_init_modules): If using frames, don't
+ request unwind info.
+
+2008-03-25 Martin Hunt <hunt@redhat.com>
+
+ * control.c (_stp_ctl_write_dbug): Insert missing break.
+
+ 32-bit systems can't do 64-bit get_user(), so
+ * symbols.c (_stp_do_unwind_data): Change unwind_len to a u32.
+ * transport_msgs.h (struct _stp_msg_unwind): Ditto.
+
2008-02-27 Martin Hunt <hunt@redhat.com>
* symbols.c: Use rwlocks. Use new dbug macros. Handle
diff --git a/runtime/transport/control.c b/runtime/transport/control.c
index 6a5b272d..ca7edf79 100644
--- a/runtime/transport/control.c
+++ b/runtime/transport/control.c
@@ -14,80 +14,31 @@ static int _stp_current_buffers = STP_DEFAULT_BUFFERS;
static _stp_mempool_t *_stp_pool_q;
static struct list_head _stp_ctl_ready_q;
-static struct list_head _stp_sym_ready_q;
DEFINE_SPINLOCK(_stp_ctl_ready_lock);
-DEFINE_SPINLOCK(_stp_sym_ready_lock);
-static ssize_t _stp_sym_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
- static int saved_type = 0;
- int type;
-
- if (count < sizeof(int32_t))
- return 0;
-
- /* Allow sending of packet type followed by data in the next packet. */
- if (count == sizeof(int32_t)) {
- if (get_user(saved_type, (int __user *)buf))
- return -EFAULT;
- return count;
- } else if (saved_type) {
- type = saved_type;
- saved_type = 0;
- } else {
- if (get_user(type, (int __user *)buf))
- return -EFAULT;
- count -= sizeof(int);
- buf += sizeof(int);
- }
-
-#if DEBUG_TRANSPORT > 0
- if (type < STP_MAX_CMD)
- _dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count);
-#endif
-
- switch (type) {
- case STP_SYMBOLS:
- count = _stp_do_symbols(buf, count);
- break;
- case STP_MODULE:
- if (count > 1)
- count = _stp_do_module(buf, count);
- else {
- /* count == 1 indicates end of initial modules list */
- _stp_ctl_send(STP_TRANSPORT, NULL, 0);
- }
- break;
- case STP_EXIT:
- _stp_exit_flag = 1;
- break;
- default:
- errk("invalid symbol command type %d\n", type);
- return -EINVAL;
- }
-
- return count;
-}
static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- int type;
+ u32 type;
static int started = 0;
- if (count < sizeof(int))
+ if (count < sizeof(u32))
return 0;
- if (get_user(type, (int __user *)buf))
+ if (get_user(type, (u32 __user *)buf))
return -EFAULT;
-#if DEBUG_TRANSPORT > 0
+ count -= sizeof(u32);
+ buf += sizeof(u32);
+
+#ifdef DEBUG_TRANS
if (type < STP_MAX_CMD)
_dbug("Got %s. len=%d\n", _stp_command_name[type], (int)count);
#endif
- count -= sizeof(int);
- buf += sizeof(int);
-
switch (type) {
+ case STP_UNWIND:
+ _stp_do_unwind_data(buf, count);
+ break;
case STP_START:
if (started == 0) {
struct _stp_msg_start st;
@@ -110,7 +61,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz
#endif
case STP_READY:
/* request symbolic information */
- _stp_ask_for_symbols();
+ /* _stp_ask_for_symbols(); */
break;
default:
@@ -121,8 +72,6 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz
return count;
}
-#define STP_CTL_BUFFER_SIZE 256
-
struct _stp_buffer {
struct list_head list;
int len;
@@ -131,9 +80,8 @@ struct _stp_buffer {
};
static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
-static DECLARE_WAIT_QUEUE_HEAD(_stp_sym_wq);
-#if DEBUG_TRANSPORT > 0
+#ifdef DEBUG_TRANS
static void _stp_ctl_write_dbug(int type, void *data, int len)
{
char buf[64];
@@ -155,19 +103,9 @@ static void _stp_ctl_write_dbug(int type, void *data, int len)
case STP_TRANSPORT:
_dbug("sending STP_TRANSPORT\n");
break;
- default:
- _dbug("ERROR: unknown message type: %d\n", type);
- break;
- }
-}
-static void _stp_sym_write_dbug(int type, void *data, int len)
-{
- switch (type) {
- case STP_SYMBOLS:
- _dbug("sending STP_SYMBOLS\n");
- break;
- case STP_MODULE:
- _dbug("sending STP_MODULE\n");
+ 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);
@@ -181,7 +119,7 @@ static int _stp_ctl_write(int type, void *data, unsigned len)
struct _stp_buffer *bptr;
unsigned long flags;
-#if DEBUG_TRANSPORT > 0
+#ifdef DEBUG_TRANS
_stp_ctl_write_dbug(type, data, len);
#endif
@@ -203,99 +141,22 @@ static int _stp_ctl_write(int type, void *data, unsigned len)
list_add_tail(&bptr->list, &_stp_ctl_ready_q);
spin_unlock_irqrestore(&_stp_ctl_ready_lock, flags);
- return len;
-}
-
-static int _stp_sym_write(int type, void *data, unsigned len)
-{
- struct _stp_buffer *bptr;
- unsigned long flags;
-
-#if DEBUG_TRANSPORT > 0
- _stp_sym_write_dbug(type, data, len);
-#endif
-
- /* make sure we won't overflow the buffer */
- if (unlikely(len > STP_CTL_BUFFER_SIZE))
- return 0;
-
- /* get a buffer from the free pool */
- bptr = _stp_mempool_alloc(_stp_pool_q);
- if (unlikely(bptr == NULL))
- return -1;
-
- bptr->type = type;
- memcpy(bptr->buf, data, len);
- bptr->len = len;
-
- /* put it on the pool of ready buffers */
- spin_lock_irqsave(&_stp_sym_ready_lock, flags);
- list_add_tail(&bptr->list, &_stp_sym_ready_q);
- spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
-
- /* OK, it's queued. Now signal any waiters. */
- wake_up_interruptible(&_stp_sym_wq);
-
- return len;
+ return len + sizeof(bptr->type);
}
/* send commands with timeout and retry */
static int _stp_ctl_send(int type, void *data, int len)
{
int err, trylimit = 50;
- kbug(DEBUG_TRANSPORT, "ctl_send: type=%d len=%d\n", type, len);
- if (unlikely(type == STP_SYMBOLS || type == STP_MODULE)) {
- while ((err = _stp_sym_write(type, data, len)) < 0 && trylimit--)
- msleep(5);
- } else {
- while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
- msleep(5);
- if (err > 0)
- wake_up_interruptible(&_stp_ctl_wq);
- }
- kbug(DEBUG_TRANSPORT, "returning %d\n", err);
+ dbug_trans(1, "ctl_send: type=%d len=%d\n", type, len);
+ while ((err = _stp_ctl_write(type, data, len)) < 0 && trylimit--)
+ msleep(5);
+ if (err > 0)
+ wake_up_interruptible(&_stp_ctl_wq);
+ dbug_trans(1, "returning %d\n", err);
return err;
}
-static ssize_t _stp_sym_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
- struct _stp_buffer *bptr;
- int len;
- unsigned long flags;
-
- /* wait for nonempty ready queue */
- spin_lock_irqsave(&_stp_sym_ready_lock, flags);
- while (list_empty(&_stp_sym_ready_q)) {
- spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- if (wait_event_interruptible(_stp_sym_wq, !list_empty(&_stp_sym_ready_q)))
- return -ERESTARTSYS;
- spin_lock_irqsave(&_stp_sym_ready_lock, flags);
- }
-
- /* get the next buffer off the ready list */
- bptr = (struct _stp_buffer *)_stp_sym_ready_q.next;
- list_del_init(&bptr->list);
- spin_unlock_irqrestore(&_stp_sym_ready_lock, flags);
-
- /* write it out */
- len = bptr->len + 4;
- if (len > count || copy_to_user(buf, &bptr->type, len)) {
- /* now what? We took it off the queue then failed to send it */
- /* we can't put it back on the queue because it will likely be out-of-order */
- /* fortunately this should never happen */
- /* FIXME need to mark this as a transport failure */
- errk("Supplied buffer too small. count:%d len:%d\n", (int)count, len);
- return -EFAULT;
- }
-
- /* put it on the pool of free buffers */
- _stp_mempool_free(bptr);
-
- return len;
-}
-
static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct _stp_buffer *bptr;
@@ -335,29 +196,10 @@ static ssize_t _stp_ctl_read_cmd(struct file *file, char __user *buf, size_t cou
return len;
}
-static int _stp_sym_opens = 0;
-static int _stp_sym_open_cmd(struct inode *inode, struct file *file)
-{
- /* only allow one reader */
- if (_stp_sym_opens)
- return -1;
-
- _stp_sym_opens++;
- return 0;
-}
-
-static int _stp_sym_close_cmd(struct inode *inode, struct file *file)
-{
- if (_stp_sym_opens)
- _stp_sym_opens--;
- return 0;
-}
-
static int _stp_ctl_open_cmd(struct inode *inode, struct file *file)
{
if (_stp_attached)
return -1;
-
_stp_attach();
return 0;
}
@@ -377,16 +219,7 @@ static struct file_operations _stp_ctl_fops_cmd = {
.release = _stp_ctl_close_cmd,
};
-static struct file_operations _stp_sym_fops_cmd = {
- .owner = THIS_MODULE,
- .read = _stp_sym_read_cmd,
- .write = _stp_sym_write_cmd,
- .open = _stp_sym_open_cmd,
- .release = _stp_sym_close_cmd,
-};
-
static struct dentry *_stp_cmd_file = NULL;
-static struct dentry *_stp_sym_file = NULL;
static int _stp_register_ctl_channel(void)
{
@@ -400,7 +233,6 @@ static int _stp_register_ctl_channel(void)
}
INIT_LIST_HEAD(&_stp_ctl_ready_q);
- INIT_LIST_HEAD(&_stp_sym_ready_q);
/* allocate buffers */
_stp_pool_q = _stp_mempool_init(sizeof(struct _stp_buffer), STP_DEFAULT_BUFFERS);
@@ -415,15 +247,9 @@ static int _stp_register_ctl_channel(void)
_stp_cmd_file->d_inode->i_uid = _stp_uid;
_stp_cmd_file->d_inode->i_gid = _stp_gid;
- /* create [debugfs]/systemtap/module_name/.symbols */
- _stp_sym_file = debugfs_create_file(".symbols", 0600, _stp_utt->dir, NULL, &_stp_sym_fops_cmd);
- if (_stp_sym_file == NULL)
- goto err0;
return 0;
err0:
- if (_stp_cmd_file)
- debugfs_remove(_stp_cmd_file);
_stp_mempool_destroy(_stp_pool_q);
errk("Error creating systemtap debugfs entries.\n");
return -1;
@@ -432,16 +258,10 @@ err0:
static void _stp_unregister_ctl_channel(void)
{
struct list_head *p, *tmp;
- if (_stp_sym_file)
- debugfs_remove(_stp_sym_file);
if (_stp_cmd_file)
debugfs_remove(_stp_cmd_file);
/* Return memory to pool and free it. */
- list_for_each_safe(p, tmp, &_stp_sym_ready_q) {
- list_del(p);
- _stp_mempool_free(p);
- }
list_for_each_safe(p, tmp, &_stp_ctl_ready_q) {
list_del(p);
_stp_mempool_free(p);
diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c
index 2afea1c9..750e1994 100644
--- a/runtime/transport/procfs.c
+++ b/runtime/transport/procfs.c
@@ -161,7 +161,7 @@ struct _stp_buffer {
struct list_head list;
int len;
int type;
- char buf[STP_BUFFER_SIZE];
+ char buf[STP_CTL_BUFFER_SIZE];
};
static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index 8c453a55..087bf893 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -12,8 +12,8 @@
* lib/sort.c of kernel 2.6.22-rc5. It was written by Matt Mackall.
*/
-#ifndef _SYMBOLS_C_
-#define _SYMBOLS_C_
+#ifndef _STP_SYMBOLS_C_
+#define _STP_SYMBOLS_C_
#include "../sym.h"
static char *_stp_symbol_data = NULL;
@@ -21,17 +21,12 @@ static int _stp_symbol_state = 0;
static char *_stp_module_data = NULL;
static int _stp_module_state = 0;
-
/* these are all the symbol types we are interested in */
static int _stp_sym_type_ok(int type)
{
- switch (type) {
- case 'T':
- case 't':
+ /* we only care about function symbols, which are in the text section */
+ if (type == 'T' || type == 't')
return 1;
- default:
- return 0;
- }
return 0;
}
@@ -41,10 +36,10 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize)
{
unsigned int i;
unsigned num = 0, datasize = 0;
- for (i=0; i < m->num_symtab; i++) {
+ for (i = 0; i < m->num_symtab; i++) {
char *str = (char *)(m->strtab + m->symtab[i].st_name);
if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) {
- datasize += strlen(str)+1;
+ datasize += strlen(str) + 1;
num++;
}
}
@@ -52,19 +47,23 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize)
return num;
}
-/* allocate space for a module and symbols */
-static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, unsigned unwindsize)
+/* allocate space for a module, sections, and symbols */
+static struct _stp_module *_stp_alloc_module(unsigned sectsize, unsigned num, unsigned datasize)
{
struct _stp_module *mod = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module));
if (mod == NULL)
goto bad;
+ mod->sections = (struct _stp_symbol *)_stp_kmalloc(sectsize);
+ if (mod->sections == NULL)
+ goto bad;
+
mod->symbols = (struct _stp_symbol *)_stp_kmalloc(num * sizeof(struct _stp_symbol));
if (mod->symbols == NULL) {
mod->symbols = (struct _stp_symbol *)_stp_vmalloc(num * sizeof(struct _stp_symbol));
if (mod->symbols == NULL)
goto bad;
- mod->allocated = 1;
+ mod->allocated.symbols = 1;
}
mod->symbol_data = _stp_kmalloc(datasize);
@@ -72,91 +71,63 @@ static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, u
mod->symbol_data = _stp_vmalloc(datasize);
if (mod->symbol_data == NULL)
goto bad;
- mod->allocated |= 2;
+ mod->allocated.symbol_data = 1;
}
- mod->unwind_data = _stp_kmalloc(unwindsize);
- if (mod->unwind_data == NULL) {
- mod->unwind_data = _stp_vmalloc(unwindsize);
- if (mod->unwind_data == NULL)
- goto bad;
- mod->allocated |= 4;
- }
-
mod->num_symbols = num;
return mod;
bad:
if (mod) {
+ if (mod->sections)
+ _stp_kfree(mod->sections);
if (mod->symbols) {
- if (mod->allocated & 1)
+ if (mod->allocated.symbols)
_stp_vfree(mod->symbols);
else
_stp_kfree(mod->symbols);
- mod->symbols = NULL;
}
- if (mod->symbol_data) {
- if (mod->allocated & 2)
- _stp_vfree(mod->symbol_data);
- else
- _stp_kfree(mod->symbol_data);
- mod->symbol_data = NULL;
- }
- _stp_kfree(mod);
- if (mod->symbols) {
- if (mod->allocated & 1)
- _stp_vfree(mod->symbols);
- else
- _stp_kfree(mod->symbols);
- mod->symbols = NULL;
- }
- _stp_kfree(mod);
+ _stp_kfree(mod);
}
return NULL;
}
-static struct _stp_module * _stp_alloc_module_from_module (struct module *m, uint32_t unwind_len)
-{
- unsigned datasize, num = _stp_get_sym_sizes(m, &datasize);
- return _stp_alloc_module(num, datasize, unwind_len);
-}
-
static void _stp_free_module(struct _stp_module *mod)
{
/* The module write lock is held. Any prior readers of this */
/* module's data will have read locks and need to finish before */
/* the memory is freed. */
write_lock(&mod->lock);
- write_unlock(&mod->lock); /* there will be no more readers */
+ write_unlock(&mod->lock); /* there will be no more readers */
- /* free symbol memory */
- if (mod->symbols) {
- if (mod->allocated & 1)
- _stp_vfree(mod->symbols);
- else
- _stp_kfree(mod->symbols);
- mod->symbols = NULL;
- }
+ /* Free symbol memory */
+ /* If symbol_data wasn't allocated, then symbols weren't either. */
if (mod->symbol_data) {
- if (mod->allocated & 2)
+ if (mod->symbols) {
+ if (mod->allocated.symbols)
+ _stp_vfree(mod->symbols);
+ else
+ _stp_kfree(mod->symbols);
+ }
+ if (mod->allocated.symbol_data)
_stp_vfree(mod->symbol_data);
else
_stp_kfree(mod->symbol_data);
- mod->symbol_data = NULL;
-
}
if (mod->unwind_data) {
- if (mod->allocated & 4)
+ if (mod->allocated.unwind_data)
_stp_vfree(mod->unwind_data);
else
_stp_kfree(mod->unwind_data);
- mod->unwind_data = NULL;
-
}
- if (mod->sections) {
- _stp_kfree(mod->sections);
- mod->sections = NULL;
+ if (mod->unwind_hdr) {
+ if (mod->allocated.unwind_hdr)
+ _stp_vfree(mod->unwind_hdr);
+ else
+ _stp_kfree(mod->unwind_hdr);
}
+ if (mod->sections)
+ _stp_kfree(mod->sections);
/* free module memory */
_stp_kfree(mod);
@@ -168,7 +139,7 @@ static void _stp_del_module(struct _stp_module *mod)
{
int i, num;
- // kbug(DEBUG_SYMBOLS, "deleting %s\n", mod->name);
+ dbug_sym(1, "deleting module %s\n", mod->name);
/* signal relocation code to clear its cache */
_stp_module_relocate((char *)-1, NULL, 0);
@@ -181,15 +152,15 @@ static void _stp_del_module(struct _stp_module *mod)
if (num >= _stp_num_modules)
return;
- for (i = num; i < _stp_num_modules-1; i++)
- _stp_modules[i] = _stp_modules[i+1];
+ for (i = num; i < _stp_num_modules - 1; i++)
+ _stp_modules[i] = _stp_modules[i + 1];
for (num = 0; num < _stp_num_modules; num++) {
if (_stp_modules_by_addr[num] == mod)
break;
}
- for (i = num; i < _stp_num_modules-1; i++)
- _stp_modules_by_addr[i] = _stp_modules_by_addr[i+1];
+ for (i = num; i < _stp_num_modules - 1; i++)
+ _stp_modules_by_addr[i] = _stp_modules_by_addr[i + 1];
_stp_num_modules--;
@@ -197,10 +168,8 @@ static void _stp_del_module(struct _stp_module *mod)
}
static void _stp_free_modules(void)
-{
+{
int i;
- unsigned long flags;
-
/* This only happens when the systemtap module unloads */
/* so there is no need for locks. */
for (i = _stp_num_modules - 1; i >= 0; i--)
@@ -208,82 +177,134 @@ static void _stp_free_modules(void)
}
static unsigned long _stp_kallsyms_lookup_name(const char *name);
+static void _stp_create_unwind_hdr(struct _stp_module *m);
+
+extern unsigned _stp_num_kernel_symbols;
+extern struct _stp_symbol _stp_kernel_symbols[];
-/* process the KERNEL symbols */
-static int _stp_do_symbols(const char __user *buf, int count)
+/* initialize the kernel symbols */
+static int _stp_init_kernel_symbols(void)
{
- struct _stp_symbol *s;
- unsigned datasize, num, unwindsize;
+ _stp_modules[0] = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module));
+ if (_stp_modules[0] == NULL) {
+ _dbug("cannot allocate memory\n");
+ return -1;
+ }
+ _stp_modules[0]->symbols = _stp_kernel_symbols;
+ _stp_modules[0]->num_symbols = _stp_num_kernel_symbols;
+ rwlock_init(&_stp_modules[0]->lock);
+ _stp_num_modules = 1;
+
+ /* Note: this mapping is used by kernel/_stext pseudo-relocations. */
+ _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext");
+ if (_stp_modules[0]->text == 0) {
+ _dbug("Lookup of _stext failed. Exiting.\n");
+ return -1;
+ }
+ _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext");
+ if (_stp_modules[0]->data == 0) {
+ _dbug("Lookup of _etext failed. Exiting.\n");
+ return -1;
+ }
+ _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text;
+ _stp_modules_by_addr[0] = _stp_modules[0];
+
+ _stp_kretprobe_trampoline = _stp_kallsyms_lookup_name("kretprobe_trampoline");
+ /* Lookup failure is not fatal */
+
+ return 0;
+}
+
+static void _stp_do_unwind_data(const char __user *buf, size_t count)
+{
+ u32 unwind_len;
+ unsigned long flags;
+ char name[STP_MODULE_NAME_LEN];
int i;
+ struct _stp_module *m;
+
+ dbug_unwind(1, "got unwind data, count=%d\n", count);
- switch (_stp_symbol_state) {
- case 0:
- if (count != sizeof(struct _stp_msg_symbol_hdr)) {
- errk("count=%d\n", count);
- return -EFAULT;
- }
- if (get_user(num, (unsigned __user *)buf))
- return -EFAULT;
- if (get_user(datasize, (unsigned __user *)(buf+4)))
- return -EFAULT;
- if (get_user(unwindsize, (unsigned __user *)(buf+8)))
- return -EFAULT;
- dbug(DEBUG_UNWIND, "num=%d datasize=%d unwindsize=%d\n", num, datasize, unwindsize);
-
- _stp_modules[0] = _stp_alloc_module(num, datasize, unwindsize);
- if (_stp_modules[0] == NULL) {
- errk("cannot allocate memory\n");
- return -EFAULT;
+ if (count < STP_MODULE_NAME_LEN + sizeof(unwind_len)) {
+ dbug_unwind(1, "unwind message too short\n");
+ return;
+ }
+ if (strncpy_from_user(name, buf, STP_MODULE_NAME_LEN) < 0) {
+ errk("userspace copy failed\n");
+ return;
+ }
+ dbug_unwind(1, "name=%s\n", name);
+ if (!strcmp(name,"*")) {
+ /* OK, all initial unwind data received. Ready to go. */
+ _stp_ctl_send(STP_TRANSPORT, NULL, 0);
+ return;
+ }
+ count -= STP_MODULE_NAME_LEN;
+ buf += STP_MODULE_NAME_LEN;
+
+ if (get_user(unwind_len, (u32 __user *)buf)) {
+ errk("userspace copy failed\n");
+ return;
+ }
+ count -= sizeof(unwind_len);
+ buf += sizeof(unwind_len);
+ if (count != unwind_len) {
+ dbug_unwind(1, "count=%d unwind_len=%d\n", (int)count, (int)unwind_len);
+ return;
+ }
+
+ STP_RLOCK_MODULES;
+ for (i = 0; i < _stp_num_modules; i++) {
+ if (strcmp(name, _stp_modules[i]->name) == 0)
+ break;
+ }
+ if (unlikely(i == _stp_num_modules)) {
+ dbug_unwind(1, "module %s not found!\n", name);
+ STP_RUNLOCK_MODULES;
+ return;
+ }
+ m = _stp_modules[i];
+ write_lock(&m->lock);
+ STP_RUNLOCK_MODULES;
+
+ /* allocate space for unwind data */
+ m->unwind_data = _stp_kmalloc(count);
+ if (unlikely(m->unwind_data == NULL)) {
+ m->unwind_data = _stp_vmalloc(count);
+ if (m->unwind_data == NULL) {
+ errk("kmalloc failed\n");
+ goto done;
}
- rwlock_init(&_stp_modules[0]->lock);
- _stp_symbol_state = 1;
- break;
- case 1:
- dbug(DEBUG_SYMBOLS, "got stap_symbols, count=%d\n", count);
- if (copy_from_user ((char *)_stp_modules[0]->symbols, buf, count))
- return -EFAULT;
- _stp_symbol_state = 2;
- break;
- case 2:
- dbug(DEBUG_SYMBOLS, "got symbol data, count=%d buf=%p\n", count, buf);
- if (copy_from_user (_stp_modules[0]->symbol_data, buf, count))
- return -EFAULT;
- _stp_num_modules = 1;
-
- s = _stp_modules[0]->symbols;
- for (i = 0; i < _stp_modules[0]->num_symbols; i++)
- s[i].symbol += (long)_stp_modules[0]->symbol_data;
-
- _stp_symbol_state = 3;
- /* NB: this mapping is used by kernel/_stext pseudo-relocations. */
- _stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext");
- _stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext");
- _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text;
- _stp_modules_by_addr[0] = _stp_modules[0];
- dbug(DEBUG_SYMBOLS, "Got kernel symbols. text=%p len=%u\n",
- (int64_t)_stp_modules[0]->text, _stp_modules[0]->text_size);
- break;
- case 3:
- dbug(DEBUG_UNWIND, "got unwind data, count=%d\n", count);
- _stp_symbol_state = 4;
- if (copy_from_user (_stp_modules[0]->unwind_data, buf, count)) {
- _dbug("cfu failed\n");
- return -EFAULT;
+ m->allocated.unwind_data = 1;
+ }
+
+ if (unlikely(copy_from_user(m->unwind_data, buf, count))) {
+ errk("userspace copy failed\n");
+ if (m->unwind_data) {
+ if (m->allocated.unwind_data)
+ _stp_vfree(m->unwind_data);
+ else
+ _stp_kfree(m->unwind_data);
+ m->unwind_data = NULL;
}
- _stp_modules[0]->unwind_data_len = count;
- break;
- default:
- errk("unexpected symbol data of size %d.\n", count);
+ goto done;
}
- return count;
+ m->unwind_data_len = count;
+#ifdef STP_USE_DWARF_UNWINDER
+ _stp_create_unwind_hdr(m);
+#endif
+done:
+ write_unlock(&m->lock);
}
static int _stp_compare_addr(const void *p1, const void *p2)
{
struct _stp_symbol *s1 = (struct _stp_symbol *)p1;
struct _stp_symbol *s2 = (struct _stp_symbol *)p2;
- if (s1->addr == s2->addr) return 0;
- if (s1->addr < s2->addr) return -1;
+ if (s1->addr == s2->addr)
+ return 0;
+ if (s1->addr < s2->addr)
+ return -1;
return 1;
}
@@ -332,18 +353,17 @@ static void generic_swap(void *a, void *b, int size)
* it less suitable for kernel use.
*/
void _stp_sort(void *base, size_t num, size_t size,
- int (*cmp)(const void *, const void *),
- void (*swap)(void *, void *, int size))
+ int (*cmp) (const void *, const void *), void (*swap) (void *, void *, int size))
{
/* pre-scale counters for performance */
- int i = (num/2 - 1) * size, n = num * size, c, r;
+ int i = (num / 2 - 1) * size, n = num * size, c, r;
if (!swap)
swap = (size == 4 ? u32_swap : generic_swap);
/* heapify */
- for ( ; i >= 0; i -= size) {
- for (r = i; r * 2 + size < n; r = c) {
+ for (; i >= 0; i -= size) {
+ for (r = i; r * 2 + size < n; r = c) {
c = r * 2 + size;
if (c < n - size && cmp(base + c, base + c + size) < 0)
c += size;
@@ -367,65 +387,125 @@ void _stp_sort(void *base, size_t num, size_t size,
}
}
+/* filter out section names we don't care about */
+static int _stp_section_is_interesting(const char *name)
+{
+ int ret = 1;
+ if (!strncmp("__", name, 2)
+ || !strncmp(".note", name, 5)
+ || !strncmp(".gnu", name, 4)
+ || !strncmp(".mod", name, 4))
+ ret = 0;
+ return ret;
+}
+
/* Create a new _stp_module and load the symbols */
-static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod, uint32_t unwind_len)
+static struct _stp_module *_stp_load_module_symbols(struct module *mod)
{
- unsigned i, num=0;
- struct module *m = (struct module *)imod->module;
- struct _stp_module *mod = NULL;
- char *dataptr;
+ int i, num, overflow = 0;
+ struct module_sect_attrs *sa = mod->sect_attrs;
+ struct attribute_group *sag = & sa->grp;
+ unsigned sect_size = 0, sect_num = 0, sym_size, sym_num;
+ struct _stp_module *sm;
+ char *dataptr, *endptr;
+ unsigned nsections = 0;
+
+#ifdef STAPCONF_MODULE_NSECTIONS
+ nsections = sa->nsections;
+#else
+ /* count section attributes on older kernel */
+ struct attribute** gattr;
+ for (gattr = sag->attrs; *gattr; gattr++)
+ nsections++;
+ dbug_sym(2, "\tcount %d\n", nsections);
+#endif
+
+ /* calculate how much space to allocate for section strings */
+ for (i = 0; i < nsections; i++) {
+ if (_stp_section_is_interesting(sa->attrs[i].name)) {
+ sect_num++;
+ sect_size += strlen(sa->attrs[i].name) + 1;
+ dbug_sym(2, "\t%s\t%lx\n", sa->attrs[i].name, sa->attrs[i].address);
+ }
+ }
+ sect_size += sect_num * sizeof(struct _stp_symbol);
- if (m == NULL) {
- kbug(DEBUG_SYMBOLS, "imod->module is NULL\n");
+ /* and how much space for symbols */
+ sym_num = _stp_get_sym_sizes(mod, &sym_size);
+
+ sm = _stp_alloc_module(sect_size, sym_num, sym_size);
+ if (!sm) {
+ errk("failed to allocate memory for module.\n");
return NULL;
}
- if (try_module_get(m)) {
- mod = _stp_alloc_module_from_module(m, unwind_len);
- if (mod == NULL) {
- module_put(m);
- errk("failed to allocate memory for module.\n");
- return NULL;
- }
+ strlcpy(sm->name, mod->name, STP_MODULE_NAME_LEN);
+ sm->module = (unsigned long)mod;
+ sm->text = (unsigned long)mod->module_core;
+ sm->text_size = mod->core_text_size;
+ sm->data = 0; /* fixme */
+ sm->num_sections = sect_num;
+ rwlock_init(&sm->lock);
- strlcpy(mod->name, imod->name, STP_MODULE_NAME_LEN);
- mod->module = imod->module;
- mod->text = imod->text;
- mod->data = imod->data;
- mod->num_sections = imod->num_sections;
- mod->sections = imod->sections;
- mod->text_size = m->core_text_size;
- rwlock_init(&mod->lock);
-
- /* now copy all the symbols we are interested in */
- dataptr = mod->symbol_data;
- for (i=0; i < m->num_symtab; i++) {
- char *str = (char *)(m->strtab + m->symtab[i].st_name);
- if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) {
- mod->symbols[num].symbol = dataptr;
- mod->symbols[num].addr = m->symtab[i].st_value;
- while (*str) *dataptr++ = *str++;
- *dataptr++ = 0;
- num++;
+ /* copy in section data */
+ dataptr = (char *)((long)sm->sections + sect_num * sizeof(struct _stp_symbol));
+ endptr = (char *)((long)sm->sections + sect_size);
+ num = 0;
+ for (i = 0; i < nsections; i++) {
+ size_t len, maxlen;
+ if (_stp_section_is_interesting(sa->attrs[i].name)) {
+ sm->sections[num].addr = sa->attrs[i].address;
+ sm->sections[num].symbol = dataptr;
+ maxlen = (size_t) (endptr - dataptr);
+ len = strlcpy(dataptr, sa->attrs[i].name, maxlen);
+ if (unlikely(len >= maxlen)) {
+ _dbug("dataptr=%lx endptr=%lx len=%d maxlen=%d\n", dataptr, endptr, len, maxlen);
+ overflow = 1;
}
+ dataptr += len + 1;
+ num++;
}
- module_put(m);
+ }
+ if (unlikely(overflow)) {
+ errk("Section names truncated!!! Should never happen!!\n");
+ *endptr = 0;
+ overflow = 0;
+ }
- /* sort symbols by address */
- _stp_sort (mod->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol);
+ /* now copy all the symbols we are interested in */
+ dataptr = sm->symbol_data;
+ endptr = dataptr + sym_size - 1;
+ num = 0;
+ for (i = 0; i < mod->num_symtab; i++) {
+ char *str = (char *)(mod->strtab + mod->symtab[i].st_name);
+ if (*str != '\0' && _stp_sym_type_ok(mod->symtab[i].st_info)) {
+ sm->symbols[num].symbol = dataptr;
+ sm->symbols[num].addr = mod->symtab[i].st_value;
+ while (*str && (dataptr < endptr))
+ *dataptr++ = *str++;
+ if (unlikely(*str))
+ overflow = 1;
+ *dataptr++ = 0;
+ num++;
+ }
}
- return mod;
+ if (unlikely(overflow))
+ errk("Symbol names truncated!!! Should never happen!!\n");
+
+ /* sort symbols by address */
+ _stp_sort(sm->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol);
+
+ return sm;
}
-/* Remove any old module info from our database */
-static void _stp_module_exists_delete (struct _stp_module *mod)
+/* Remove any old module info from our database. */
+static void _stp_module_exists_delete(struct _stp_module *mod)
{
int i, num;
-
/* remove any old modules with the same name */
for (num = 1; num < _stp_num_modules; num++) {
if (strcmp(_stp_modules[num]->name, mod->name) == 0) {
- dbug(DEBUG_SYMBOLS, "found existing module with name %s. Deleting.\n", mod->name);
+ dbug_sym(1, "found existing module with name %s. Deleting.\n", mod->name);
_stp_del_module(_stp_modules[num]);
break;
}
@@ -435,143 +515,61 @@ static void _stp_module_exists_delete (struct _stp_module *mod)
for (num = 1; num < _stp_num_modules; num++) {
if (mod->text + mod->text_size < _stp_modules_by_addr[num]->text)
continue;
- if (mod->text < _stp_modules_by_addr[num]->text
- + _stp_modules_by_addr[num]->text_size) {
- dbug(DEBUG_SYMBOLS, "New module %s overlaps with old module %s. Deleting old.\n",
- mod->name, _stp_modules_by_addr[num]->name);
+ if (mod->text < _stp_modules_by_addr[num]->text + _stp_modules_by_addr[num]->text_size) {
+ dbug_sym(1, "New module %s overlaps with old module %s. Deleting old.\n",
+ mod->name, _stp_modules_by_addr[num]->name);
_stp_del_module(_stp_modules_by_addr[num]);
}
}
}
-static int _stp_ins_module(struct _stp_module *mod)
+static void _stp_ins_module(struct module *mod)
{
- int i, num, res, ret = 0;
+ int i, num, res;
unsigned long flags;
-
- // kbug(DEBUG_SYMBOLS, "insert %s\n", mod->name);
+ struct _stp_module *m;
+ dbug_sym(1, "insert %s\n", mod->name);
+ m = _stp_load_module_symbols(mod);
+ if (m == NULL)
+ return;
STP_WLOCK_MODULES;
-
- _stp_module_exists_delete(mod);
-
+ _stp_module_exists_delete(m);
/* check for overflow */
if (_stp_num_modules == STP_MAX_MODULES) {
errk("Exceeded the limit of %d modules\n", STP_MAX_MODULES);
- ret = -ENOMEM;
goto done;
}
-
+
/* insert alphabetically in _stp_modules[] */
for (num = 1; num < _stp_num_modules; num++)
- if (strcmp(_stp_modules[num]->name, mod->name) > 0)
+ if (strcmp(_stp_modules[num]->name, m->name) > 0)
break;
for (i = _stp_num_modules; i > num; i--)
- _stp_modules[i] = _stp_modules[i-1];
- _stp_modules[num] = mod;
-
+ _stp_modules[i] = _stp_modules[i - 1];
+ _stp_modules[num] = m;
/* insert by text address in _stp_modules_by_addr[] */
for (num = 1; num < _stp_num_modules; num++)
- if (mod->text < _stp_modules_by_addr[num]->text)
+ if (m->text < _stp_modules_by_addr[num]->text)
break;
for (i = _stp_num_modules; i > num; i--)
- _stp_modules_by_addr[i] = _stp_modules_by_addr[i-1];
- _stp_modules_by_addr[num] = mod;
-
+ _stp_modules_by_addr[i] = _stp_modules_by_addr[i - 1];
+ _stp_modules_by_addr[num] = m;
_stp_num_modules++;
-
done:
STP_WUNLOCK_MODULES;
- return ret;
-}
-
-
-/* Called from procfs.c when a STP_MODULE msg is received */
-static int _stp_do_module(const char __user *buf, int count)
-{
- struct _stp_msg_module tmpmod;
- struct _stp_module mod, *m;
- unsigned i, section_len;
-
- if (count < (int)sizeof(tmpmod)) {
- errk("expected %d and got %d\n", (int)sizeof(tmpmod), count);
- return -EFAULT;
- }
- if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod)))
- return -EFAULT;
-
- section_len = count - sizeof(tmpmod) - tmpmod.unwind_len;
- if (section_len <= 0) {
- errk("section_len = %d\n", section_len);
- return -EFAULT;
- }
- dbug(DEBUG_SYMBOLS, "Got module %s, count=%d section_len=%d unwind_len=%d\n",
- tmpmod.name, count, section_len, tmpmod.unwind_len);
-
- strcpy(mod.name, tmpmod.name);
- mod.module = tmpmod.module;
- mod.text = tmpmod.text;
- mod.data = tmpmod.data;
- mod.num_sections = tmpmod.num_sections;
-
- /* copy in section data */
- mod.sections = _stp_kmalloc(section_len);
- if (mod.sections == NULL) {
- errk("unable to allocate memory.\n");
- return -EFAULT;
- }
- if (copy_from_user ((char *)mod.sections, buf+sizeof(tmpmod), section_len)) {
- _stp_kfree(mod.sections);
- return -EFAULT;
- }
- for (i = 0; i < mod.num_sections; i++) {
- mod.sections[i].symbol =
- (char *)((long)mod.sections[i].symbol
- + (long)((long)mod.sections + mod.num_sections * sizeof(struct _stp_symbol)));
- }
-
- #if 0
- for (i = 0; i < mod.num_sections; i++)
- _dbug("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr);
- #endif
-
- /* load symbols from tmpmod.module to mod */
- m = _stp_load_module_symbols(&mod, tmpmod.unwind_len);
- if (m == NULL) {
- _stp_kfree(mod.sections);
- return 0;
- }
-
- dbug(DEBUG_SYMBOLS, "module %s loaded. Text=%p text_size=%u\n", m->name, (int64_t)m->text, m->text_size);
- /* finally copy unwind info */
- if (copy_from_user (m->unwind_data, buf+sizeof(tmpmod)+section_len, tmpmod.unwind_len)) {
- _stp_free_module(m);
- _stp_kfree(mod.sections);
- return -EFAULT;
- }
- m->unwind_data_len = tmpmod.unwind_len;
-
- if (_stp_ins_module(m) < 0) {
- _stp_free_module(m);
- return -ENOMEM;
- }
-
- return count;
+ return;
}
-static int _stp_ctl_send (int type, void *data, int len);
-
-static int _stp_module_load_notify(struct notifier_block * self, unsigned long val, void * data)
+static int _stp_module_load_notify(struct notifier_block *self, unsigned long val, void *data)
{
struct module *mod = (struct module *)data;
struct _stp_module rmod;
-
switch (val) {
case MODULE_STATE_COMING:
- dbug(DEBUG_SYMBOLS, "module %s load notify\n", mod->name);
- strlcpy(rmod.name, mod->name, STP_MODULE_NAME_LEN);
- _stp_ctl_send(STP_MODULE, &rmod, sizeof(struct _stp_module));
+ dbug_sym(1, "module %s load notify\n", mod->name);
+ _stp_ins_module(mod);
break;
default:
errk("module loaded? val=%ld\n", val);
@@ -583,4 +581,72 @@ static struct notifier_block _stp_module_load_nb = {
.notifier_call = _stp_module_load_notify,
};
-#endif /* _SYMBOLS_C_ */
+#include <linux/seq_file.h>
+
+static int _stp_init_modules(void)
+{
+ loff_t pos = 0;
+ void *res;
+ struct module *mod;
+ const struct seq_operations *modules_op = (const struct seq_operations *)_stp_kallsyms_lookup_name("modules_op");
+
+ if (modules_op == NULL) {
+ _dbug("Lookup of modules_op failed.\n");
+ return -1;
+ }
+
+ /* Use the seq_file interface to safely get a list of installed modules */
+ res = modules_op->start(NULL, &pos);
+ while (res) {
+ mod = list_entry(res, struct module, list);
+ _stp_ins_module(mod);
+ res = modules_op->next(NULL, res, &pos);
+ }
+
+ if (register_module_notifier(&_stp_module_load_nb))
+ errk("failed to load module notifier\n");
+
+ /* unlocks the list */
+ modules_op->stop(NULL, NULL);
+
+#ifdef STP_USE_DWARF_UNWINDER
+ /* now that we have all the modules, ask for their unwind info */
+ {
+ unsigned long flags;
+ int i, left = STP_CTL_BUFFER_SIZE;
+ char buf[STP_CTL_BUFFER_SIZE];
+ char *ptr = buf;
+ *ptr = 0;
+
+ STP_RLOCK_MODULES;
+ /* Loop through modules, sending module names packed into */
+ /* messages of size STP_CTL_BUFFER. */
+ for (i = 0; i < _stp_num_modules; i++) {
+ char *name = _stp_modules[i]->name;
+ int len = strlen(name);
+ if (len >= left) {
+ _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left);
+ ptr = buf;
+ left = STP_CTL_BUFFER_SIZE;
+ }
+ strlcpy(ptr, name, left);
+ ptr += len + 1;
+ left -= len + 1;
+ }
+ STP_RUNLOCK_MODULES;
+
+ /* Send terminator. When we get this back from stapio */
+ /* that means all the unwind info has been sent. */
+ strlcpy(ptr, "*", left);
+ left -= 2;
+ _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left);
+ }
+#else
+ /* done with modules, now go */
+ _stp_ctl_send(STP_TRANSPORT, NULL, 0);
+#endif /* STP_USE_DWARF_UNWINDER */
+
+ return 0;
+}
+
+#endif /* _STP_SYMBOLS_C_ */
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index 8335e44b..a4e4e652 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -23,83 +23,47 @@
#include "../procfs.c"
static struct utt_trace *_stp_utt = NULL;
-
+static unsigned int utt_seq = 1;
+static int _stp_probes_started = 0;
+pid_t _stp_target = 0;
+static int _stp_exit_called = 0;
+int _stp_exit_flag = 0;
#ifdef STP_OLD_TRANSPORT
#include "relayfs.c"
+#include "procfs.c"
#else
#include "utt.c"
+#include "control.c"
#endif
-static unsigned int utt_seq = 1;
-
-static int _stp_probes_started = 0;
-
/* module parameters */
static int _stp_bufsize;
module_param(_stp_bufsize, int, 0);
MODULE_PARM_DESC(_stp_bufsize, "buffer size");
-pid_t _stp_target = 0;
-static int _stp_exit_called = 0;
-int _stp_exit_flag = 0;
-
/* forward declarations */
void probe_exit(void);
int probe_start(void);
void _stp_exit(void);
-void _stp_handle_start (struct _stp_msg_start *st);
-static void _stp_detach(void);
-static void _stp_attach(void);
/* check for new workqueue API */
-#ifdef DECLARE_DELAYED_WORK
-static void _stp_work_queue (struct work_struct *data);
+#ifdef DECLARE_DELAYED_WORK
+static void _stp_work_queue(struct work_struct *data);
static DECLARE_DELAYED_WORK(_stp_work, _stp_work_queue);
#else
-static void _stp_work_queue (void *data);
+static void _stp_work_queue(void *data);
static DECLARE_WORK(_stp_work, _stp_work_queue, NULL);
#endif
static struct workqueue_struct *_stp_wq;
-static void _stp_ask_for_symbols(void);
-
-#ifdef STP_OLD_TRANSPORT
-#include "procfs.c"
-#else
-#include "control.c"
-#endif
-
-static void _stp_ask_for_symbols(void)
-{
- struct _stp_msg_symbol req;
- struct _stp_module mod;
- static int sent_symbols = 0;
-
- if (sent_symbols == 0) {
- /* ask for symbols and modules */
- kbug(DEBUG_SYMBOLS|DEBUG_TRANSPORT, "AFS\n");
-
- req.endian = 0x1234;
- req.ptr_size = sizeof(char *);
- _stp_ctl_send(STP_SYMBOLS, &req, sizeof(req));
-
- strcpy(mod.name, "");
- _stp_ctl_send(STP_MODULE, &mod, sizeof(mod));
- sent_symbols = 1;
- }
-}
/*
* _stp_handle_start - handle STP_START
*/
-void _stp_handle_start (struct _stp_msg_start *st)
+void _stp_handle_start(struct _stp_msg_start *st)
{
- kbug (DEBUG_TRANSPORT, "stp_handle_start\n");
-
- if (register_module_notifier(&_stp_module_load_nb))
- errk("failed to load module notifier\n");
-
+ dbug_trans(1, "stp_handle_start\n");
_stp_target = st->target;
st->res = probe_start();
if (st->res >= 0)
@@ -108,16 +72,14 @@ void _stp_handle_start (struct _stp_msg_start *st)
_stp_ctl_send(STP_START, st, sizeof(*st));
}
-
/* common cleanup code. */
/* This is called from the kernel thread when an exit was requested */
-/* by staprun or the exit() function. It is also called by transport_close() */
-/* when the module is removed. In that case "dont_rmmod" is set to 1. */
+/* by staprun or the exit() function. */
/* We need to call it both times because we want to clean up properly */
/* when someone does /sbin/rmmod on a loaded systemtap module. */
-static void _stp_cleanup_and_exit (int dont_rmmod)
+static void _stp_cleanup_and_exit(int send_exit)
{
- kbug(DEBUG_TRANSPORT, "cleanup_and_exit (%d)\n", dont_rmmod);
+ dbug_trans(1, "cleanup_and_exit (%d)\n", send_exit);
if (!_stp_exit_called) {
int failures;
@@ -128,23 +90,24 @@ static void _stp_cleanup_and_exit (int dont_rmmod)
_stp_exit_called = 1;
if (_stp_probes_started) {
- kbug(DEBUG_TRANSPORT, "calling probe_exit\n");
+ dbug_trans(1, "calling probe_exit\n");
/* tell the stap-generated code to unload its probes, etc */
probe_exit();
- kbug(DEBUG_TRANSPORT, "done with probe_exit\n");
+ dbug_trans(1, "done with probe_exit\n");
}
failures = atomic_read(&_stp_transport_failures);
if (failures)
- _stp_warn ("There were %d transport failures.\n", failures);
+ _stp_warn("There were %d transport failures.\n", failures);
- kbug(DEBUG_TRANSPORT, "************** calling startstop 0 *************\n");
- if (_stp_utt) utt_trace_startstop(_stp_utt, 0, &utt_seq);
+ dbug_trans(1, "************** calling startstop 0 *************\n");
+ if (_stp_utt)
+ utt_trace_startstop(_stp_utt, 0, &utt_seq);
- kbug(DEBUG_TRANSPORT, "ctl_send STP_EXIT\n");
- /* tell staprun to exit (if it is still there) */
- _stp_ctl_send(STP_EXIT, &dont_rmmod, sizeof(int));
- kbug(DEBUG_TRANSPORT, "done with ctl_send STP_EXIT\n");
+ dbug_trans(1, "ctl_send STP_EXIT\n");
+ if (send_exit)
+ _stp_ctl_send(STP_EXIT, NULL, 0);
+ dbug_trans(1, "done with ctl_send STP_EXIT\n");
}
}
@@ -153,7 +116,7 @@ static void _stp_cleanup_and_exit (int dont_rmmod)
*/
static void _stp_detach(void)
{
- kbug(DEBUG_TRANSPORT, "detach\n");
+ dbug_trans(1, "detach\n");
_stp_attached = 0;
_stp_pid = 0;
@@ -169,10 +132,10 @@ static void _stp_detach(void)
*/
static void _stp_attach(void)
{
- kbug(DEBUG_TRANSPORT, "attach\n");
+ dbug_trans(1, "attach\n");
_stp_attached = 1;
_stp_pid = current->pid;
- utt_set_overwrite(0);
+ utt_set_overwrite(0);
queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER);
}
@@ -180,10 +143,10 @@ static void _stp_attach(void)
* _stp_work_queue - periodically check for IO or exit
* This is run by a kernel thread and may sleep.
*/
-#ifdef DECLARE_DELAYED_WORK
-static void _stp_work_queue (struct work_struct *data)
+#ifdef DECLARE_DELAYED_WORK
+static void _stp_work_queue(struct work_struct *data)
#else
-static void _stp_work_queue (void *data)
+static void _stp_work_queue(void *data)
#endif
{
int do_io = 0;
@@ -198,7 +161,7 @@ static void _stp_work_queue (void *data)
/* if exit flag is set AND we have finished with probe_start() */
if (unlikely(_stp_exit_flag))
- _stp_cleanup_and_exit(0);
+ _stp_cleanup_and_exit(1);
else if (likely(_stp_attached))
queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER);
}
@@ -211,19 +174,19 @@ static void _stp_work_queue (void *data)
*/
void _stp_transport_close()
{
- kbug(DEBUG_TRANSPORT, "%d: ************** transport_close *************\n", current->pid);
- _stp_cleanup_and_exit(1);
+ dbug_trans(1, "%d: ************** transport_close *************\n", current->pid);
+ _stp_cleanup_and_exit(0);
destroy_workqueue(_stp_wq);
_stp_unregister_ctl_channel();
- if (_stp_utt) utt_trace_remove(_stp_utt);
+ if (_stp_utt)
+ utt_trace_remove(_stp_utt);
_stp_free_modules();
_stp_kill_time();
- _stp_print_cleanup(); /* free print buffers */
+ _stp_print_cleanup(); /* free print buffers */
_stp_mem_debug_done();
- kbug(DEBUG_TRANSPORT, "---- CLOSED ----\n");
+ dbug_trans(1, "---- CLOSED ----\n");
}
-
static struct utt_trace *_stp_utt_open(void)
{
struct utt_trace_setup utts;
@@ -249,22 +212,26 @@ int _stp_transport_init(void)
{
int ret;
- kbug(DEBUG_TRANSPORT, "transport_init\n");
+ dbug_trans(1, "transport_init\n");
_stp_init_pid = current->pid;
_stp_uid = current->uid;
_stp_gid = current->gid;
#ifdef RELAY_GUEST
- /* Guest scripts use relay only for reporting warnings and errors */
- _stp_subbuf_size = 65536;
- _stp_nsubbufs = 2;
+ /* Guest scripts use relay only for reporting warnings and errors */
+ _stp_subbuf_size = 65536;
+ _stp_nsubbufs = 2;
#endif
if (_stp_bufsize) {
unsigned size = _stp_bufsize * 1024 * 1024;
- _stp_subbuf_size = ((size >> 2) + 1) * 65536;
+ _stp_subbuf_size = 65536;
+ while (size / _stp_subbuf_size > 64 &&
+ _stp_subbuf_size < 1024 * 1024) {
+ _stp_subbuf_size <<= 1;
+ }
_stp_nsubbufs = size / _stp_subbuf_size;
- kbug(DEBUG_TRANSPORT, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size);
+ dbug_trans(1, "Using %d subbufs of size %d\n", _stp_nsubbufs, _stp_subbuf_size);
}
/* initialize timer code */
@@ -286,41 +253,57 @@ int _stp_transport_init(void)
if (_stp_print_init() < 0)
goto err2;
+ /* start transport */
utt_trace_startstop(_stp_utt, 1, &utt_seq);
/* create workqueue of kernel threads */
_stp_wq = create_workqueue("systemtap");
if (!_stp_wq)
goto err3;
+
+ _stp_transport_state = 1;
+
+ dbug_trans(1, "calling init_kernel_symbols\n");
+ if (_stp_init_kernel_symbols() < 0)
+ goto err4;
+
+ dbug_trans(1, "calling init_modules\n");
+ if (_stp_init_modules() < 0)
+ goto err4;
+
return 0;
+err4:
+ errk("failed to initialize modules\n");
+ _stp_free_modules();
+ destroy_workqueue(_stp_wq);
err3:
_stp_print_cleanup();
err2:
_stp_unregister_ctl_channel();
err1:
- if (_stp_utt) utt_trace_remove(_stp_utt);
+ if (_stp_utt)
+ utt_trace_remove(_stp_utt);
err0:
_stp_kill_time();
return -1;
}
-
static inline void _stp_lock_inode(struct inode *inode)
{
#ifdef DEFINE_MUTEX
- mutex_lock(&inode->i_mutex);
+ mutex_lock(&inode->i_mutex);
#else
- down(&inode->i_sem);
+ down(&inode->i_sem);
#endif
}
static inline void _stp_unlock_inode(struct inode *inode)
{
#ifdef DEFINE_MUTEX
- mutex_unlock(&inode->i_mutex);
+ mutex_unlock(&inode->i_mutex);
#else
- up(&inode->i_sem);
+ up(&inode->i_sem);
#endif
}
@@ -358,7 +341,8 @@ static void _stp_unlock_debugfs(void)
/* utt.c and relayfs.c. Will not be necessary if utt is included */
/* in the kernel. */
-static struct dentry *_stp_get_root_dir(const char *name) {
+static struct dentry *_stp_get_root_dir(const char *name)
+{
struct file_system_type *fs;
struct dentry *root;
struct super_block *sb;
@@ -377,7 +361,6 @@ static struct dentry *_stp_get_root_dir(const char *name) {
errk("Couldn't lock transport directory.\n");
return NULL;
}
-
#ifdef STP_OLD_TRANSPORT
root = relayfs_create_dir(name, NULL);
#else
@@ -389,12 +372,11 @@ static struct dentry *_stp_get_root_dir(const char *name) {
_stp_lock_inode(sb->s_root->d_inode);
root = lookup_one_len(name, sb->s_root, strlen(name));
_stp_unlock_inode(sb->s_root->d_inode);
- kbug(DEBUG_TRANSPORT, "root=%p\n", root);
if (!IS_ERR(root))
dput(root);
else {
root = NULL;
- kbug(DEBUG_TRANSPORT, "Could not create or find transport directory.\n");
+ errk("Could not create or find transport directory.\n");
}
}
_stp_unlock_debugfs();
diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h
index 6dc00d2b..dc499961 100644
--- a/runtime/transport/transport.h
+++ b/runtime/transport/transport.h
@@ -7,21 +7,37 @@
#include "transport_msgs.h"
-void _stp_warn (const char *fmt, ...);
-
+/* The size of print buffers. This limits the maximum */
+/* amount of data a print can send. */
#define STP_BUFFER_SIZE 8192
+/* STP_CTL_BUFFER_SIZE is the maximum size of a message */
+/* exchanged on the control channel. */
+#ifdef STP_OLD_TRANSPORT
+/* Old transport sends print output on control channel */
+#define STP_CTL_BUFFER_SIZE STP_BUFFER_SIZE
+#else
+#define STP_CTL_BUFFER_SIZE 256
+#endif
+
/* how often the work queue wakes up and checks buffers */
#define STP_WORK_TIMER (HZ/100)
static unsigned _stp_nsubbufs = 8;
static unsigned _stp_subbuf_size = 65536*4;
+
+void _stp_warn (const char *fmt, ...);
extern void _stp_transport_close(void);
extern int _stp_print_init(void);
extern void _stp_print_cleanup(void);
static struct dentry *_stp_get_root_dir(const char *name);
static int _stp_lock_debugfs(void);
static void _stp_unlock_debugfs(void);
+static int _stp_ctl_send(int type, void *data, int len);
+static void _stp_attach(void);
+static void _stp_detach(void);
+void _stp_handle_start(struct _stp_msg_start *st);
+
int _stp_pid = 0;
uid_t _stp_uid = 0;
gid_t _stp_gid = 0;
diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h
index 55de2d4a..5f385565 100644
--- a/runtime/transport/transport_msgs.h
+++ b/runtime/transport/transport_msgs.h
@@ -23,8 +23,7 @@ enum
STP_EXIT,
STP_OOB_DATA,
STP_SYSTEM,
- STP_SYMBOLS,
- STP_MODULE,
+ STP_UNWIND,
STP_TRANSPORT,
STP_CONNECT,
STP_DISCONNECT,
@@ -36,18 +35,16 @@ enum
STP_SUBBUFS_CONSUMED,
STP_REALTIME_DATA,
#endif
-
STP_MAX_CMD
};
-#ifdef DEBUG_TRANSPORT
+#ifdef DEBUG_TRANS
static const char *_stp_command_name[] = {
"STP_START",
"STP_EXIT",
"STP_OOB_DATA",
"STP_SYSTEM",
- "STP_SYMBOLS",
- "STP_MODULE",
+ "STP_UNWIND",
"STP_TRANSPORT",
"STP_CONNECT",
"STP_DISCONNECT",
@@ -59,68 +56,34 @@ static const char *_stp_command_name[] = {
"STP_REALTIME_DATA",
#endif
};
-#endif /* DEBUG_TRANSPORT */
+#endif /* DEBUG_TRANS */
/* control channel messages */
-/* command to execute: sent to staprun */
+/* command to execute: module->stapio */
struct _stp_msg_cmd
{
char cmd[128];
};
-/* request for symbol data. sent to staprun */
-struct _stp_msg_symbol
+/* Unwind data. stapio->module */
+struct _stp_msg_unwind
{
- int32_t endian;
- int32_t ptr_size;
+ /* the module name, or "*" for all */
+ char name[STP_MODULE_NAME_LEN];
+ /* length of unwind data */
+ uint32_t unwind_len;
+ /* data ...*/
};
/* Request to start probes. */
-/* Sent from staprun. Then returned from module. */
+/* stapio->module->stapio */
struct _stp_msg_start
{
pid_t target;
int32_t res; // for reply: result of probe_start()
};
-struct _stp_symbol32
-{
- uint32_t addr;
- uint32_t symbol;
-};
-
-struct _stp_symbol64
-{
- uint64_t addr;
- uint64_t symbol;
-};
-
-struct _stp_msg_symbol_hdr
-{
- uint32_t num_syms;
- uint32_t sym_size;
- uint32_t unwind_size;
-};
-
-struct _stp_msg_module {
- /* the module name, or "" for kernel */
- char name[STP_MODULE_NAME_LEN];
-
- /* A pointer to the struct module */
- uint64_t module;
-
- /* the start of the module's text and data sections */
- uint64_t text;
- uint64_t data;
-
- /* how many sections this module has */
- uint32_t num_sections;
-
- /* length of unwind data */
- uint32_t unwind_len;
-};
-
#ifdef STP_OLD_TRANSPORT
/**** for compatibility with old relayfs ****/
struct _stp_buf_info
diff --git a/runtime/unwind.c b/runtime/unwind.c
new file mode 100644
index 00000000..aa270cad
--- /dev/null
+++ b/runtime/unwind.c
@@ -0,0 +1,964 @@
+/* -*- linux-c -*-
+ * kernel stack unwinding
+ * Copyright (C) 2008 Red Hat Inc.
+ *
+ * Based on old kernel code that is
+ * Copyright (C) 2002-2006 Novell, Inc.
+ * Jan Beulich <jbeulich@novell.com>
+ *
+ * This code is released under version 2 of the GNU GPL.
+ *
+ * This code currently does stack unwinding in the
+ * kernel and modules. It will need some extension to handle
+ * userspace unwinding.
+ */
+
+#include "unwind/unwind.h"
+
+#ifdef STP_USE_DWARF_UNWINDER
+
+struct eh_frame_hdr_table_entry {
+ unsigned long start, fde;
+};
+
+static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
+{
+ const struct eh_frame_hdr_table_entry *e1 = p1;
+ const struct eh_frame_hdr_table_entry *e2 = p2;
+ return (e1->start > e2->start) - (e1->start < e2->start);
+}
+
+static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
+{
+ struct eh_frame_hdr_table_entry *e1 = p1;
+ struct eh_frame_hdr_table_entry *e2 = p2;
+ unsigned long v;
+
+ v = e1->start;
+ e1->start = e2->start;
+ e2->start = v;
+ v = e1->fde;
+ e1->fde = e2->fde;
+ e2->fde = v;
+}
+
+/* Build a binary-searchable unwind header. Also do some
+ * validity checks. In the future we might use */
+/* .eh_frame_hdr if it is already present. */
+static void _stp_create_unwind_hdr(struct _stp_module *m)
+{
+ const u8 *ptr;
+ unsigned long tableSize, hdrSize, last;
+ unsigned n = 0;
+ const u32 *fde;
+ int bad_order = 0;
+ struct {
+ u8 version;
+ u8 eh_frame_ptr_enc;
+ u8 fde_count_enc;
+ u8 table_enc;
+ unsigned long eh_frame_ptr;
+ unsigned int fde_count;
+ struct eh_frame_hdr_table_entry table[];
+ } __attribute__ ((__packed__)) * header = NULL;
+
+ /* already did this or no data? */
+ if (m->unwind_hdr || m->unwind_data_len == 0)
+ return;
+
+ tableSize = m->unwind_data_len;
+ if (tableSize & (sizeof(*fde) - 1)) {
+ dbug_unwind(1, "tableSize=0x%x not a multiple of 0x%x\n", (int)tableSize, (int)sizeof(*fde));
+ goto bad;
+ }
+
+ /* count the FDEs */
+ for (fde = m->unwind_data;
+ tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
+ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
+ signed ptrType;
+ const u32 *cie;
+
+ /* check for extended length */
+ if ((*fde & 0xfffffff0) == 0xfffffff0) {
+ dbug_unwind(1, "Module %s has extended-length CIE or FDE.");
+ dbug_unwind(1, "This is not supported at this time.");
+ goto bad;
+ }
+ cie = cie_for_fde(fde, m);
+ if (cie == &not_fde)
+ continue; /* fde was a CIE. That's OK, just skip it. */
+ if (cie == NULL || cie == &bad_cie || (ptrType = fde_pointer_type(cie)) < 0)
+ goto bad;
+ /* we have a real FDE */
+ ptr = (const u8 *)(fde + 2);
+ if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType))
+ goto bad;
+ ++n;
+ }
+
+ if (tableSize || !n) {
+ dbug_unwind(1, "%s: tableSize=%ld, n=%d\n", m->name, tableSize, n);
+ goto bad;
+ }
+
+ hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int) + 2 * n * sizeof(unsigned long);
+ header = _stp_kmalloc(hdrSize);
+ if (header == NULL) {
+ header = _stp_vmalloc(hdrSize);
+ if (header == NULL)
+ return;
+ m->allocated.unwind_hdr = 1;
+ }
+
+ header->version = 1;
+ header->eh_frame_ptr_enc = DW_EH_PE_absptr;
+ header->fde_count_enc = DW_EH_PE_data4;
+ header->table_enc = DW_EH_PE_absptr;
+ _stp_put_unaligned((unsigned long)m->unwind_data, &header->eh_frame_ptr);
+
+ BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
+ % __alignof(typeof(header->fde_count)));
+ header->fde_count = n;
+
+ BUILD_BUG_ON(offsetof(typeof(*header), table) % __alignof(typeof(*header->table)));
+
+ n = 0;
+ last = 0;
+ tableSize = m->unwind_data_len;
+ for (fde = m->unwind_data; tableSize; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
+ const u32 *cie = cie_for_fde(fde, m);
+ if (cie == &not_fde)
+ continue;
+ if (cie == NULL || cie == &bad_cie)
+ goto bad;
+ /* we have a real FDE */
+ ptr = (const u8 *)(fde + 2);
+ header->table[n].start = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, fde_pointer_type(cie));
+ header->table[n].fde = (unsigned long)fde;
+ if (header->table[n].start < last)
+ bad_order++;
+ last = header->table[n].start;
+ ++n;
+ }
+ WARN_ON(n != header->fde_count);
+
+ /* Is sort ever necessary? */
+ if (bad_order)
+ _stp_sort(header->table, n, sizeof(*header->table), cmp_eh_frame_hdr_table_entries,
+ swap_eh_frame_hdr_table_entries);
+
+ m->unwind_hdr_len = hdrSize;
+ m->unwind_hdr = header;
+ return;
+
+ /* unwind data is not acceptable. free it and return */
+bad:
+ dbug_unwind(1, "unwind data for %s is unacceptable. Freeing.", m->name);
+ if (header) {
+ if (m->allocated.unwind_hdr) {
+ m->allocated.unwind_hdr = 0;
+ _stp_vfree(header);
+ } else
+ _stp_kfree(header);
+ }
+ if (m->unwind_data) {
+ if (m->allocated.unwind_data)
+ _stp_vfree(m->unwind_data);
+ else
+ _stp_kfree(m->unwind_data);
+ m->unwind_data = NULL;
+ m->unwind_data_len = 0;
+ }
+ return;
+}
+
+static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
+{
+ const u8 *cur = *pcur;
+ uleb128_t value = 0;
+ unsigned shift;
+
+ for (shift = 0; cur < end; shift += 7) {
+ if (shift + 7 > 8 * sizeof(value)
+ && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
+ cur = end + 1;
+ break;
+ }
+ value |= (uleb128_t)(*cur & 0x7f) << shift;
+ if (!(*cur++ & 0x80))
+ break;
+ }
+ *pcur = cur;
+
+ return value;
+}
+
+static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
+{
+ const u8 *cur = *pcur;
+ sleb128_t value = 0;
+ unsigned shift;
+
+ for (shift = 0; cur < end; shift += 7) {
+ if (shift + 7 > 8 * sizeof(value)
+ && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
+ cur = end + 1;
+ break;
+ }
+ value |= (sleb128_t)(*cur & 0x7f) << shift;
+ if (!(*cur & 0x80)) {
+ value |= -(*cur++ & 0x40) << shift;
+ break;
+ }
+ }
+ *pcur = cur;
+
+ return value;
+}
+
+/* given an FDE, find its CIE */
+static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *m)
+{
+ const u32 *cie;
+
+ /* check that length is proper */
+ if (!*fde || (*fde & (sizeof(*fde) - 1)))
+ return &bad_cie;
+
+ /* CIE id for eh_frame is 0, otherwise 0xffffffff */
+ if (m->unwind_is_ehframe && fde[1] == 0)
+ return &not_fde;
+ else if (fde[1] == 0xffffffff)
+ return &not_fde;
+
+ /* OK, must be an FDE. Now find its CIE. */
+
+ /* CIE_pointer must be a proper offset */
+ if ((fde[1] & (sizeof(*fde) - 1)) || fde[1] > (unsigned long)(fde + 1) - (unsigned long)m->unwind_data) {
+ dbug_unwind(1, "fde[1]=%lx fde+1=%lx, unwind_data=%lx %lx\n",
+ (unsigned long)fde[1], (unsigned long)(fde + 1),
+ (unsigned long)m->unwind_data, (unsigned long)(fde + 1) - (unsigned long)m->unwind_data);
+ return NULL; /* this is not a valid FDE */
+ }
+
+ /* cie pointer field is different in eh_frame vs debug_frame */
+ if (m->unwind_is_ehframe)
+ cie = fde + 1 - fde[1] / sizeof(*fde);
+ else
+ cie = m->unwind_data + fde[1];
+
+ if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
+ || (*cie & (sizeof(*cie) - 1))
+ || (cie[1] != 0xffffffff && cie[1] != 0)) {
+ dbug_unwind(1, "cie is not valid %lx %x %x %x\n", cie, *cie, fde[1], cie[1]);
+ return NULL; /* this is not a (valid) CIE */
+ }
+
+ return cie;
+}
+
+/* read an encoded pointer */
+static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrType)
+{
+ unsigned long value = 0;
+ union {
+ const u8 *p8;
+ const u16 *p16u;
+ const s16 *p16s;
+ const u32 *p32u;
+ const s32 *p32s;
+ const unsigned long *pul;
+ } ptr;
+
+ if (ptrType < 0 || ptrType == DW_EH_PE_omit)
+ return 0;
+
+ ptr.p8 = *pLoc;
+ switch (ptrType & DW_EH_PE_FORM) {
+ case DW_EH_PE_data2:
+ if (end < (const void *)(ptr.p16u + 1))
+ return 0;
+ if (ptrType & DW_EH_PE_signed)
+ value = _stp_get_unaligned(ptr.p16s++);
+ else
+ value = _stp_get_unaligned(ptr.p16u++);
+ break;
+ case DW_EH_PE_data4:
+#ifdef CONFIG_64BIT
+ if (end < (const void *)(ptr.p32u + 1))
+ return 0;
+ if (ptrType & DW_EH_PE_signed)
+ value = _stp_get_unaligned(ptr.p32s++);
+ else
+ value = _stp_get_unaligned(ptr.p32u++);
+ break;
+ case DW_EH_PE_data8:
+ BUILD_BUG_ON(sizeof(u64) != sizeof(value));
+#else
+ BUILD_BUG_ON(sizeof(u32) != sizeof(value));
+#endif
+ case DW_EH_PE_absptr:
+ if (end < (const void *)(ptr.pul + 1))
+ return 0;
+ value = _stp_get_unaligned(ptr.pul++);
+ break;
+ case DW_EH_PE_leb128:
+ BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
+ value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end)
+ : get_uleb128(&ptr.p8, end);
+ if ((const void *)ptr.p8 > end)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ switch (ptrType & DW_EH_PE_ADJUST) {
+ case DW_EH_PE_absptr:
+ break;
+ case DW_EH_PE_pcrel:
+ value += (unsigned long)*pLoc;
+ break;
+ default:
+ return 0;
+ }
+ if ((ptrType & DW_EH_PE_indirect)
+ && _stp_read_address(value, (unsigned long *)value, KERNEL_DS))
+ return 0;
+ *pLoc = ptr.p8;
+
+ return value;
+}
+
+static signed fde_pointer_type(const u32 *cie)
+{
+ const u8 *ptr = (const u8 *)(cie + 2);
+ unsigned version = *ptr;
+
+ if (version != 1)
+ return -1; /* unsupported */
+ if (*++ptr) {
+ const char *aug;
+ const u8 *end = (const u8 *)(cie + 1) + *cie;
+ uleb128_t len;
+
+ /* check if augmentation size is first (and thus present) */
+ if (*ptr != 'z')
+ return -1;
+ /* check if augmentation string is nul-terminated */
+ if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
+ return -1;
+ ++ptr; /* skip terminator */
+ get_uleb128(&ptr, end); /* skip code alignment */
+ get_sleb128(&ptr, end); /* skip data alignment */
+ /* skip return address column */
+ version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end);
+ len = get_uleb128(&ptr, end); /* augmentation length */
+ if (ptr + len < ptr || ptr + len > end)
+ return -1;
+ end = ptr + len;
+ while (*++aug) {
+ if (ptr >= end)
+ return -1;
+ switch (*aug) {
+ case 'L':
+ ++ptr;
+ break;
+ case 'P':{
+ signed ptrType = *ptr++;
+
+ if (!read_pointer(&ptr, end, ptrType) || ptr > end)
+ return -1;
+ }
+ break;
+ case 'R':
+ return *ptr;
+ default:
+ return -1;
+ }
+ }
+ }
+ return DW_EH_PE_absptr;
+}
+
+static int advance_loc(unsigned long delta, struct unwind_state *state)
+{
+ state->loc += delta * state->codeAlign;
+ dbug_unwind(1, "state->loc=%lx\n", state->loc);
+ return delta > 0;
+}
+
+static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value, struct unwind_state *state)
+{
+ dbug_unwind(1, "reg=%d, where=%d, value=%lx\n", reg, where, value);
+ if (reg < ARRAY_SIZE(state->regs)) {
+ state->regs[reg].where = where;
+ state->regs[reg].value = value;
+ }
+}
+
+static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, signed ptrType, struct unwind_state *state)
+{
+ union {
+ const u8 *p8;
+ const u16 *p16;
+ const u32 *p32;
+ } ptr;
+ int result = 1;
+
+ dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc);
+ if (start != state->cieStart) {
+ state->loc = state->org;
+ result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state);
+ if (targetLoc == 0 && state->label == NULL)
+ return result;
+ }
+
+ for (ptr.p8 = start; result && ptr.p8 < end;) {
+ switch (*ptr.p8 >> 6) {
+ uleb128_t value;
+ case 0:
+ switch (*ptr.p8++) {
+ case DW_CFA_nop:
+ dbug_unwind(1, "DW_CFA_nop\n");
+ break;
+ case DW_CFA_set_loc:
+ if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0)
+ result = 0;
+ dbug_unwind(1, "DW_CFA_set_loc %lx (result=%d)\n", state->loc, result);
+ break;
+ case DW_CFA_advance_loc1:
+ result = ptr.p8 < end && advance_loc(*ptr.p8++, state);
+ dbug_unwind(1, "DW_CFA_advance_loc1 %d\n", result);
+ break;
+ case DW_CFA_advance_loc2:
+ result = ptr.p8 <= end + 2 && advance_loc(*ptr.p16++, state);
+ dbug_unwind(1, "DW_CFA_advance_loc2 %d\n", result);
+ break;
+ case DW_CFA_advance_loc4:
+ result = ptr.p8 <= end + 4 && advance_loc(*ptr.p32++, state);
+ dbug_unwind(1, "DW_CFA_advance_loc4 %d\n", result);
+ break;
+ case DW_CFA_offset_extended:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "DW_CFA_offset_extended\n");
+ break;
+ case DW_CFA_val_offset:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Value, get_uleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "DW_CFA_val_offset\n");
+ break;
+ case DW_CFA_offset_extended_sf:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Memory, get_sleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "DW_CFA_offset_extended_sf\n");
+ break;
+ case DW_CFA_val_offset_sf:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Value, get_sleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "DW_CFA_val_offset_sf\n");
+ break;
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state);
+ dbug_unwind(1, "DW_CFA_undefined\n");
+ break;
+ case DW_CFA_register:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Register, get_uleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "DW_CFA_register\n");
+ break;
+ case DW_CFA_remember_state:
+ dbug_unwind(1, "DW_CFA_remember_state\n");
+ if (ptr.p8 == state->label) {
+ state->label = NULL;
+ return 1;
+ }
+ if (state->stackDepth >= MAX_STACK_DEPTH)
+ return 0;
+ state->stack[state->stackDepth++] = ptr.p8;
+ break;
+ case DW_CFA_restore_state:
+ dbug_unwind(1, "DW_CFA_restore_state\n");
+ if (state->stackDepth) {
+ const uleb128_t loc = state->loc;
+ const u8 *label = state->label;
+
+ state->label = state->stack[state->stackDepth - 1];
+ memcpy(&state->cfa, &badCFA, sizeof(state->cfa));
+ memset(state->regs, 0, sizeof(state->regs));
+ state->stackDepth = 0;
+ result = processCFI(start, end, 0, ptrType, state);
+ state->loc = loc;
+ state->label = label;
+ } else
+ return 0;
+ break;
+ case DW_CFA_def_cfa:
+ state->cfa.reg = get_uleb128(&ptr.p8, end);
+ dbug_unwind(1, "DW_CFA_def_cfa reg=%ld\n", state->cfa.reg);
+ /*nobreak */
+ case DW_CFA_def_cfa_offset:
+ state->cfa.offs = get_uleb128(&ptr.p8, end);
+ dbug_unwind(1, "DW_CFA_def_cfa_offset offs=%lx\n", state->cfa.offs);
+ break;
+ case DW_CFA_def_cfa_sf:
+ state->cfa.reg = get_uleb128(&ptr.p8, end);
+ dbug_unwind(1, "DW_CFA_def_cfa_sf reg=%ld\n", state->cfa.reg);
+ /*nobreak */
+ case DW_CFA_def_cfa_offset_sf:
+ state->cfa.offs = get_sleb128(&ptr.p8, end) * state->dataAlign;
+ dbug_unwind(1, "DW_CFA_def_cfa_offset_sf offs=%lx\n", state->cfa.offs);
+ break;
+ case DW_CFA_def_cfa_register:
+ state->cfa.reg = get_uleb128(&ptr.p8, end);
+ dbug_unwind(1, "DW_CFA_def_cfa_register reg=%ld\n", state->cfa.reg);
+ break;
+ /*todo case DW_CFA_def_cfa_expression: */
+ /*todo case DW_CFA_expression: */
+ /*todo case DW_CFA_val_expression: */
+ case DW_CFA_GNU_args_size:
+ get_uleb128(&ptr.p8, end);
+ dbug_unwind(1, "DW_CFA_GNU_args_size\n");
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ value = get_uleb128(&ptr.p8, end);
+ set_rule(value, Memory, (uleb128_t)0 - get_uleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "DW_CFA_GNU_negative_offset_extended\n");
+ break;
+ case DW_CFA_GNU_window_save:
+ default:
+ dbug_unwind(1, "unimplemented call frame instruction: 0x%x\n", *(ptr.p8 - 1));
+ result = 0;
+ break;
+ }
+ break;
+ case 1:
+ result = advance_loc(*ptr.p8++ & 0x3f, state);
+ dbug_unwind(1, "case 1\n");
+ break;
+ case 2:
+ value = *ptr.p8++ & 0x3f;
+ set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
+ dbug_unwind(1, "case 2\n");
+ break;
+ case 3:
+ set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
+ dbug_unwind(1, "case 3\n");
+ break;
+ }
+ dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc);
+ if (ptr.p8 > end)
+ result = 0;
+ if (result && targetLoc != 0 && targetLoc < state->loc)
+ return 1;
+ }
+ return result && ptr.p8 == end && (targetLoc == 0 || state->label == NULL);
+}
+
+/* If we previously created an unwind header, then use it now to binary search */
+/* for the FDE corresponding to pc. */
+
+static u32 *_stp_search_unwind_hdr(unsigned long pc, struct _stp_module *m)
+{
+ const u8 *ptr, *end, *hdr = m->unwind_hdr;
+ unsigned long startLoc;
+ u32 *fde = NULL;
+ unsigned num, tableSize, t2;
+
+ if (hdr == NULL || hdr[0] != 1)
+ return NULL;
+
+ dbug_unwind(1, "search for %lx", pc);
+
+ /* table_enc */
+ switch (hdr[3] & DW_EH_PE_FORM) {
+ case DW_EH_PE_absptr:
+ tableSize = sizeof(unsigned long);
+ break;
+ case DW_EH_PE_data2:
+ tableSize = 2;
+ break;
+ case DW_EH_PE_data4:
+ tableSize = 4;
+ break;
+ case DW_EH_PE_data8:
+ tableSize = 8;
+ break;
+ default:
+ dbug_unwind(1, "bad table encoding");
+ return NULL;
+ }
+ ptr = hdr + 4;
+ end = hdr + m->unwind_hdr_len;
+
+ if (read_pointer(&ptr, end, hdr[1]) != (unsigned long)m->unwind_data) {
+ dbug_unwind(1, "eh_frame_ptr not valid");
+ return NULL;
+ }
+
+ num = read_pointer(&ptr, end, hdr[2]);
+ if (num == 0 || num != (end - ptr) / (2 * tableSize) || (end - ptr) % (2 * tableSize)) {
+ dbug_unwind(1, "Bad num=%d end-ptr=%ld 2*tableSize=%d", num, end - ptr, 2 * tableSize);
+ return NULL;
+ }
+
+ do {
+ const u8 *cur = ptr + (num / 2) * (2 * tableSize);
+ startLoc = read_pointer(&cur, cur + tableSize, hdr[3]);
+ if (pc < startLoc)
+ num /= 2;
+ else {
+ ptr = cur - tableSize;
+ num = (num + 1) / 2;
+ }
+ } while (startLoc && num > 1);
+
+ if (num == 1 && (startLoc = read_pointer(&ptr, ptr + tableSize, hdr[3])) != 0 && pc >= startLoc)
+ fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]);
+
+ dbug_unwind(1, "returning fde=%lx startLoc=%lx", fde, startLoc);
+ return fde;
+}
+
+#ifdef DEBUG_UNWIND
+static const char *_stp_enc_hi_name[] = {
+ "",
+ "DW_EH_PE_pcrel",
+ "DW_EH_PE_textrel",
+ "DW_EH_PE_datarel",
+ "DW_EH_PE_funcrel",
+ "DW_EH_PE_aligned"
+};
+static const char *_stp_enc_lo_name[] = {
+ "DW_EH_PE_absptr",
+ "DW_EH_PE_uleb128",
+ "DW_EH_PE_udata2",
+ "DW_EH_PE_udata4",
+ "DW_EH_PE_udata8",
+ "DW_EH_PE_sleb128",
+ "DW_EH_PE_sdata2",
+ "DW_EH_PE_sdata4",
+ "DW_EH_PE_sdata8"
+};
+char *_stp_eh_enc_name(signed type)
+{
+ static char buf[64];
+ int hi, low;
+ if (type == DW_EH_PE_omit)
+ return "DW_EH_PE_omit";
+
+ hi = (type & DW_EH_PE_ADJUST) >> 4;
+ low = type & DW_EH_PE_FORM;
+ if (hi > 5 || low > 4 || (low == 0 && (type & DW_EH_PE_signed))) {
+ sprintf(buf, "ERROR:encoding=0x%x", type);
+ return buf;
+ }
+
+ buf[0] = 0;
+ if (type & DW_EH_PE_indirect)
+ strlcpy(buf, "DW_EH_PE_indirect|", sizeof(buf));
+ if (hi)
+ strlcat(buf, _stp_enc_hi_name[hi], sizeof(buf));
+
+ if (type & DW_EH_PE_signed)
+ low += 4;
+ strlcat(buf, _stp_enc_lo_name[low], sizeof(buf));
+ return buf;
+}
+#endif /* DEBUG_UNWIND */
+
+/* Unwind to previous to frame. Returns 0 if successful, negative
+ * number in case of an error. A positive return means unwinding is finished;
+ * don't try to fallback to dumping addresses on the stack. */
+int unwind(struct unwind_frame_info *frame)
+{
+#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
+ const u32 *fde, *cie = NULL;
+ const u8 *ptr = NULL, *end = NULL;
+ unsigned long pc = UNW_PC(frame) - frame->call_frame;
+ unsigned long tableSize, startLoc = 0, endLoc = 0, cfa;
+ unsigned i;
+ signed ptrType = -1;
+ uleb128_t retAddrReg = 0;
+ struct _stp_module *m;
+ struct unwind_state state;
+
+ dbug_unwind(1, "pc=%lx, %lx", pc, UNW_PC(frame));
+
+ if (UNW_PC(frame) == 0)
+ return -EINVAL;
+
+ m = _stp_get_unwind_info(pc);
+ if (unlikely(m == NULL)) {
+ dbug_unwind(1, "No module found for pc=%lx", pc);
+ return -EINVAL;
+ }
+
+ if (unlikely(m->unwind_data_len == 0 || m->unwind_data_len & (sizeof(*fde) - 1))) {
+ dbug_unwind(1, "Module %s: unwind_data_len=%d", m->name, m->unwind_data_len);
+ goto err;
+ }
+
+ fde = _stp_search_unwind_hdr(pc, m);
+ dbug_unwind(1, "%s: fde=%lx\n", m->name, fde);
+
+ /* found the fde, now set startLoc and endLoc */
+ if (fde != NULL) {
+ cie = cie_for_fde(fde, m);
+ if (likely(cie != NULL && cie != &bad_cie && cie != &not_fde)) {
+ ptr = (const u8 *)(fde + 2);
+ ptrType = fde_pointer_type(cie);
+ startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType));
+ if (!(ptrType & DW_EH_PE_indirect))
+ ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
+ endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ if (pc > endLoc) {
+ dbug_unwind(1, "pc (%lx) > endLoc(%lx)\n", pc, endLoc);
+ goto done;
+ }
+ } else {
+ dbug_unwind(1, "fde found in header, but cie is bad!\n");
+ fde = NULL;
+ }
+ }
+
+ /* did not a good fde find with binary search, so do slow linear search */
+ if (fde == NULL) {
+ for (fde = m->unwind_data, tableSize = m->unwind_data_len; cie = NULL, tableSize > sizeof(*fde)
+ && tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
+ dbug_unwind(3, "fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize);
+ cie = cie_for_fde(fde, m);
+ if (cie == &bad_cie) {
+ cie = NULL;
+ break;
+ }
+ if (cie == NULL || cie == &not_fde || (ptrType = fde_pointer_type(cie)) < 0)
+ continue;
+
+ ptr = (const u8 *)(fde + 2);
+ startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ dbug_unwind(2, "startLoc=%lx, ptrType=%s", startLoc, _stp_eh_enc_name(ptrType));
+ if (!startLoc)
+ continue;
+ if (!(ptrType & DW_EH_PE_indirect))
+ ptrType &= DW_EH_PE_FORM | DW_EH_PE_signed;
+ endLoc = startLoc + read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
+ dbug_unwind(3, "endLoc=%lx\n", endLoc);
+ if (pc >= startLoc && pc < endLoc)
+ break;
+ }
+ }
+
+ dbug_unwind(1, "cie=%lx fde=%lx startLoc=%lx endLoc=%lx\n", cie, fde, startLoc, endLoc);
+ if (cie == NULL || fde == NULL)
+ goto err;
+
+ /* found the CIE and FDE */
+
+ memset(&state, 0, sizeof(state));
+ state.cieEnd = ptr; /* keep here temporarily */
+ ptr = (const u8 *)(cie + 2);
+ end = (const u8 *)(cie + 1) + *cie;
+ frame->call_frame = 1;
+ if ((state.version = *ptr) != 1) {
+ dbug_unwind(1, "CIE version number is %d. 1 is supported.\n", state.version);
+ goto err; /* unsupported version */
+ }
+ if (*++ptr) {
+ /* check if augmentation size is first (and thus present) */
+ if (*ptr == 'z') {
+ while (++ptr < end && *ptr) {
+ switch (*ptr) {
+ /* check for ignorable (or already handled)
+ * nul-terminated augmentation string */
+ case 'L':
+ case 'P':
+ case 'R':
+ continue;
+ case 'S':
+ dbug_unwind(1, "This is a signal frame\n");
+ frame->call_frame = 0;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ if (ptr >= end || *ptr) {
+ dbug_unwind(1, "Problem parsing the augmentation string.\n");
+ goto err;
+ }
+ }
+ ++ptr;
+
+ /* get code aligment factor */
+ state.codeAlign = get_uleb128(&ptr, end);
+ /* get data aligment factor */
+ state.dataAlign = get_sleb128(&ptr, end);
+ if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
+ goto err;;
+
+ retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
+
+ /* skip augmentation */
+ if (((const char *)(cie + 2))[1] == 'z') {
+ uleb128_t augSize = get_uleb128(&ptr, end);
+ ptr += augSize;
+ }
+ if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
+ || REG_INVALID(retAddrReg)
+ || reg_info[retAddrReg].width != sizeof(unsigned long))
+ goto err;
+
+ state.cieStart = ptr;
+ ptr = state.cieEnd;
+ state.cieEnd = end;
+ end = (const u8 *)(fde + 1) + *fde;
+
+ /* skip augmentation */
+ if (((const char *)(cie + 2))[1] == 'z') {
+ uleb128_t augSize = get_uleb128(&ptr, end);
+ if ((ptr += augSize) > end)
+ goto err;
+ }
+
+ state.org = startLoc;
+ memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
+ /* process instructions */
+ if (!processCFI(ptr, end, pc, ptrType, &state)
+ || state.loc > endLoc || state.regs[retAddrReg].where == Nowhere || state.cfa.reg >= ARRAY_SIZE(reg_info)
+ || reg_info[state.cfa.reg].width != sizeof(unsigned long)
+ || state.cfa.offs % sizeof(unsigned long))
+ goto err;
+
+ /* update frame */
+#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
+ if (frame->call_frame && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
+ frame->call_frame = 0;
+#endif
+ cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
+ startLoc = min((unsigned long)UNW_SP(frame), cfa);
+ endLoc = max((unsigned long)UNW_SP(frame), cfa);
+ dbug_unwind(1, "cfa=%lx startLoc=%lx, endLoc=%lx\n", cfa, startLoc, endLoc);
+ if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
+ startLoc = min(STACK_LIMIT(cfa), cfa);
+ endLoc = max(STACK_LIMIT(cfa), cfa);
+ dbug_unwind(1, "cfa startLoc=%p, endLoc=%p\n", (u64)startLoc, (u64)endLoc);
+ }
+#ifndef CONFIG_64BIT
+# define CASES CASE(8); CASE(16); CASE(32)
+#else
+# define CASES CASE(8); CASE(16); CASE(32); CASE(64)
+#endif
+ dbug_unwind(1, "cie=%lx fde=%lx\n", cie, fde);
+ for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
+ if (REG_INVALID(i)) {
+ if (state.regs[i].where == Nowhere)
+ continue;
+ dbug_unwind(2, "REG_INVALID %d\n", i);
+ goto err;
+ }
+ dbug_unwind(2, "register %d. where=%d\n", i, state.regs[i].where);
+ switch (state.regs[i].where) {
+ default:
+ break;
+ case Register:
+ if (state.regs[i].value >= ARRAY_SIZE(reg_info)
+ || REG_INVALID(state.regs[i].value)
+ || reg_info[i].width > reg_info[state.regs[i].value].width) {
+ dbug_unwind(2, "case Register bad\n");
+ goto err;
+ }
+ switch (reg_info[state.regs[i].value].width) {
+#define CASE(n) \
+ case sizeof(u##n): \
+ state.regs[i].value = FRAME_REG(state.regs[i].value, \
+ const u##n); \
+ break
+ CASES;
+#undef CASE
+ default:
+ dbug_unwind(2, "default\n");
+ goto err;
+ }
+ break;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
+ dbug_unwind(2, "register %d. invalid=%d\n", i, REG_INVALID(i));
+ if (REG_INVALID(i))
+ continue;
+ dbug_unwind(2, "register %d. where=%d\n", i, state.regs[i].where);
+ switch (state.regs[i].where) {
+ case Nowhere:
+ if (reg_info[i].width != sizeof(UNW_SP(frame))
+ || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
+ != &UNW_SP(frame))
+ continue;
+ UNW_SP(frame) = cfa;
+ break;
+ case Register:
+ switch (reg_info[i].width) {
+#define CASE(n) case sizeof(u##n): \
+ FRAME_REG(i, u##n) = state.regs[i].value; \
+ break
+ CASES;
+#undef CASE
+ default:
+ dbug_unwind(2, "default\n");
+ goto err;
+ }
+ break;
+ case Value:
+ if (reg_info[i].width != sizeof(unsigned long)) {
+ dbug_unwind(2, "Value\n");
+ goto err;
+ }
+ FRAME_REG(i, unsigned long) = cfa + state.regs[i].value * state.dataAlign;
+ break;
+ case Memory:{
+ unsigned long addr = cfa + state.regs[i].value * state.dataAlign;
+ dbug_unwind(2, "addr=%lx width=%d\n", addr, reg_info[i].width);
+ switch (reg_info[i].width) {
+#define CASE(n) case sizeof(u##n): \
+ if (unlikely(_stp_read_address(FRAME_REG(i, u##n), (u##n *)addr, KERNEL_DS))) \
+ goto copy_failed;\
+ dbug_unwind(1, "set register %d to %lx\n", i, (long)FRAME_REG(i,u##n));\
+ break
+ CASES;
+#undef CASE
+ default:
+ dbug_unwind(2, "default\n");
+ goto err;
+ }
+ }
+ break;
+ }
+ }
+ read_unlock(&m->lock);
+ dbug_unwind(1, "returning 0 (%lx)\n", UNW_PC(frame));
+ return 0;
+
+copy_failed:
+ dbug_unwind(1, "_stp_read_address failed to access memory\n");
+err:
+ read_unlock(&m->lock);
+ return -EIO;
+
+done:
+ /* PC was in a range convered by a module but no unwind info */
+ /* found for the specific PC. This seems to happen only for kretprobe */
+ /* trampolines and at the end of interrupt backtraces. */
+ read_unlock(&m->lock);
+ return 1;
+#undef CASES
+#undef FRAME_REG
+}
+
+
+#endif /* STP_USE_DWARF_UNWINDER */
diff --git a/runtime/unwind/i386.h b/runtime/unwind/i386.h
new file mode 100644
index 00000000..79e6ba73
--- /dev/null
+++ b/runtime/unwind/i386.h
@@ -0,0 +1,135 @@
+/* -*- linux-c -*-
+ *
+ * 32-bit x86 dwarf unwinder header file
+ * Copyright (C) 2008 Red Hat Inc.
+ * Copyright (C) 2002-2006 Novell, 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 _STP_I386_UNWIND_H
+#define _STP_I386_UNWIND_H
+
+#include <linux/sched.h>
+#include <asm/fixmap.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+/* these are simple for i386 */
+#define _stp_get_unaligned(ptr) (*(ptr))
+#define _stp_put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+struct unwind_frame_info
+{
+ struct pt_regs regs;
+ struct task_struct *task;
+ unsigned call_frame:1;
+};
+
+#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
+
+#ifdef STAPCONF_X86_UNIREGS
+
+#define UNW_PC(frame) (frame)->regs.ip
+#define UNW_SP(frame) (frame)->regs.sp
+
+#define UNW_REGISTER_INFO \
+ PTREGS_INFO(ax), \
+ PTREGS_INFO(cx), \
+ PTREGS_INFO(dx), \
+ PTREGS_INFO(bx), \
+ PTREGS_INFO(sp), \
+ PTREGS_INFO(bp), \
+ PTREGS_INFO(si), \
+ PTREGS_INFO(di), \
+ PTREGS_INFO(ip)
+
+#else /* !STAPCONF_X86_UNIREGS */
+
+#define UNW_PC(frame) (frame)->regs.eip
+#define UNW_SP(frame) (frame)->regs.esp
+
+#define UNW_REGISTER_INFO \
+ PTREGS_INFO(eax), \
+ PTREGS_INFO(ecx), \
+ PTREGS_INFO(edx), \
+ PTREGS_INFO(ebx), \
+ PTREGS_INFO(esp), \
+ PTREGS_INFO(ebp), \
+ PTREGS_INFO(esi), \
+ PTREGS_INFO(edi), \
+ PTREGS_INFO(eip)
+
+#endif /* STAPCONF_X86_UNIREGS */
+
+#define UNW_DEFAULT_RA(raItem, dataAlign) \
+ ((raItem).where == Memory && \
+ !((raItem).value * (dataAlign) + 4))
+
+static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
+ /*const*/ struct pt_regs *regs)
+{
+ if (user_mode_vm(regs))
+ info->regs = *regs;
+ else {
+#ifdef STAPCONF_X86_UNIREGS
+ memcpy(&info->regs, regs, offsetof(struct pt_regs, sp));
+ info->regs.sp = (unsigned long)&regs->sp;
+ info->regs.ss = __KERNEL_DS;
+#else
+ memcpy(&info->regs, regs, offsetof(struct pt_regs, esp));
+ info->regs.esp = (unsigned long)&regs->esp;
+ info->regs.xss = __KERNEL_DS;
+#endif
+
+ }
+ info->call_frame = 1;
+}
+
+static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
+{
+ memset(&info->regs, 0, sizeof(info->regs));
+#ifdef STAPCONF_X86_UNIREGS
+ info->regs.ip = info->task->thread.ip;
+ info->regs.cs = __KERNEL_CS;
+ __get_user(info->regs.bp, (long *)info->task->thread.sp);
+ info->regs.sp = info->task->thread.sp;
+ info->regs.ss = __KERNEL_DS;
+ info->regs.ds = __USER_DS;
+ info->regs.es = __USER_DS;
+#else
+ info->regs.eip = info->task->thread.eip;
+ info->regs.xcs = __KERNEL_CS;
+ __get_user(info->regs.ebp, (long *)info->task->thread.esp);
+ info->regs.esp = info->task->thread.esp;
+ info->regs.xss = __KERNEL_DS;
+ info->regs.xds = __USER_DS;
+ info->regs.xes = __USER_DS;
+#endif
+
+}
+
+
+static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
+{
+#if 0 /* This can only work when selector register and EFLAGS saves/restores
+ are properly annotated (and tracked in UNW_REGISTER_INFO). */
+ return user_mode_vm(&info->regs);
+#else
+#ifdef STAPCONF_X86_UNIREGS
+ return info->regs.ip < PAGE_OFFSET
+ || (info->regs.ip >= __fix_to_virt(FIX_VDSO)
+ && info->regs.ip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
+ || info->regs.sp < PAGE_OFFSET;
+#else
+ return info->regs.eip < PAGE_OFFSET
+ || (info->regs.eip >= __fix_to_virt(FIX_VDSO)
+ && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
+ || info->regs.esp < PAGE_OFFSET;
+#endif
+#endif
+}
+
+#endif /* _STP_I386_UNWIND_H */
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h
new file mode 100644
index 00000000..ae5e75d3
--- /dev/null
+++ b/runtime/unwind/unwind.h
@@ -0,0 +1,146 @@
+/* -*- linux-c -*-
+ *
+ * dwarf unwinder header file
+ * Copyright (C) 2008 Red Hat Inc.
+ * Copyright (C) 2002-2006 Novell, 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 _STP_UNWIND_H_
+#define _STP_UNWIND_H_
+
+#ifdef STP_USE_DWARF_UNWINDER
+
+#if defined (__x86_64__)
+#include "x86_64.h"
+#elif defined (__i386__)
+#include "i386.h"
+#else
+#error "Unsupported dwarf unwind architecture"
+#endif
+
+#define MAX_STACK_DEPTH 8
+
+#define EXTRA_INFO(f) { \
+ BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
+ % FIELD_SIZEOF(struct unwind_frame_info, f)) \
+ + offsetof(struct unwind_frame_info, f) \
+ / FIELD_SIZEOF(struct unwind_frame_info, f), \
+ FIELD_SIZEOF(struct unwind_frame_info, f) \
+ }
+#define PTREGS_INFO(f) EXTRA_INFO(regs.f)
+
+static const struct {
+ unsigned offs:BITS_PER_LONG / 2;
+ unsigned width:BITS_PER_LONG / 2;
+} reg_info[] = {
+ UNW_REGISTER_INFO
+};
+
+#undef PTREGS_INFO
+#undef EXTRA_INFO
+
+#ifndef REG_INVALID
+#define REG_INVALID(r) (reg_info[r].width == 0)
+#endif
+
+#define DW_CFA_nop 0x00
+#define DW_CFA_set_loc 0x01
+#define DW_CFA_advance_loc1 0x02
+#define DW_CFA_advance_loc2 0x03
+#define DW_CFA_advance_loc4 0x04
+#define DW_CFA_offset_extended 0x05
+#define DW_CFA_restore_extended 0x06
+#define DW_CFA_undefined 0x07
+#define DW_CFA_same_value 0x08
+#define DW_CFA_register 0x09
+#define DW_CFA_remember_state 0x0a
+#define DW_CFA_restore_state 0x0b
+#define DW_CFA_def_cfa 0x0c
+#define DW_CFA_def_cfa_register 0x0d
+#define DW_CFA_def_cfa_offset 0x0e
+#define DW_CFA_def_cfa_expression 0x0f
+#define DW_CFA_expression 0x10
+#define DW_CFA_offset_extended_sf 0x11
+#define DW_CFA_def_cfa_sf 0x12
+#define DW_CFA_def_cfa_offset_sf 0x13
+#define DW_CFA_val_offset 0x14
+#define DW_CFA_val_offset_sf 0x15
+#define DW_CFA_val_expression 0x16
+#define DW_CFA_lo_user 0x1c
+#define DW_CFA_GNU_window_save 0x2d
+#define DW_CFA_GNU_args_size 0x2e
+#define DW_CFA_GNU_negative_offset_extended 0x2f
+#define DW_CFA_hi_user 0x3f
+
+#define DW_EH_PE_absptr 0x00
+#define DW_EH_PE_leb128 0x01
+#define DW_EH_PE_data2 0x02
+#define DW_EH_PE_data4 0x03
+#define DW_EH_PE_data8 0x04
+#define DW_EH_PE_FORM 0x07 /* mask */
+#define DW_EH_PE_signed 0x08 /* signed versions of above have this bit set */
+
+#define DW_EH_PE_pcrel 0x10
+#define DW_EH_PE_textrel 0x20
+#define DW_EH_PE_datarel 0x30
+#define DW_EH_PE_funcrel 0x40
+#define DW_EH_PE_aligned 0x50
+#define DW_EH_PE_ADJUST 0x70 /* mask */
+#define DW_EH_PE_indirect 0x80
+#define DW_EH_PE_omit 0xff
+
+typedef unsigned long uleb128_t;
+typedef signed long sleb128_t;
+
+static struct unwind_table {
+ unsigned long pc; /* text */
+ unsigned long range; /* text_size */
+ const void *address; /* unwind_data */
+ unsigned long size; /* unwind_data_len */
+ const unsigned char *header; /* unwind_header */
+ unsigned long hdrsz;
+ struct unwind_table *link;
+ const char *name; /* module name */
+} root_table;
+
+struct unwind_item {
+ enum item_location {
+ Nowhere,
+ Memory,
+ Register,
+ Value
+ } where;
+ uleb128_t value;
+};
+
+struct unwind_state {
+ uleb128_t loc, org;
+ const u8 *cieStart, *cieEnd;
+ uleb128_t codeAlign;
+ sleb128_t dataAlign;
+ struct cfa {
+ uleb128_t reg, offs;
+ } cfa;
+ struct unwind_item regs[ARRAY_SIZE(reg_info)];
+ unsigned stackDepth:8;
+ unsigned version:8;
+ const u8 *label;
+ const u8 *stack[MAX_STACK_DEPTH];
+};
+
+static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
+static unsigned long read_pointer(const u8 **pLoc,
+ const void *end,
+ signed ptrType);
+static const u32 bad_cie, not_fde;
+static const u32 *cie_for_fde(const u32 *fde, const struct _stp_module *);
+static signed fde_pointer_type(const u32 *cie);
+
+
+#endif /* STP_USE_DWARF_UNWINDER */
+#endif /*_STP_UNWIND_H_*/
diff --git a/runtime/unwind/x86_64.h b/runtime/unwind/x86_64.h
new file mode 100644
index 00000000..5eb3a58f
--- /dev/null
+++ b/runtime/unwind/x86_64.h
@@ -0,0 +1,150 @@
+/* -*- linux-c -*-
+ *
+ * x86_64 dwarf unwinder header file
+ * Copyright (C) 2008 Red Hat Inc.
+ * Copyright (C) 2002-2006 Novell, 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 _STP_X86_64_UNWIND_H
+#define _STP_X86_64_UNWIND_H
+
+/*
+ * Copyright (C) 2002-2006 Novell, Inc.
+ * Jan Beulich <jbeulich@novell.com>
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/vsyscall.h>
+
+/* these are simple for x86_64 */
+#define _stp_get_unaligned(ptr) (*(ptr))
+#define _stp_put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+
+struct unwind_frame_info
+{
+ struct pt_regs regs;
+ struct task_struct *task;
+ unsigned call_frame:1;
+};
+
+#ifdef STAPCONF_X86_UNIREGS
+#define UNW_PC(frame) (frame)->regs.ip
+#define UNW_SP(frame) (frame)->regs.sp
+#else
+#define UNW_PC(frame) (frame)->regs.rip
+#define UNW_SP(frame) (frame)->regs.rsp
+#endif /* STAPCONF_X86_UNIREGS */
+
+#if 0 /* STP_USE_FRAME_POINTER */
+/* Frame pointers not implemented in x86_64 currently */
+#define UNW_FP(frame) (frame)->regs.rbp
+#define FRAME_RETADDR_OFFSET 8
+#define FRAME_LINK_OFFSET 0
+#define STACK_BOTTOM(tsk) (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1))
+#define STACK_TOP(tsk) ((tsk)->thread.rsp0)
+#endif
+
+/* Might need to account for the special exception and interrupt handling
+ stacks here, since normally
+ EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER,
+ but the construct is needed only for getting across the stack switch to
+ the interrupt stack - thus considering the IRQ stack itself is unnecessary,
+ and the overhead of comparing against all exception handling stacks seems
+ not desirable. */
+#define STACK_LIMIT(ptr) (((ptr) - 1) & ~(THREAD_SIZE - 1))
+
+#ifdef STAPCONF_X86_UNIREGS
+#define UNW_REGISTER_INFO \
+ PTREGS_INFO(ax), \
+ PTREGS_INFO(dx), \
+ PTREGS_INFO(cx), \
+ PTREGS_INFO(bx), \
+ PTREGS_INFO(si), \
+ PTREGS_INFO(di), \
+ PTREGS_INFO(bp), \
+ PTREGS_INFO(sp), \
+ PTREGS_INFO(r8), \
+ PTREGS_INFO(r9), \
+ PTREGS_INFO(r10), \
+ PTREGS_INFO(r11), \
+ PTREGS_INFO(r12), \
+ PTREGS_INFO(r13), \
+ PTREGS_INFO(r14), \
+ PTREGS_INFO(r15), \
+ PTREGS_INFO(ip)
+#else
+#define UNW_REGISTER_INFO \
+ PTREGS_INFO(rax), \
+ PTREGS_INFO(rdx), \
+ PTREGS_INFO(rcx), \
+ PTREGS_INFO(rbx), \
+ PTREGS_INFO(rsi), \
+ PTREGS_INFO(rdi), \
+ PTREGS_INFO(rbp), \
+ PTREGS_INFO(rsp), \
+ PTREGS_INFO(r8), \
+ PTREGS_INFO(r9), \
+ PTREGS_INFO(r10), \
+ PTREGS_INFO(r11), \
+ PTREGS_INFO(r12), \
+ PTREGS_INFO(r13), \
+ PTREGS_INFO(r14), \
+ PTREGS_INFO(r15), \
+ PTREGS_INFO(rip)
+#endif /* STAPCONF_X86_UNIREGS */
+
+#define UNW_DEFAULT_RA(raItem, dataAlign) \
+ ((raItem).where == Memory && \
+ !((raItem).value * (dataAlign) + 8))
+
+static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
+ /*const*/ struct pt_regs *regs)
+{
+ info->regs = *regs;
+ info->call_frame = 1;
+}
+
+static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
+{
+ extern const char thread_return[];
+
+ memset(&info->regs, 0, sizeof(info->regs));
+ info->regs.cs = __KERNEL_CS;
+ info->regs.ss = __KERNEL_DS;
+
+#ifdef STAPCONF_X86_UNIREGS
+ info->regs.ip = (unsigned long)thread_return;
+ __get_user(info->regs.bp, (unsigned long *)info->task->thread.sp);
+ info->regs.sp = info->task->thread.sp;
+#else
+ info->regs.rip = (unsigned long)thread_return;
+ __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp);
+ info->regs.rsp = info->task->thread.rsp;
+#endif
+}
+
+static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
+{
+#if 0 /* This can only work when selector register saves/restores
+ are properly annotated (and tracked in UNW_REGISTER_INFO). */
+ return user_mode(&info->regs);
+#else
+#ifdef STAPCONF_X86_UNIREGS
+ return (long)info->regs.ip >= 0
+ || (info->regs.ip >= VSYSCALL_START && info->regs.ip < VSYSCALL_END)
+ || (long)info->regs.sp >= 0;
+#else
+ return (long)info->regs.rip >= 0
+ || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END)
+ || (long)info->regs.rsp >= 0;
+#endif
+#endif
+}
+
+#endif /* _STP_X86_64_UNWIND_H */
diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c
index 0bf625a5..4ffcf72e 100644
--- a/runtime/vsprintf.c
+++ b/runtime/vsprintf.c
@@ -248,6 +248,11 @@ int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
++str;
}
}
+#ifdef __ia64__
+ if ((str + precision - 1) <= end)
+ memcpy(str, &num, precision); //to prevent unaligned access
+ str += precision;
+#else
switch(precision) {
case 1:
if(str <= end)
@@ -271,6 +276,7 @@ int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
str+=8;
break;
}
+#endif
while (len < field_width--) {
if (str <= end)
*str = '\0';
diff --git a/session.h b/session.h
index e44e5c98..646b9154 100644
--- a/session.h
+++ b/session.h
@@ -30,6 +30,8 @@ struct derived_probe;
struct be_derived_probe_group;
struct dwarf_derived_probe_group;
struct uprobe_derived_probe_group;
+struct utrace_derived_probe_group;
+struct task_finder_derived_probe_group;
struct timer_derived_probe_group;
struct profile_derived_probe_group;
struct mark_derived_probe_group;
@@ -88,6 +90,7 @@ struct systemtap_session
bool timing;
bool keep_tmpdir;
bool guru_mode;
+ bool listing_mode;
bool bulk_mode;
bool unoptimized;
bool merge;
@@ -140,6 +143,8 @@ struct systemtap_session
be_derived_probe_group* be_derived_probes;
dwarf_derived_probe_group* dwarf_derived_probes;
uprobe_derived_probe_group* uprobe_derived_probes;
+ utrace_derived_probe_group* utrace_derived_probes;
+ task_finder_derived_probe_group* task_finder_derived_probes;
timer_derived_probe_group* timer_derived_probes;
profile_derived_probe_group* profile_derived_probes;
mark_derived_probe_group* mark_derived_probes;
diff --git a/stap.1.in b/stap.1.in
index 1b9fe466..d4458850 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -45,6 +45,15 @@ stap \- systemtap script translator/driver
[
.I ARGUMENTS
]
+.br
+.B stap
+[
+.I OPTIONS
+]
+.BI \-l " PROBE"
+[
+.I ARGUMENTS
+]
.SH DESCRIPTION
@@ -154,6 +163,11 @@ Start the probes, run CMD, and exit when CMD finishes.
Sets target() to PID. This allows scripts to be written that filter on
a specific process.
.TP
+.BI \-l " PROBE"
+Instead of running a probe script, just list all available probe
+points matching the given pattern. The pattern may include wildcards
+and aliases.
+.TP
.B \-\-kelf
For names and addresses of functions to probe,
consult the symbol tables in the kernel and modules.
diff --git a/stapex.5.in b/stapex.5.in
index 86e1c87b..2c9ecb60 100644
--- a/stapex.5.in
+++ b/stapex.5.in
@@ -101,11 +101,9 @@ probe kernel.function("sys_mkdir") { println ("enter") }
probe kernel.function("sys_mkdir").return { println ("exit") }
.ESAMPLE
-To list the probeable functions in the kernel, use the last-pass
-option to the translator. That output needs to be filtered because
-each inlined function instance is listed separately.
+To list the probeable functions in the kernel, use the listings mode.
.SAMPLE
-% stap \-p2 \-e \[aq]probe kernel.function("*") {}\[aq] | sort | uniq
+% stap \-l \[aq]kernel.function("*")\[aq]
.ESAMPLE
.SH SEE ALSO
diff --git a/stapprobes.5.in b/stapprobes.5.in
index ce8ef52d..3633fd39 100644
--- a/stapprobes.5.in
+++ b/stapprobes.5.in
@@ -306,6 +306,46 @@ in that both use raw (unverified) virtual addresses and provide
no $variables. The target PID parameter must identify a running
process, and ADDRESS should identify a valid instruction address.
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).syscall
+process("PATH").syscall
+process(PID).syscall.return
+process("PATH").syscall.return
+.ESAMPLE
+.PP
+A
+.B .clone
+probe gets called when a thread described by PID or PATH creates a new
+thread.
+A
+.B .exec
+probe gets called when a thread described by PID or PATH returns from
+.IR exec() .
+A
+.B .death
+probe gets called when a thread described by PID or PATH dies.
+A
+.B .syscall
+probe gets called when a thread described by PID or PATH makes a
+system call. The system call number is available in the "$syscall"
+context variable.
+A
+.B .syscall.return
+probe gets called when a thread described by PID or PATH returns from a
+system call. The system call number is available in the "$syscall"
+context variable.
+.PP
+Note that
+.I PATH
+pathnames must be absolute.
.SS PROCFS
diff --git a/staprun.8.in b/staprun.8.in
index c1678f69..ca976a4a 100644
--- a/staprun.8.in
+++ b/staprun.8.in
@@ -57,7 +57,7 @@ be in percpu files FILE_x where 'x' is the cpu number.
.B \-b BUFFER_SIZE
The systemtap module will specify a buffer size.
Setting one here will override that value. The value should be
-an integer between 1 and 64 which be assumed to be the
+an integer between 1 and 4095 which be assumed to be the
buffer size in MB. That value will be per-cpu if bulk mode is used.
.TP
.B \-L
@@ -68,6 +68,11 @@ option.
.TP
.B \-A
Attach to loaded systemtap module.
+.TP
+.B \-d
+Delete a module. Only detached or unused modules
+the user has permission to access will be deleted. Use "*"
+(quoted) to delete all unused modules.
.SH ARGUMENTS
.B MODULE
@@ -136,7 +141,7 @@ Members of the
.I stapusr
group can use
.I staprun
-to insert systemtap modules (or attach to existing systemtap modules) that
+to insert or remove systemtap modules (or attach to existing systemtap modules) that
are located in the /lib/modules/VERSION/systemtap directory.
.SH FILES
.TP
diff --git a/staptree.cxx b/staptree.cxx
index 39f5580e..02a6c8dc 100644
--- a/staptree.cxx
+++ b/staptree.cxx
@@ -801,6 +801,14 @@ void block::print (ostream& o) const
o << "}";
}
+block::block (statement* car, statement* cdr)
+{
+ statements.push_back(car);
+ statements.push_back(cdr);
+ this->tok = car->tok;
+}
+
+
void for_loop::print (ostream& o) const
{
diff --git a/staptree.h b/staptree.h
index 136472fd..9adbc822 100644
--- a/staptree.h
+++ b/staptree.h
@@ -470,6 +470,8 @@ struct block: public statement
std::vector<statement*> statements;
void print (std::ostream& o) const;
void visit (visitor* u);
+ block () {}
+ block (statement* car, statement* cdr);
};
@@ -605,7 +607,7 @@ std::ostream& operator << (std::ostream& o, const probe_point& k);
struct probe
{
std::vector<probe_point*> locations;
- block* body;
+ statement* body;
const token* tok;
std::vector<vardecl*> locals;
std::vector<vardecl*> unused_locals;
diff --git a/systemtap.spec.in b/systemtap.spec.in
index dd105790..e663b15a 100644
--- a/systemtap.spec.in
+++ b/systemtap.spec.in
@@ -1,19 +1,9 @@
-# Release number for rpm build. Stays at 1 for new PACKAGE_VERSION increases.
%define release 1
-# Version number of oldest elfutils release that works with systemtap.
-%define elfutils_version 0.127
-
-# Default options (suitable for fedora)
%define with_sqlite 1
%define with_docs 1
%define with_crash 0
%define with_bundled_elfutils 0
-
-# Enable these options by default for RHEL
-%if 0%{?rhel} >= 5
-%define with_crash 1
-%define with_bundled_elfutils 1
-%endif
+%define elfutils_version 0.127
Name: systemtap
Version: @VERSION@
diff --git a/tapset/ChangeLog b/tapset/ChangeLog
index dae8b452..70d75b83 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,24 @@
+2008-05-08 Ananth N Mavinakayanahalli <ananth@in.ibm.com>
+
+ PR 5231
+ * ioblock.stp (ioblock.end): Set bytes_done depending on kernel
+ version.
+
+2008-04-29 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6466
+ * tcp.stp (tcp_sockstate_str, tcp_sockopt_str): Initialize
+ number->string lookup tables here, instead of "probe begin(-1)"
+ block that can be elided/warned.
+
+2008-04-16 Wenji Huang <wenji.huang@oracle.com>
+
+ * scsi.stp (scsi.iodispatching): Correct for 2.6.25 kernel.
+
+2008-04-15 Martin Hunt <hunt@monkey>
+
+ * context.stp (print_backtrace, backtrace): Use MAXTRACE.
+
2008-03-21 Eugene Teo <eugeneteo@kernel.sg>
PR 5528
diff --git a/tapset/context.stp b/tapset/context.stp
index 4aa75158..dc560316 100644
--- a/tapset/context.stp
+++ b/tapset/context.stp
@@ -15,7 +15,7 @@ function print_regs () %{
function print_backtrace () %{
if (CONTEXT->regs) {
- _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi);
+ _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE);
} else {
_stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point);
}
@@ -23,7 +23,7 @@ function print_backtrace () %{
function backtrace:string () %{ /* pure */
if (CONTEXT->regs)
- _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi);
+ _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE);
else
strlcpy (THIS->__retvalue, "", MAXSTRINGLEN);
%}
diff --git a/tapset/i686/registers.stp b/tapset/i686/registers.stp
index 85aa7a7f..db532f7a 100644
--- a/tapset/i686/registers.stp
+++ b/tapset/i686/registers.stp
@@ -1,9 +1,70 @@
-/* Return the named register value as a signed value. */
-function register:long (name:string) %{ /* pure */
- THIS->__retvalue = (int64_t)
- _stp_get_reg32_by_name(THIS->name, CONTEXT->regs);
+global _reg_offsets, _stp_regs_registered
+
+function _stp_register_regs() {
+ /* Same order as pt_regs */
+ _reg_offsets["ebx"] = 0 _reg_offsets["bx"] = 0
+ _reg_offsets["ecx"] = 4 _reg_offsets["cx"] = 4
+ _reg_offsets["edx"] = 8 _reg_offsets["dx"] = 8
+ _reg_offsets["esi"] = 12 _reg_offsets["si"] = 12
+ _reg_offsets["edi"] = 16 _reg_offsets["di"] = 16
+ _reg_offsets["ebp"] = 20 _reg_offsets["bp"] = 20
+ _reg_offsets["eax"] = 24 _reg_offsets["ax"] = 24
+ _reg_offsets["xds"] = 28 _reg_offsets["ds"] = 28
+ _reg_offsets["xes"] = 32 _reg_offsets["es"] = 32
+ _reg_offsets["xfs"] = 36 _reg_offsets["fs"] = 36
+ _reg_offsets["orig_eax"] = 40 _reg_offsets["orig_ax"] = 40
+ _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
+
+ _stp_regs_registered = 1
+}
+
+function _stp_get_register_by_offset:long (offset:long) %{
+ long value;
+ memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value));
+ THIS->__retvalue = value;
+%}
+
+function _stp_probing_kernel:long () %{
+ THIS->__retvalue = !user_mode(CONTEXT->regs);
+%}
+
+/*
+ * esp and ss aren't saved on a breakpoint in kernel mode, so
+ * the pre-trap stack pointer is &regs->sp.
+ */
+function _stp_kernel_sp:long (sp_offset:long) %{
+ THIS->__retvalue = ((long) CONTEXT->regs) + THIS->sp_offset;
+%}
+
+/* Assume ss register hasn't changed since we took the trap. */
+function _stp_kernel_ss:long () %{
+ unsigned short ss;
+ asm volatile("movw %%ss, %0" : : "m" (ss));
+ THIS->__retvalue = ss;
%}
+/* Return the named register value as a signed value. */
+function register:long (name:string) {
+ if (!_stp_regs_registered)
+ _stp_register_regs()
+ offset = _reg_offsets[name]
+ if (offset == 0 && !(name in _reg_offsets)) {
+ error("Unknown register: " . name)
+ return 0
+ }
+ if (_stp_probing_kernel()) {
+ 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)
+}
+
/*
* Return the named register value as an unsigned value. Specifically,
* don't sign-extend the register value when promoting it to 64 bits.
diff --git a/tapset/ioblock.stp b/tapset/ioblock.stp
index 94781c04..14ce3f6b 100644
--- a/tapset/ioblock.stp
+++ b/tapset/ioblock.stp
@@ -167,7 +167,7 @@ probe ioblock.end = kernel.function("bio_endio")
devname = __bio_devname($bio)
ino = __bio_ino($bio)
- bytes_done = $bytes_done
+ bytes_done = %( kernel_vr < "2.6.24" %? $bytes_done %: $bio->bi_size %)
error = $error
sector = $bio->bi_sector
diff --git a/tapset/scsi.stp b/tapset/scsi.stp
index c9103cd6..7787b6d6 100644
--- a/tapset/scsi.stp
+++ b/tapset/scsi.stp
@@ -43,8 +43,13 @@ probe scsi.iodispatching
dev_id = $cmd->device->id
device_state = $cmd->device->sdev_state
data_direction = $cmd->sc_data_direction
+%( kernel_v >= "2.6.25" %?
+ request_buffer = $cmd->sdb->table->sgl
+ request_bufflen = $cmd->sdb->length
+%:
request_buffer = $cmd->request_buffer
request_bufflen = $cmd->request_bufflen
+%)
req_addr = $cmd->request
}
diff --git a/tapset/tcp.stp b/tapset/tcp.stp
index 3c3bd23b..7fa48000 100644
--- a/tapset/tcp.stp
+++ b/tapset/tcp.stp
@@ -71,7 +71,23 @@ function tcp_ts_get_info_state:long(sock:long)
CATCH_DEREF_FAULT();
%}
+global sockstate[13], sockstate_init_p
function tcp_sockstate_str:string (state:long) {
+ if (! sockstate_init_p) {
+ sockstate_init_p = 1
+ sockstate[1] = "TCP_ESTABLISHED"
+ sockstate[2] = "TCP_SYN_SENT"
+ sockstate[3] = "TCP_SYN_RECV"
+ sockstate[4] = "TCP_FIN_WAIT1"
+ sockstate[5] = "TCP_FIN_WAIT2"
+ sockstate[6] = "TCP_TIME_WAIT"
+ sockstate[7] = "TCP_CLOSE"
+ sockstate[8] = "TCP_CLOSE_WAIT"
+ sockstate[9] = "TCP_LAST_ACK"
+ sockstate[10] = "TCP_LISTEN"
+ sockstate[11] = "TCP_CLOSING"
+ sockstate[12] = "TCP_MAX_STATES"
+ }
return (state in sockstate ? sockstate[state] : "UNDEF")
}
@@ -105,7 +121,25 @@ function tcp_ts_get_info_rcv_mss:long(sock:long)
CATCH_DEREF_FAULT();
%}
+global sockopt[15], sockopt_init_p
function tcp_sockopt_str:string (optname:long) {
+ if (!sockopt_init_p) {
+ sockopt_init_p=1
+ sockopt[1] = "TCP_NODELAY"
+ sockopt[2] = "TCP_MAXSEG"
+ sockopt[3] = "TCP_CORK"
+ sockopt[4] = "TCP_KEEPIDLE"
+ sockopt[5] = "TCP_KEEPINTVL"
+ sockopt[6] = "TCP_KEEPCNT"
+ sockopt[7] = "TCP_SYNCNT"
+ sockopt[8] = "TCP_LINGER2"
+ sockopt[9] = "TCP_DEFER_ACCEPT"
+ sockopt[10] = "TCP_WINDOW_CLAMP"
+ sockopt[11] = "TCP_INFO"
+ sockopt[12] = "TCP_QUICKACK"
+ sockopt[13] = "TCP_CONGESTION"
+ sockopt[14] = "TCP_MD5SIG"
+ }
return (optname in sockopt ? sockopt[optname] : "UNDEF")
}
@@ -257,34 +291,3 @@ probe tcp.setsockopt.return = kernel.function("tcp_setsockopt").return {
ret = $return
}
-global sockopt[15], sockstate[13]
-
-probe begin(-1) {
- sockopt[1] = "TCP_NODELAY"
- sockopt[2] = "TCP_MAXSEG"
- sockopt[3] = "TCP_CORK"
- sockopt[4] = "TCP_KEEPIDLE"
- sockopt[5] = "TCP_KEEPINTVL"
- sockopt[6] = "TCP_KEEPCNT"
- sockopt[7] = "TCP_SYNCNT"
- sockopt[8] = "TCP_LINGER2"
- sockopt[9] = "TCP_DEFER_ACCEPT"
- sockopt[10] = "TCP_WINDOW_CLAMP"
- sockopt[11] = "TCP_INFO"
- sockopt[12] = "TCP_QUICKACK"
- sockopt[13] = "TCP_CONGESTION"
- sockopt[14] = "TCP_MD5SIG"
-
- sockstate[1] = "TCP_ESTABLISHED"
- sockstate[2] = "TCP_SYN_SENT"
- sockstate[3] = "TCP_SYN_RECV"
- sockstate[4] = "TCP_FIN_WAIT1"
- sockstate[5] = "TCP_FIN_WAIT2"
- sockstate[6] = "TCP_TIME_WAIT"
- sockstate[7] = "TCP_CLOSE"
- sockstate[8] = "TCP_CLOSE_WAIT"
- sockstate[9] = "TCP_LAST_ACK"
- sockstate[10] = "TCP_LISTEN"
- sockstate[11] = "TCP_CLOSING"
- sockstate[12] = "TCP_MAX_STATES"
-}
diff --git a/tapset/x86_64/registers.stp b/tapset/x86_64/registers.stp
index 45acddd1..a5aba55a 100644
--- a/tapset/x86_64/registers.stp
+++ b/tapset/x86_64/registers.stp
@@ -1,18 +1,93 @@
-/* Return the named register value as a signed value. */
-function register:long (name:string) %{ /* pure */
- int reg32 = 0;
- THIS->__retvalue = (int64_t) _stp_get_reg64_by_name(THIS->name,
- CONTEXT->regs, &reg32);
- if (reg32)
- THIS->__retvalue = _stp_sign_extend32(THIS->__retvalue);
+global _reg_offsets, _r32_offsets, _stp_regs_registered
+
+function _stp_register_regs() {
+ /* Same order as pt_regs */
+ _reg_offsets["r15"] = 0
+ _reg_offsets["r14"] = 8
+ _reg_offsets["r13"] = 16
+ _reg_offsets["r12"] = 24
+ _reg_offsets["rbp"] = 32 _reg_offsets["bp"] = 32
+ _reg_offsets["rbx"] = 40 _reg_offsets["bx"] = 40
+ _reg_offsets["r11"] = 48
+ _reg_offsets["r10"] = 56
+ _reg_offsets["r9"] = 64
+ _reg_offsets["r8"] = 72
+ _reg_offsets["rax"] = 80 _reg_offsets["ax"] = 80
+ _reg_offsets["rcx"] = 88 _reg_offsets["cx"] = 88
+ _reg_offsets["rdx"] = 96 _reg_offsets["dx"] = 96
+ _reg_offsets["rsi"] = 104 _reg_offsets["si"] = 104
+ _reg_offsets["rdi"] = 112 _reg_offsets["di"] = 112
+ _reg_offsets["orig_rax"] = 120 _reg_offsets["orig_ax"] = 120
+ _reg_offsets["rip"] = 128 _reg_offsets["ip"] = 128
+ _reg_offsets["xcs"] = 136 _reg_offsets["cs"] = 136
+ _reg_offsets["eflags"] = 144 _reg_offsets["flags"] = 144
+ _reg_offsets["rsp"] = 152 _reg_offsets["sp"] = 152
+ _reg_offsets["xss"] = 160 _reg_offsets["ss"] = 160
+
+ _r32_offsets["ebp"] = 32
+ _r32_offsets["ebx"] = 40
+ _r32_offsets["eax"] = 80
+ _r32_offsets["ecx"] = 88
+ _r32_offsets["edx"] = 96
+ _r32_offsets["esi"] = 104
+ _r32_offsets["edi"] = 112
+ _r32_offsets["orig_eax"] = 120
+ _r32_offsets["eip"] = 128
+ _r32_offsets["esp"] = 152
+
+ _stp_regs_registered = 1
+}
+
+function _stp_get_register_by_offset:long (offset:long) %{
+ long value;
+ memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value));
+ THIS->__retvalue = value;
%}
-/* Return the named register value as an unsigned value. */
-function u_register:long (name:string) %{
- THIS->__retvalue = (int64_t) _stp_get_reg64_by_name(THIS->name,
- CONTEXT->regs, NULL);
+/*
+ * _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) %{
+ THIS->__retvalue = __stp_sign_extend32(THIS->value);
%}
+function _stp_register:long (name:string, sign_extend:long) {
+ reg32 = 0
+ if (!_stp_regs_registered)
+ _stp_register_regs()
+ offset = _reg_offsets[name]
+ if (offset == 0 && !(name in _reg_offsets)) {
+ offset = _r32_offsets[name]
+ if (offset == 0 && !(name in _r32_offsets)) {
+ error("Unknown register: " . name)
+ return 0
+ }
+ reg32 = 1
+ }
+ value = _stp_get_register_by_offset(offset)
+ if (reg32) {
+ if (sign_extend)
+ value = _stp_sign_extend32(value)
+ else
+ value &= 0xffffffff
+ }
+ return value
+}
+
+/* Return the named register value as a signed value. */
+function register:long (name:string) {
+ return _stp_register(name, 1)
+}
+
+/*
+ * Return the named register value as an unsigned value. Specifically,
+ * don't sign-extend the register value when promoting it to 64 bits.
+ */
+function u_register:long (name:string) {
+ return _stp_register(name, 0)
+}
+
/*
* Return the value of function arg #argnum (1=first arg).
* If truncate=1, mask off the top 32 bits.
@@ -68,7 +143,7 @@ function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) %{
}
if (THIS->truncate || argsz == sizeof(int)) {
if (THIS->sign_extend)
- THIS->__retvalue = (int64_t) _stp_sign_extend32(val);
+ THIS->__retvalue = (int64_t) __stp_sign_extend32(val);
else
/* High bits may be garbage. */
THIS->__retvalue = (int64_t) (val & 0xffffffff);
diff --git a/tapsets.cxx b/tapsets.cxx
index 47bb20e2..9528066f 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -218,6 +218,16 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
o->newline() << "#ifdef STP_TIMING";
o->newline() << "c->statp = 0;";
o->newline() << "#endif";
+ // NB: The following would actually be incorrect.
+ // That's because cycles_sum/cycles_base values are supposed to survive
+ // between consecutive probes. Periodically (STP_OVERLOAD_INTERVAL
+ // cycles), the values will be reset.
+ /*
+ o->newline() << "#ifdef STP_OVERLOAD";
+ o->newline() << "c->cycles_sum = 0;";
+ o->newline() << "c->cycles_base = 0;";
+ o->newline() << "#endif";
+ */
}
@@ -869,7 +879,7 @@ struct dwflpp
void setup(bool kernel, bool debuginfo_needed = true)
{
// XXX: this is where the session -R parameter could come in
- static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug";
+ 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 ?
@@ -2742,6 +2752,14 @@ dwarf_query::build_blacklist()
blfn += "|raw_.*";
blfn += "|.*seq_.*lock.*";
+ // atomic functions
+ blfn += "|atomic_.*";
+ blfn += "|atomic64_.*";
+
+ // few other problematic cases
+ blfn += "|get_bh";
+ blfn += "|put_bh";
+
// Experimental
blfn += "|.*apic.*|.*APIC.*";
blfn += "|.*softirq.*";
@@ -2885,7 +2903,13 @@ dwarf_query::blacklisted_p(const string& funcname,
Dwarf_Addr addr)
{
if (section.substr(0, 6) == string(".init.") ||
- section.substr(0, 6) == string(".exit."))
+ section.substr(0, 6) == string(".exit.") ||
+ section.substr(0, 9) == string(".devinit.") ||
+ section.substr(0, 9) == string(".devexit.") ||
+ section.substr(0, 9) == string(".cpuinit.") ||
+ section.substr(0, 9) == string(".cpuexit.") ||
+ section.substr(0, 9) == string(".meminit.") ||
+ section.substr(0, 9) == string(".memexit."))
{
// NB: module .exit. routines could be probed in theory:
// if the exit handler in "struct module" is diverted,
@@ -3938,7 +3962,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
expr_statement* es = new expr_statement;
es->tok = e->tok;
es->value = a;
- add_probe->body->statements.push_back (es);
+ add_probe->body = new block(add_probe->body, es);
vardecl* vd = new vardecl;
vd->tok = e->tok;
@@ -3971,7 +3995,7 @@ dwarf_var_expanding_copy_visitor::visit_target_symbol (target_symbol *e)
es->tok = e->tok;
es->value = a;
- add_probe->body->statements.push_back (es);
+ add_probe->body = new block(add_probe->body, es);
// (4) Provide the '_dwarf_tvar_{name}_{num}_tmp' variable to
// our parent so it can be used as a substitute for the target
@@ -4144,12 +4168,12 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
if (!null_die(scope_die))
{
dwarf_var_expanding_copy_visitor v (q, scope_die, dwfl_addr);
- require <block*> (&v, &(this->body), this->body);
+ require <statement*> (&v, &(this->body), this->body);
// If during target-variable-expanding the probe, we added a new block
// of code, add it to the start of the probe.
if (v.add_block)
- this->body->statements.insert(this->body->statements.begin(), v.add_block);
+ this->body = new block(v.add_block, this->body);
// If when target-variable-expanding the probe, we added a new
// probe, add it in a new file to the list of files to be processed.
@@ -4896,6 +4920,643 @@ module_info::~module_info()
// ------------------------------------------------------------------------
+// task_finder derived 'probes': These don't really exist. The whole
+// purpose of the task_finder_derived_probe_group is to make sure that
+// stap_start_task_finder()/stap_stop_task_finder() get called only
+// once and in the right place.
+// ------------------------------------------------------------------------
+
+struct task_finder_derived_probe: public derived_probe
+{
+ // Dummy constructor for gcc 3.4 compatibility
+ task_finder_derived_probe (): derived_probe (0) { assert(0); }
+};
+
+
+struct task_finder_derived_probe_group: public generic_dpg<task_finder_derived_probe>
+{
+public:
+ static void create_session_group (systemtap_session& s);
+
+ void emit_module_decls (systemtap_session& ) { }
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+void
+task_finder_derived_probe_group::create_session_group (systemtap_session& s)
+{
+ if (! s.task_finder_derived_probes)
+ {
+ s.task_finder_derived_probes = new task_finder_derived_probe_group();
+
+ // Make sure we've got the stuff we need early in the output code.
+ embeddedcode *ec = new embeddedcode;
+ ec->tok = NULL;
+ ec->code = string("#if ! defined(CONFIG_UTRACE)\n")
+ + string("#error \"Need CONFIG_UTRACE!\"\n")
+ + string("#endif\n")
+ + string("#include <linux/utrace.h>\n")
+ + string("#include <linux/mount.h>\n")
+ + string("#include \"task_finder.c\"\n");
+
+ s.embeds.push_back(ec);
+ }
+}
+
+
+void
+task_finder_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ s.op->newline();
+ s.op->newline() << "/* ---- task finder ---- */";
+ s.op->newline() << "rc = stap_start_task_finder();";
+
+ s.op->newline() << "if (rc) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_stop_task_finder();";
+ s.op->newline(-1) << "}";
+}
+
+
+void
+task_finder_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ s.op->newline();
+ s.op->newline() << "/* ---- task finder ---- */";
+ s.op->newline() << "stap_stop_task_finder();";
+}
+
+
+// ------------------------------------------------------------------------
+// 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.
+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_NFLAGS
+};
+
+struct utrace_derived_probe: public derived_probe
+{
+ bool has_path;
+ string path;
+ int64_t pid;
+ enum utrace_derived_probe_flags flags;
+ bool target_symbol_seen;
+
+ utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
+ bool hp, string &pn, int64_t pd,
+ enum utrace_derived_probe_flags f);
+ void join_group (systemtap_session& s);
+};
+
+
+struct utrace_derived_probe_group: public generic_dpg<utrace_derived_probe>
+{
+private:
+ map<string, vector<utrace_derived_probe*> > probes_by_path;
+ typedef map<string, vector<utrace_derived_probe*> >::iterator p_b_path_iterator;
+ map<int64_t, vector<utrace_derived_probe*> > probes_by_pid;
+ typedef map<int64_t, vector<utrace_derived_probe*> >::iterator p_b_pid_iterator;
+ unsigned num_probes;
+ bool flags_seen[UDPF_NFLAGS];
+
+ void emit_probe_decl (systemtap_session& s, utrace_derived_probe *p);
+
+public:
+ utrace_derived_probe_group(): num_probes(0), flags_seen() { }
+
+ void enroll (utrace_derived_probe* probe);
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+struct utrace_var_expanding_copy_visitor: public var_expanding_copy_visitor
+{
+ utrace_var_expanding_copy_visitor(systemtap_session& s, const string& pn,
+ enum utrace_derived_probe_flags f):
+ sess (s), probe_name (pn), flags (f), target_symbol_seen (false) {}
+
+ systemtap_session& sess;
+ string probe_name;
+ enum utrace_derived_probe_flags flags;
+ bool target_symbol_seen;
+
+ void visit_target_symbol (target_symbol* e);
+};
+
+
+utrace_derived_probe::utrace_derived_probe (systemtap_session &s,
+ probe* p, probe_point* l,
+ bool hp, string &pn, int64_t pd,
+ enum utrace_derived_probe_flags f):
+ derived_probe(p, l), has_path(hp), path(pn), pid(pd), flags(f),
+ target_symbol_seen(false)
+{
+ // Make a local-variable-expanded copy of the probe body
+ utrace_var_expanding_copy_visitor v (s, name, flags);
+ require <statement*> (&v, &(this->body), base->body);
+ target_symbol_seen = v.target_symbol_seen;
+}
+
+
+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);
+}
+
+
+void
+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)
+ throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols",
+ e->tok);
+
+ if (e->base_name != "$syscall")
+ throw semantic_error ("invalid target symbol for utrace probe, $syscall expected",
+ e->tok);
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("utrace target variable '$syscall' may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("utrace target variable '$syscall' may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid use of utrace target variable '$syscall'",
+ e->tok);
+ break;
+ }
+ }
+
+ bool lvalue = is_active_lvalue(e);
+ if (lvalue)
+ throw semantic_error("utrace $syscall variable is read-only", e->tok);
+
+ // 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.
+ functioncall* n = new functioncall;
+ n->tok = e->tok;
+ n->function = fname;
+ n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
+
+ provide <functioncall*> (this, n);
+}
+
+
+struct utrace_builder: public derived_probe_builder
+{
+ utrace_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ std::map<std::string, literal *> const & parameters,
+ vector<derived_probe *> & finished_results)
+ {
+ string path;
+ int64_t pid;
+
+ bool has_path = get_param (parameters, TOK_PROCESS, path);
+ bool has_pid = get_param (parameters, TOK_PROCESS, pid);
+ 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_RETURN))
+ flags = UDPF_SYSCALL_EXIT;
+ else
+ flags = UDPF_SYSCALL_ENTRY;
+ }
+ else if (has_null_param (parameters, "clone"))
+ flags = UDPF_CLONE;
+ else if (has_null_param (parameters, "exec"))
+ flags = UDPF_EXEC;
+
+ // If we have a path, we need to validate it.
+ if (has_path)
+ {
+ string::size_type start_pos, end_pos;
+ string component;
+
+ // Make sure it starts with '/'.
+ if (path[0] != '/')
+ throw semantic_error ("process path must start with a '/'",
+ location->tok);
+
+ start_pos = 1; // get past the initial '/'
+ while ((end_pos = path.find('/', start_pos)) != string::npos)
+ {
+ component = path.substr(start_pos, end_pos - start_pos);
+ // Make sure it isn't empty.
+ if (component.size() == 0)
+ throw semantic_error ("process path component cannot be empty",
+ location->tok);
+ // Make sure it isn't relative.
+ else if (component == "." || component == "..")
+ throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
+
+ start_pos = end_pos + 1;
+ }
+ component = path.substr(start_pos);
+ // Make sure it doesn't end with '/'.
+ if (component.size() == 0)
+ throw semantic_error ("process path cannot end with a '/'", location->tok);
+ // Make sure it isn't relative.
+ else if (component == "." || component == "..")
+ throw semantic_error ("process path cannot be relative (and contain '.' or '..')", location->tok);
+ }
+
+ finished_results.push_back(new utrace_derived_probe(sess, base, location,
+ has_path, path, pid,
+ flags));
+ }
+};
+
+
+void
+utrace_derived_probe_group::enroll (utrace_derived_probe* p)
+{
+ if (p->has_path)
+ probes_by_path[p->path].push_back(p);
+ else
+ probes_by_pid[p->pid].push_back(p);
+ num_probes++;
+ flags_seen[p->flags] = true;
+
+ // XXX: multiple exec probes (for instance) for the same path (or
+ // pid) should all share a utrace report function, and have their
+ // handlers executed sequentially.
+}
+
+
+void
+utrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
+ utrace_derived_probe *p)
+{
+ s.op->newline() << "{";
+ s.op->line() << " .tgt={";
+
+ if (p->has_path)
+ {
+ s.op->line() << " .pathname=\"" << p->path << "\",";
+ s.op->line() << " .pid=0,";
+ }
+ else
+ {
+ s.op->line() << " .pathname=NULL,";
+ s.op->line() << " .pid=" << p->pid << ",";
+ }
+
+ s.op->line() << " .callback=&_stp_utrace_probe_cb,";
+ s.op->line() << " },";
+ s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
+ s.op->line() << " .ph=&" << p->name << ",";
+
+ // 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)),";
+ 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)),";
+ 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)),";
+ break;
+ case UDPF_SYSCALL_ENTRY:
+ 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)),";
+ break;
+ case UDPF_SYSCALL_EXIT:
+ 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)),";
+ break;
+ default:
+ throw semantic_error ("bad utrace probe flag");
+ break;
+ }
+ 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())
+ return;
+
+ s.op->newline();
+ s.op->newline() << "/* ---- utrace probes ---- */";
+ 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() << "struct utrace_engine_ops ops;";
+ s.op->newline() << "unsigned long flags;";
+ s.op->newline() << "int engine_attached;";
+ s.op->newline(-1) << "};";
+
+ // Output handler function for CLONE events
+ if (flags_seen[UDPF_CLONE])
+ {
+ 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->indent(1);
+ s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING");
+ s.op->newline() << "c->probe_point = p->pp;";
+
+ // call probe function
+ s.op->newline() << "(*p->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+
+ s.op->newline() << "return UTRACE_ACTION_RESUME;";
+ s.op->newline(-1) << "}";
+ }
+
+ // Output handler function for EXEC and DEATH events
+ if (flags_seen[UDPF_EXEC] || flags_seen[UDPF_DEATH])
+ {
+ s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
+ s.op->indent(1);
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING");
+ s.op->newline() << "c->probe_point = p->pp;";
+
+ // call probe function
+ s.op->newline() << "(*p->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+
+ s.op->newline() << "return;";
+ s.op->newline(-1) << "}";
+ }
+
+ // Output handler function for SYSCALL_ENTRY and SYSCALL_EXIT events
+ if (flags_seen[UDPF_SYSCALL_ENTRY] || flags_seen[UDPF_SYSCALL_EXIT])
+ {
+ 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);
+ s.op->newline() << "struct stap_utrace_probe *p = (struct stap_utrace_probe *)engine->data;";
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING");
+ s.op->newline() << "c->probe_point = p->pp;";
+ s.op->newline() << "c->regs = regs;";
+
+ // call probe function
+ s.op->newline() << "(*p->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+
+ s.op->newline() << "return UTRACE_ACTION_RESUME;";
+ s.op->newline(-1) << "}";
+ }
+
+ // 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->indent(1);
+ s.op->newline() << "int rc = 0;";
+ s.op->newline() << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);";
+ s.op->newline() << "struct utrace_attached_engine *engine;";
+
+ s.op->newline() << "if (register_p) {";
+ s.op->indent(1);
+
+ 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):";
+ 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->indent(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)):";
+ 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->indent(1);
+ s.op->newline() << "int error = -PTR_ERR(engine);";
+ s.op->newline() << "if (error != ENOENT) {";
+ 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(-1) << "}";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "else if (unlikely(engine == NULL)) {";
+ 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->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(-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.
+ s.op->newline() << "else {";
+ s.op->indent(1);
+ // For death probes, go ahead and call the probe directly.
+ if (flags_seen[UDPF_DEATH])
+ {
+ s.op->newline() << "if (p->flags == UTRACE_EVENT(DEATH)) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ }
+ s.op->newline(-1) << "}";
+ s.op->newline() << "return rc;";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "struct stap_utrace_probe stap_utrace_probes[] = {";
+ s.op->indent(1);
+
+ // Set up 'process(PATH)' probes
+ if (! probes_by_path.empty())
+ {
+ for (p_b_path_iterator it = probes_by_path.begin();
+ it != probes_by_path.end(); it++)
+ {
+ for (unsigned i = 0; i < it->second.size(); i++)
+ {
+ utrace_derived_probe *p = it->second[i];
+ emit_probe_decl(s, p);
+ }
+ }
+ }
+
+ // Set up 'process(PID)' probes
+ if (! probes_by_pid.empty())
+ {
+ for (p_b_pid_iterator it = probes_by_pid.begin();
+ it != probes_by_pid.end(); it++)
+ {
+ for (unsigned i = 0; i < it->second.size(); i++)
+ {
+ utrace_derived_probe *p = it->second[i];
+ emit_probe_decl(s, p);
+ }
+ }
+ }
+ s.op->newline(-1) << "};";
+}
+
+
+void
+utrace_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes_by_path.empty() && probes_by_pid.empty())
+ return;
+
+ s.op->newline();
+ s.op->newline() << "/* ---- utrace probes ---- */";
+
+ s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
+ s.op->newline(-1) << "}";
+
+ // rollback all utrace probes
+ s.op->newline() << "if (rc) {";
+ s.op->indent(1);
+ s.op->newline() << "for (j=i-1; j>=0; j--) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[j];";
+
+ s.op->newline() << "if (p->engine_attached) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_detach_ops(&p->ops);";
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+
+ s.op->newline(-1) << "}";
+}
+
+
+void
+utrace_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes_by_path.empty() && probes_by_pid.empty()) return;
+
+ s.op->newline();
+ s.op->newline() << "/* ---- utrace probes ---- */";
+ s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_utrace_probe *p = &stap_utrace_probes[i];";
+
+ s.op->newline() << "if (p->engine_attached) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_detach_ops(&p->ops);";
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+}
+
+
+// ------------------------------------------------------------------------
// user-space probes
// ------------------------------------------------------------------------
@@ -5359,6 +6020,7 @@ profile_derived_probe_group::emit_module_exit (systemtap_session& s)
}
+
// ------------------------------------------------------------------------
// procfs file derived probes
// ------------------------------------------------------------------------
@@ -5426,7 +6088,7 @@ procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
{
// Make a local-variable-expanded copy of the probe body
procfs_var_expanding_copy_visitor v (s, name, path, write);
- require <block*> (&v, &(this->body), base->body);
+ require <statement*> (&v, &(this->body), base->body);
target_symbol_seen = v.target_symbol_seen;
}
@@ -5837,6 +6499,7 @@ procfs_builder::build(systemtap_session & sess,
}
+
// ------------------------------------------------------------------------
// statically inserted macro-based derived probes
// ------------------------------------------------------------------------
@@ -6085,7 +6748,7 @@ mark_derived_probe::mark_derived_probe (systemtap_session &s,
// Now make a local-variable-expanded copy of the probe body
mark_var_expanding_copy_visitor v (sess, name, mark_args);
- require <block*> (&v, &(this->body), base->body);
+ require <statement*> (&v, &(this->body), base->body);
target_symbol_seen = v.target_symbol_seen;
if (sess.verbose > 2)
@@ -6237,7 +6900,19 @@ void
mark_derived_probe::join_group (systemtap_session& s)
{
if (! s.mark_derived_probes)
- s.mark_derived_probes = new mark_derived_probe_group ();
+ {
+ s.mark_derived_probes = new mark_derived_probe_group ();
+
+ // Make sure <linux/marker.h> is included early.
+ embeddedcode *ec = new embeddedcode;
+ ec->tok = NULL;
+ ec->code = string("#if ! defined(CONFIG_MARKERS)\n")
+ + string("#error \"Need CONFIG_MARKERS!\"\n")
+ + string("#endif\n")
+ + string("#include <linux/marker.h>\n");
+
+ s.embeds.push_back(ec);
+ }
s.mark_derived_probes->enroll (this);
}
@@ -6316,12 +6991,6 @@ mark_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "/* ---- marker probes ---- */";
- // Warn of misconfigured kernels
- s.op->newline() << "#if ! defined(CONFIG_MARKERS)";
- s.op->newline() << "#error \"Need CONFIG_MARKERS!\"";
- s.op->newline() << "#endif";
- s.op->newline();
-
s.op->newline() << "struct stap_marker_probe {";
s.op->newline(1) << "const char * const name;";
s.op->newline() << "const char * const format;";
@@ -6473,6 +7142,11 @@ mark_builder::build(systemtap_session & sess,
string::size_type notwhite = format.find_first_not_of(" \t");
format.erase(0, notwhite);
+ // If the format is empty, make sure we add back a space
+ // character, which is what MARK_NOARGS expands to.
+ if (format.length() == 0)
+ format = " ";
+
if (sess.verbose>3)
clog << "'" << name << "' '" << module << "' '" << format
<< "'" << endl;
@@ -6535,6 +7209,7 @@ mark_builder::build(systemtap_session & sess,
}
+
// ------------------------------------------------------------------------
// hrtimer derived probes
// ------------------------------------------------------------------------
@@ -6828,6 +7503,7 @@ timer_builder::register_patterns(match_node *root)
}
+
// ------------------------------------------------------------------------
// perfmon derived probes
// ------------------------------------------------------------------------
@@ -6970,7 +7646,7 @@ perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
// Now make a local-variable-expanded copy of the probe body
perfmon_var_expanding_copy_visitor v (sess, probes_allocated-1);
- require <block*> (&v, &(this->body), base->body);
+ require <statement*> (&v, &(this->body), base->body);
if (sess.verbose > 1)
clog << "perfmon-based probe" << endl;
@@ -7278,6 +7954,28 @@ register_standard_tapsets(systemtap_session & s)
->bind_num(TOK_STATEMENT)->bind(TOK_ABSOLUTE)->bind(TOK_RETURN)
->bind(new uprobe_builder ());
+ // utrace user-space probes
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("clone")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("clone")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("exec")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("exec")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("syscall")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("syscall")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("syscall")->bind(TOK_RETURN)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("syscall")->bind(TOK_RETURN)
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_str(TOK_PROCESS)->bind("death")
+ ->bind(new utrace_builder ());
+ s.pattern_root->bind_num(TOK_PROCESS)->bind("death")
+ ->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")
@@ -7312,6 +8010,12 @@ all_session_groups(systemtap_session& s)
DOONE(hrtimer);
DOONE(perfmon);
DOONE(procfs);
+
+ // Another "order is important" item. We want to make sure we
+ // "register" the dummy task_finder probe group after all probe
+ // groups that use the task_finder.
+ DOONE(utrace);
+ DOONE(task_finder);
#undef DOONE
return g;
}
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
new file mode 100644
index 00000000..34a4e8d0
--- /dev/null
+++ b/testsuite/.gitignore
@@ -0,0 +1,4 @@
+.systemtap
+site.exp
+systemtap.log
+systemtap.sum
diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog
index 95c1f117..c951971b 100644
--- a/testsuite/ChangeLog
+++ b/testsuite/ChangeLog
@@ -1,3 +1,66 @@
+2008-04-29 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 6466.
+ * semko/twelve.stp, semok/twenty.stp, systemtap.base/cache.exp,
+ systemtap.base/maxactive.exp, systemtap.base/warnings.exp,
+ transok/eight.stp: Adapt to new elision capabilities; add new
+ side-effects or -w warning-suppression flags.
+ * systemtap.pass1-4/buildok.exp: Remove two kfails.
+ * semok/optimize.stp: Test new elision.
+
+2008-04-24 Will Cohen <wcohen@redhat.com>
+
+ * systemtap.examples: examples moved into testsuite.
+
+2008-04-22 David Smith <dsmith@redhat.com>
+
+ * systemtap.base/utrace_p5.exp: Simplfied a little.
+
+ * systemtap.base/utrace_p5.exp: Added run-time utrace tests.
+
+2008-04-21 David Smith <dsmith@redhat.com>
+
+ * parseko/utrace01.stp: Renamed from semko/utrace02.stp (since it
+ received a parse error, not a semantic error).
+
+2008-04-21 Martin Hunt <hunt@redhat.com>
+
+ * systemtap.samples/args.exp: Remove obsolete "-d" option.
+
+2008-04-18 David Smith <dsmith@redhat.com>
+
+ * systemtap.base/utrace_p4.exp: Added exec probe test.
+
+ * buildok/utrace01.stp: Removed.
+ * buildok/utrace02.stp: Ditto.
+ * buildok/utrace03.stp: Ditto.
+ * systemtap.base/utrace_p4.exp: Rewrote buildok tests to check for
+ kernel utrace support.
+
+2008-04-17 David Smith <dsmith@redhat.com>
+
+ * buildok/utrace01.stp: New test.
+ * buildok/utrace02.stp: Ditto.
+ * buildok/utrace03.stp: Ditto.
+ * semko/utrace01.stp: Ditto.
+ * semko/utrace02.stp: Ditto.
+ * semko/utrace03.stp: Ditto.
+ * semko/utrace04.stp: Ditto.
+ * semko/utrace05.stp: Ditto.
+ * semko/utrace06.stp: Ditto.
+ * semko/utrace07.stp: Ditto.
+ * semko/utrace08.stp: Ditto.
+ * semko/utrace09.stp: Ditto.
+ * semko/utrace10.stp: Ditto.
+ * semko/utrace11.stp: Ditto.
+ * semko/utrace12.stp: Ditto.
+ * semko/utrace13.stp: Ditto.
+
+2008-04-10 Frank Ch. Eigler <fche@elastic.org>
+
+ PR 2949
+ * systemtap.base/cmd_parse.exp: Add "-l" listing test.
+
2008-04-04 Masami Hiramatsu <mhiramat@redhat.com>
PR 5528
diff --git a/testsuite/parseko/utrace01.stp b/testsuite/parseko/utrace01.stp
new file mode 100755
index 00000000..1cb4227f
--- /dev/null
+++ b/testsuite/parseko/utrace01.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# process NAME must be a string
+probe process(/bin/cat).death { }
diff --git a/testsuite/semko/twelve.stp b/testsuite/semko/twelve.stp
index ab71d579..c91eb743 100755
--- a/testsuite/semko/twelve.stp
+++ b/testsuite/semko/twelve.stp
@@ -1,6 +1,6 @@
#! stap -p2
probe end {
- for (a=0; "hello";) {}
- while ("goodbye") {}
+ for (a=0; "hello";) {println("hello")}
+ while ("goodbye") {println("world")}
}
diff --git a/testsuite/semko/utrace01.stp b/testsuite/semko/utrace01.stp
new file mode 100755
index 00000000..a4707008
--- /dev/null
+++ b/testsuite/semko/utrace01.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# missing process NAME|PID
+probe process.death { }
diff --git a/testsuite/semko/utrace03.stp b/testsuite/semko/utrace03.stp
new file mode 100755
index 00000000..c682410b
--- /dev/null
+++ b/testsuite/semko/utrace03.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# invalid probe type
+probe process("/bin/cat").death.return { }
diff --git a/testsuite/semko/utrace04.stp b/testsuite/semko/utrace04.stp
new file mode 100755
index 00000000..6345f9f6
--- /dev/null
+++ b/testsuite/semko/utrace04.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# death probes don't support target symbols
+probe process("/bin/cat").death.return { print($syscall) }
diff --git a/testsuite/semko/utrace05.stp b/testsuite/semko/utrace05.stp
new file mode 100755
index 00000000..e99fd22f
--- /dev/null
+++ b/testsuite/semko/utrace05.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# can't write to $syscall
+probe process("/bin/cat").syscall { $syscall = 1 }
diff --git a/testsuite/semko/utrace06.stp b/testsuite/semko/utrace06.stp
new file mode 100755
index 00000000..19e6043b
--- /dev/null
+++ b/testsuite/semko/utrace06.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# treat $syscall as a pointer
+probe process("/bin/cat").syscall { print($syscall->foo) }
diff --git a/testsuite/semko/utrace07.stp b/testsuite/semko/utrace07.stp
new file mode 100755
index 00000000..2a9405b3
--- /dev/null
+++ b/testsuite/semko/utrace07.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# treat $syscall as an array
+probe process("/bin/cat").syscall { print($syscall[0]) }
diff --git a/testsuite/semko/utrace08.stp b/testsuite/semko/utrace08.stp
new file mode 100755
index 00000000..a558a5be
--- /dev/null
+++ b/testsuite/semko/utrace08.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# process path must be absolute
+probe process("cat").death { }
diff --git a/testsuite/semko/utrace09.stp b/testsuite/semko/utrace09.stp
new file mode 100755
index 00000000..60c49cd2
--- /dev/null
+++ b/testsuite/semko/utrace09.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# process path must be absolute
+probe process("/foo/../bar").death { }
diff --git a/testsuite/semko/utrace10.stp b/testsuite/semko/utrace10.stp
new file mode 100755
index 00000000..b46baea9
--- /dev/null
+++ b/testsuite/semko/utrace10.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# path can't contain an empty component
+probe process("/foo//bar").death { }
diff --git a/testsuite/semko/utrace11.stp b/testsuite/semko/utrace11.stp
new file mode 100755
index 00000000..d78b602c
--- /dev/null
+++ b/testsuite/semko/utrace11.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# path can't end with '/'
+probe process("/foo/bar/").death { }
diff --git a/testsuite/semko/utrace12.stp b/testsuite/semko/utrace12.stp
new file mode 100755
index 00000000..478aa1d3
--- /dev/null
+++ b/testsuite/semko/utrace12.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# path can't end with '.'
+probe process("/foo/bar/.").death { }
diff --git a/testsuite/semko/utrace13.stp b/testsuite/semko/utrace13.stp
new file mode 100755
index 00000000..16cc0391
--- /dev/null
+++ b/testsuite/semko/utrace13.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# path can't end with '..'
+probe process("/foo/bar/..").death { }
diff --git a/testsuite/semok/optimize.stp b/testsuite/semok/optimize.stp
index bcf8ac04..a728bd66 100755
--- a/testsuite/semok/optimize.stp
+++ b/testsuite/semok/optimize.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -wp2
# We count on the optimizer to blow away these ridiculous
# expressions, since they have no effect on the output.
@@ -21,3 +21,19 @@ probe begin {
probe begin{for(i=1;i-=2;i++);}
probe begin{while(i+=2);}
probe begin{if(i=j);}
+
+global ii
+probe begin{for(ii=1;ii-=2;ii++);}
+probe begin{while(ii+=2);}
+probe begin{if(ii=j);}
+
+# bug #6466
+global goo
+
+probe begin { while (24) ; }
+probe begin { for (2<$i; zoo(333); poo) ; }
+probe begin { foreach (x in goo) goo[x]+1; }
+probe begin { foo = $bar; if (foo) {} }
+probe begin { { { { } } } }
+function useful () { return 1 }
+probe begin { println (useful()) } /* don't elide this one! */
diff --git a/testsuite/semok/twenty.stp b/testsuite/semok/twenty.stp
index 2e85c5e6..46dcefca 100755
--- a/testsuite/semok/twenty.stp
+++ b/testsuite/semok/twenty.stp
@@ -1,4 +1,4 @@
-#! stap -p2
+#! stap -wp2
probe kernel.function("*") {}
probe module("*").function("*") {}
diff --git a/testsuite/systemtap.base/cache.exp b/testsuite/systemtap.base/cache.exp
index eaa5ca82..26d7b0ef 100644
--- a/testsuite/systemtap.base/cache.exp
+++ b/testsuite/systemtap.base/cache.exp
@@ -74,8 +74,8 @@ if [info exists env(SYSTEMTAP_DIR)] {
set env(SYSTEMTAP_DIR) $local_systemtap_dir
# Set up the scripts we'll use.
-set basic_script1 "\"probe begin { }\""
-set basic_script2 "\"probe begin, end { }\""
+set basic_script1 "\"probe begin { println(1) }\""
+set basic_script2 "\"probe begin, end { println(2) }\""
set error_script "\"probe XbeginX { }\""
# Check basic functionality. The 1st compilation of a script won't
diff --git a/testsuite/systemtap.base/cmd_parse.exp b/testsuite/systemtap.base/cmd_parse.exp
index ff347a9d..cbce0455 100644
--- a/testsuite/systemtap.base/cmd_parse.exp
+++ b/testsuite/systemtap.base/cmd_parse.exp
@@ -75,3 +75,12 @@ expect {
eof {fail "cmd_parse7: unexpected EOF"}
}
wait
+
+spawn stap -l {vm.*}
+expect {
+ -timeout 60
+ -re "vm.*" {pass "cmd_parse8"}
+ timeout {fail "cmd_parse8: unexpected timeout"}
+ eof {fail "cmd_parse8: unexpected EOF"}
+}
+wait
diff --git a/testsuite/systemtap.base/maxactive.exp b/testsuite/systemtap.base/maxactive.exp
index ca95ac53..7c03a1bf 100644
--- a/testsuite/systemtap.base/maxactive.exp
+++ b/testsuite/systemtap.base/maxactive.exp
@@ -13,8 +13,9 @@ proc sleep_five_sec {} {
# Script1. For 5 seconds, probe the return of "sys_select" and
# "sys_read". See if we skip any probes.
set script1 {
+ global foo
probe kernel.function("sys_select").return,
- kernel.function("sys_read").return { }
+ kernel.function("sys_read").return { foo++ }
probe timer.ms(5000) { exit(); }
probe begin { log("systemtap starting probe"); log("systemtap ending probe");}
@@ -29,8 +30,9 @@ set skipped1 $skipped_probes
# "sys_read", with a limit of 1 probe active at a time. See if we
# skip any probes.
set script2 {
+ global foo
probe kernel.function("sys_select").return.maxactive(1),
- kernel.function("sys_read").return.maxactive(1) { }
+ kernel.function("sys_read").return.maxactive(1) { foo++ }
probe timer.ms(5000) { exit(); }
probe begin { log("systemtap starting probe"); log("systemtap ending probe");}
diff --git a/testsuite/systemtap.base/utrace_p4.exp b/testsuite/systemtap.base/utrace_p4.exp
new file mode 100644
index 00000000..eb6ea685
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_p4.exp
@@ -0,0 +1,106 @@
+# Utrace compile (pass 4) tests. We can't run these as
+# testsuite/buildok tests, since if the current kernel has no utrace
+# support, those will fail - but not because of a problem with
+# systemtap's utrace probes (but because of the lack of utrace). So,
+# this test script checks for the existence of utrace in the kernel.
+# If utrace exists in the kernel, it tries some compile tests. If
+# utrace doesn't exist in the kernel, marks the tests as 'untested'.
+
+# stap_compile TEST_NAME flags script args
+# - TEST_NAME is the name of the current test
+# - compile indicates whether the script is supposed to compile
+# - script is the script to compile
+# Additional arguments are passed to stap as-is.
+proc stap_compile { TEST_NAME compile script args } {
+ set cmd [concat {stap -v -p4 -e} $script $args]
+
+ verbose -log "running $cmd"
+ eval spawn $cmd
+ set compile_errors 0
+ expect {
+ -re {^Pass\ [1234]:[^\r]*\ in\ .*\ ms.\r\n} {exp_continue}
+ -re {^Pass\ [34]: using cached [^\r\n]+\r\n} {exp_continue}
+ # pass-4 output
+ -re {^/[^\r\n]+.ko\r\n} {exp_continue}
+ -re "parse error" { incr compile_errors 1; exp_continue}
+ -re "compilation failed" {incr compile_errors 1; exp_continue}
+ -re "semantic error:" {incr compile_errors 1; exp_continue}
+ }
+ catch close
+ wait
+
+ # If we've got compile errors and the script was supposed to
+ # compile, fail.
+ if {$compile_errors > 0} {
+ if {$compile == 1} {
+ fail "$TEST_NAME compilation failed"
+ } else {
+ pass "$TEST_NAME compilation failed correctly"
+ }
+ } else {
+ if {$compile == 1} {
+ pass "$TEST_NAME compilation succeeded"
+ } else {
+ fail "$TEST_NAME compilation succeeded unexpectedly"
+ }
+ }
+}
+
+# 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 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\") }"}
+
+# Try to find utrace_attach symbol in /proc/kallsyms
+set path "/proc/kallsyms"
+if {! [catch {exec grep -q utrace_attach $path} dummy]} {
+ set utrace_support_found 1
+}
+
+#
+# Do some utrace compile tests.
+#
+
+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
+}
+
+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
+}
+
+set TEST_NAME "UTRACE_P4_03"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} else {
+ # Try compiling a syscall script
+ stap_compile $TEST_NAME 1 $syscall_script
+}
+
+set TEST_NAME "UTRACE_P4_04"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} else {
+ # Try compiling a syscall return script
+ stap_compile $TEST_NAME 1 $syscall_return_script
+}
+
+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
+}
diff --git a/testsuite/systemtap.base/utrace_p5.exp b/testsuite/systemtap.base/utrace_p5.exp
new file mode 100644
index 00000000..cbb867d1
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_p5.exp
@@ -0,0 +1,140 @@
+# Utrace run (pass 5) tests.
+
+# Initialize variables
+set utrace_support_found 0
+set exepath "[pwd]/cat_[pid]"
+
+set death_script {
+ global death_probes_fired = 0
+ probe begin { printf("systemtap starting probe\n") }
+ probe process("%s").death { death_probes_fired++ }
+ probe end { printf("systemtap ending probe\n")
+ printf("deaths = %%d\n", death_probes_fired) }
+}
+set death_script_output "deaths = 1\r\n"
+
+set exec_script {
+ global exec_probes_fired = 0
+ probe begin { printf("systemtap starting probe\n") }
+ probe process("%s").exec { exec_probes_fired++ }
+ probe end { printf("systemtap ending probe\n")
+ printf("execs = %%d\n", exec_probes_fired) }
+}
+set exec_script_output "execs = 1\r\n"
+
+set syscall_script {
+ global syscall_probes_fired = 0
+ probe begin { printf("systemtap starting probe\n") }
+ probe process("%s").syscall { syscall_probes_fired++ }
+ probe end { printf("systemtap ending probe\n")
+ if (syscall_probes_fired > 0) {
+ printf("syscalls = %%d\n", syscall_probes_fired)
+ }
+ }
+}
+set syscall_script_output "syscalls = \\d+\r\n"
+
+set syscall_return_script {
+ global syscall_return_probes_fired = 0
+ probe begin { printf("systemtap starting probe\n") }
+ probe process("%s").syscall.return { syscall_return_probes_fired++ }
+ probe end { printf("systemtap ending probe\n")
+ if (syscall_return_probes_fired > 0) {
+ printf("syscall_returns = %%d\n", syscall_return_probes_fired)
+ }
+ }
+}
+set syscall_return_script_output "syscall_returns = \\d+\r\n"
+
+set clone_script {
+ global clone_probes_fired = 0
+ probe begin { printf("systemtap starting probe\n") }
+ probe process(%d).clone { clone_probes_fired++ }
+ probe end { printf("systemtap ending probe\n")
+ if (clone_probes_fired > 0) {
+ printf("clones = %%d\n", clone_probes_fired)
+ }
+ }
+}
+set clone_script_output "clones = \\d+\r\n"
+
+# Try to find utrace_attach symbol in /proc/kallsyms
+set path "/proc/kallsyms"
+if {! [catch {exec grep -q utrace_attach $path} dummy]} {
+ set utrace_support_found 1
+}
+
+# Set up our own copy of /bin/cat, to make testing for a particular
+# executable easy. We can't use 'ln' here, since we might be creating
+# a cross-device link. We can't use 'ln -s' here, since the kernel
+# resolves the symbolic link and reports that /bin/cat is being
+# exec'ed (instead of our local copy).
+if {[catch {exec cp /bin/cat $exepath} res]} {
+ fail "unable to copy /bin/cat: $res"
+ return
+}
+
+# "load" generation function for stap_run. It spawns our own copy of
+# /bin/cat, waits 5 seconds, then kills it.
+proc run_cat_5_sec {} {
+ global exepath
+
+ spawn $exepath
+ set exe_id $spawn_id
+ after 5000;
+ exec kill -INT -[exp_pid -i $exe_id]
+ 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 TEST_NAME "UTRACE_P5_02"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} 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 TEST_NAME "UTRACE_P5_03"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} elseif {![installtest_p]} {
+ untested "$TEST_NAME"
+} else {
+ set script [format $syscall_script $exepath]
+ stap_run $TEST_NAME run_cat_5_sec $syscall_script_output -e $script
+}
+
+set TEST_NAME "UTRACE_P5_04"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} elseif {![installtest_p]} {
+ untested "$TEST_NAME"
+} else {
+ set script [format $syscall_return_script $exepath]
+ stap_run $TEST_NAME run_cat_5_sec $syscall_return_script_output -e $script
+}
+
+set TEST_NAME "UTRACE_P5_05"
+if {$utrace_support_found == 0} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} 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
+}
+
+# Cleanup
+exec rm -f $exepath
diff --git a/testsuite/systemtap.base/warnings.exp b/testsuite/systemtap.base/warnings.exp
index 90409d18..025bde89 100644
--- a/testsuite/systemtap.base/warnings.exp
+++ b/testsuite/systemtap.base/warnings.exp
@@ -9,8 +9,8 @@ expect {
eof { }
}
wait
-if {$ok == 6} {
+if {$ok == 9} {
pass $test
} else {
- fail $test
+ fail "$test ($ok)"
}
diff --git a/testsuite/systemtap.context/backtrace.stp b/testsuite/systemtap.context/backtrace.stp
index c14d071c..ddd7d00a 100644
--- a/testsuite/systemtap.context/backtrace.stp
+++ b/testsuite/systemtap.context/backtrace.stp
@@ -1,10 +1,9 @@
-function print_all_trace_info(point:string) {
+function print_all_trace_info(point) {
printf("backtrace from %s:\n", pp())
print_backtrace()
- print("--------\n")
+ printf("--- %s ---\n", point)
bt = backtrace()
- printf("the %s stack is %s\n", point, bt)
- printf("--<%s>--\n", point)
+ printf("the stack is %s\n", bt)
print_stack(bt);
print("--------\n")
}
@@ -18,18 +17,20 @@ probe end {
}
global flag = 0
-probe module("systemtap_test_module2").function("yyy_func3").call {
- print_all_trace_info("call")
+
+probe module("systemtap_test_module2").function("yyy_func2") {
+ print_all_trace_info("yyy_func2")
flag ++
}
-probe module("systemtap_test_module2").function("yyy_func4").return {
- print_all_trace_info("return")
+
+probe module("systemtap_test_module2").function("yyy_func3") {
+ print_all_trace_info("yyy_func3")
flag ++
}
-probe timer.profile {
- if (cpu() == 0 && flag == 2 && probemod() != "systemtap_test_module2") {
- print_all_trace_info("profile")
- flag ++
- }
+
+probe module("systemtap_test_module2").function("yyy_func4") {
+ print_all_trace_info("yyy_func4")
+ flag ++
}
+
diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl
index f359cd41..6c8aee40 100644
--- a/testsuite/systemtap.context/backtrace.tcl
+++ b/testsuite/systemtap.context/backtrace.tcl
@@ -5,13 +5,7 @@ set m4 0
set m5 0
set m6 0
-if {[istarget ia64-*-*]} {
- set retexp {.*return\>--\r\n 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n}
-} else {
- set retexp {.*return\>--\r\n 0x[a-f0-9]+ : kretprobe_trampoline_holder[^\r\n]+\r\n}
-}
-
-spawn stap $srcdir/$subdir/backtrace.stp
+spawn stap -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp
#exp_internal 1
expect {
-timeout 240
@@ -20,69 +14,61 @@ expect {
exec echo 0 > /proc/stap_test_cmd
exp_continue
}
- -re {^backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func3@[^\r\n]+\r\n} {
+
+ #backtrace from yyy_func2
+ -re {^backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func2@[^\r\n]+\r\n} {
incr m1
expect {
-timeout 5
- -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m1 == 1} {incr m1}
- exp_continue
- }
-re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m1 == 2} {incr m1}
+ if {$m1 == 1} {incr m1}
exp_continue
}
-re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m1 == 3} {incr m1}
+ if {$m1 == 2} {incr m1}
}
}
exp_continue
}
- -re {.*---\r\nthe call stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
+ -re {.*--- yyy_func2 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
incr m2
expect {
-timeout 5
- -re {.*call\>--\r\n 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m2 == 1} {incr m2}
- exp_continue
- }
-re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m2 == 2} {incr m2}
+ if {$m2 == 1} {incr m2}
exp_continue
}
-re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m2 == 3} {incr m2}
+ if {$m2 == 2} {incr m2}
}
}
exp_continue
}
- -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func4@[^\r\n]+\r\n} {
+
+ #backtrace from yyy_func3
+ -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func3@[^\r\n]+\r\n} {
incr m3
expect {
-timeout 5
- -re {^Returning from: 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} {
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m3 == 1} {incr m3}
exp_continue
- }
- -re {^Returning to : 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m3 == 2} {incr m3}
- exp_continue
- }
+ }
-re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m3 == 3} {incr m3}
+ if {$m3 == 2} {incr m3}
exp_continue
}
-re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
- if {$m3 == 4} {incr m3}
+ if {$m3 == 3} {incr m3}
}
}
exp_continue
}
- -re {.*---\r\nthe return stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
+ -re {.*--- yyy_func3 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
incr m4
expect {
-timeout 5
- -re $retexp {
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m4 == 1} {incr m4}
exp_continue
}
@@ -96,58 +82,87 @@ expect {
}
exp_continue
}
- -re {.*backtrace from timer.profile:\r\n} {
+
+ #backtrace from yyy_func4
+ -re {.*backtrace from module\(\"systemtap_test_module2\"\)\.function\(\"yyy_func4@[^\r\n]+\r\n} {
incr m5
expect {
-timeout 5
- -re {^ 0x[a-f0-9]+[^\r\n]+\r\n} {
+ -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m5 == 1} {incr m5}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m5 == 2} {incr m5}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m5 == 3} {incr m5}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m5 == 4} {incr m5}
}
}
exp_continue
}
- -re {.*---\r\nthe profile stack is 0x[a-f0-9]+[^\r\n]+\r\n} {
+ -re {.*--- yyy_func4 ---\r\nthe stack is 0x[a-f0-9]+ [^\r\n]+\r\n} {
incr m6
expect {
-timeout 5
- -re {.*profile>--\r\n 0x[a-f0-9]+[^\r\n]+\r\n} {
+ -re {^ 0x[a-f0-9]+ : yyy_func4[^\[]+\[systemtap_test_module2\]\r\n} {
if {$m6 == 1} {incr m6}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func3[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m6 == 2} {incr m6}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func2[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m6 == 3} {incr m6}
+ exp_continue
+ }
+ -re {^ 0x[a-f0-9]+ : yyy_func1[^\[]+\[systemtap_test_module2\]\r\n} {
+ if {$m6 == 4} {incr m6}
}
}
+ exp_continue
}
- eof {fail "backtrace of yyy_func3, yyy_func4.return and timer.profile. unexpected EOF" }
+ eof {fail "backtrace of yyy_func[2-4]: unexpected EOF" }
}
exec kill -INT -[exp_pid]
-if {$m1 == 4} {
- pass "backtrace of yyy_func3"
+if {$m1 == 3} {
+ pass "backtrace of yyy_func2"
} else {
- fail "backtrace of yyy_func3 ($m1)"
+ fail "backtrace of yyy_func2 ($m1)"
}
-if {$m2 == 4} {
- pass "print_stack of yyy_func3"
+if {$m2 == 3} {
+ pass "print_stack of yyy_func2"
} else {
- fail "print_stack of yyy_func3 ($m2)"
+ fail "print_stack of yyy_func2 ($m2)"
}
-if {$m3 == 5} {
- pass "backtrace of yyy_func4.return"
+if {$m3 == 4} {
+ pass "backtrace of yyy_func3"
} else {
- fail "backtrace of yyy_func4.return ($m3)"
+ fail "backtrace of yyy_func3 ($m3)"
}
if {$m4 == 4} {
- pass "print_stack of yyy_func4.return"
+ pass "print_stack of yyy_func3"
} else {
- fail "print_stack of yyy_func4.return ($m4)"
+ fail "print_stack of yyy_func3 ($m4)"
}
-if {$m5 == 2} {
- pass "backtrace of timer.profile"
+if {$m5 == 5} {
+ pass "backtrace of yyy_func4"
} else {
- fail "backtrace of timer.profile ($m5)"
+ fail "backtrace of yyy_func4 ($m5)"
}
-if {$m6 == 2} {
- pass "print_stack of timer.profile"
+if {$m6 == 5} {
+ pass "print_stack of yyy_func4"
} else {
- fail "print_stack of timer.profile ($m6)"
+ fail "print_stack of yyy_func4 ($m6)"
}
+
+
close
wait
diff --git a/examples/ChangeLog b/testsuite/systemtap.examples/ChangeLog
index 78083901..6c5d014d 100644
--- a/examples/ChangeLog
+++ b/testsuite/systemtap.examples/ChangeLog
@@ -1,3 +1,23 @@
+2008-05-08 Mark Wielaard <mwielaard@redhat.com>
+
+ * futexes.meta (test_check,test_installcheck): Change futex.stp to
+ futexes.stp.
+
+2008-05-07 William Cohen <wcohen@redhat.com>
+
+ * futexes.meta, nettop.meta, pf2.meta: New.
+
+2008-05-07 William Cohen <wcohen@redhat.com>
+
+ * pf2.stp: Clean up output.
+
+2008-05-01 William Cohen <wcohen@redhat.com>
+
+ * helloworld.meta: New file.
+
+2008-04-27 William Cohen <wcohen@redhat.com>
+
+ * check.exp: New script to run tests on cataloged examples.
2008-03-09 Wenji Huang <wenji.huang@oracle.com>
diff --git a/examples/README b/testsuite/systemtap.examples/README
index 6718a55a..6718a55a 100644
--- a/examples/README
+++ b/testsuite/systemtap.examples/README
diff --git a/testsuite/systemtap.examples/check.exp b/testsuite/systemtap.examples/check.exp
new file mode 100644
index 00000000..2ac43050
--- /dev/null
+++ b/testsuite/systemtap.examples/check.exp
@@ -0,0 +1,75 @@
+# check.exp
+#
+# This script searches the systemtap.examples directory for .meta files
+# The .meta files contain information categorizing the script. The
+# .meta files are composed of lines of tags. Each tag is followed by a
+# value.
+
+#open the file and read in all the lines of data in FILE
+#return a string with the data
+proc get_meta_data { FILE } {
+ set meta_data ""
+
+ if [catch {open "$FILE" RDONLY} fl] {
+ puts "open $FILE failed: $err"
+ return ""
+ } else {
+ set meta_data [read -nonewline $fl]
+ close $fl
+ return "$meta_data"
+ }
+}
+
+#extract value for TAG from string META_DATA
+#if there is no matching tag return ""
+proc extract_tag { META_DATA TAG } {
+ set taglines ""
+ set value ""
+ set expr "^$TAG:\[^\$\]*"
+ regexp -line -all $expr $META_DATA taglines
+ set expr "$TAG:"
+ regsub -line $expr $taglines "" value
+ return $value
+}
+
+set curdir [pwd]
+
+set src_examples $srcdir/systemtap.examples
+set meta_files [lsort [exec find $src_examples -path "*.meta"]]
+foreach file $meta_files {
+ set dir [file dirname $file]
+ set test [regsub {.*/testsuite/} $file ""]
+
+ cd $dir
+
+ set meta_data [get_meta_data $file]
+ set test_check [extract_tag "$meta_data" "test_check"]
+ set test_installcheck [extract_tag "$meta_data" "test_installcheck"]
+ # Would like to run the tests (-p5), but pass fail logic too
+ # simple and fails for many examples
+ # FIXME following line prevents installcheck with "--tools_opts install"
+ set test_installcheck ""
+ if {[info procs installtest_p] != "" && [installtest_p]
+ && $test_installcheck != "" } then {
+ set command $test_installcheck
+ } else {
+ set command $test_check
+ }
+
+ #FIXME tcl says that single quotes not dealt with
+ if { $command != "" } then {
+ verbose -log "attempting command $command"
+ set res [catch {eval exec $command} value]
+ verbose -log "OUT $value"
+ verbose -log "RC $res"
+ if {$res != 0 } {
+ fail $test
+ } else {
+ pass $test
+ }
+ } else {
+ untested $test
+ }
+}
+
+cd $curdir
diff --git a/testsuite/systemtap.examples/futexes.meta b/testsuite/systemtap.examples/futexes.meta
new file mode 100644
index 00000000..0a34b2d8
--- /dev/null
+++ b/testsuite/systemtap.examples/futexes.meta
@@ -0,0 +1,13 @@
+title: System-Wide Futex Contention
+name: futex.stp
+version: 1.0
+author: anonymous
+keywords: syscall locking futex
+subsystem: locking
+status: production
+exit: user-controlled
+output: sorted-list on-exit
+scope: system-wide
+description: The script watches the futex syscall on the system. On exit the futexes address, the number of contentions, and the average time for each contention on the futex are printed from lowest pid number to highest.
+test_check: stap -p4 futexes.stp
+test_installcheck: stap futexes.stp -c "sleep 1"
diff --git a/examples/futexes.stp b/testsuite/systemtap.examples/futexes.stp
index 16c62937..16c62937 100755
--- a/examples/futexes.stp
+++ b/testsuite/systemtap.examples/futexes.stp
diff --git a/examples/futexes.txt b/testsuite/systemtap.examples/futexes.txt
index 51de4352..51de4352 100644
--- a/examples/futexes.txt
+++ b/testsuite/systemtap.examples/futexes.txt
diff --git a/testsuite/systemtap.examples/helloworld.meta b/testsuite/systemtap.examples/helloworld.meta
new file mode 100644
index 00000000..f56b7ca3
--- /dev/null
+++ b/testsuite/systemtap.examples/helloworld.meta
@@ -0,0 +1,13 @@
+title: SystemTap "Hello World" Program
+name: helloworld.stp
+version: 1.0
+keywords: simple
+author: anonymous
+subsystem: none
+status: production
+exit: fixed
+output: text
+scope: system-wide
+description: A basic "Hello World" program implemented in SystemTap script. It prints out "hello world" message and then immediately exits.
+test_check: stap -p4 helloworld.stp
+test_installcheck: stap helloworld.stp -c "sleep 1"
diff --git a/examples/helloworld.stp b/testsuite/systemtap.examples/helloworld.stp
index efe45b79..efe45b79 100755
--- a/examples/helloworld.stp
+++ b/testsuite/systemtap.examples/helloworld.stp
diff --git a/examples/iostat-scsi.stp b/testsuite/systemtap.examples/iostat-scsi.stp
index ef778e53..ef778e53 100755
--- a/examples/iostat-scsi.stp
+++ b/testsuite/systemtap.examples/iostat-scsi.stp
diff --git a/examples/iostat-scsi.txt b/testsuite/systemtap.examples/iostat-scsi.txt
index 8222f659..8222f659 100644
--- a/examples/iostat-scsi.txt
+++ b/testsuite/systemtap.examples/iostat-scsi.txt
diff --git a/examples/iotime.stp b/testsuite/systemtap.examples/iotime.stp
index a5b36449..a5b36449 100755
--- a/examples/iotime.stp
+++ b/testsuite/systemtap.examples/iotime.stp
diff --git a/testsuite/systemtap.examples/nettop.meta b/testsuite/systemtap.examples/nettop.meta
new file mode 100644
index 00000000..61d1c153
--- /dev/null
+++ b/testsuite/systemtap.examples/nettop.meta
@@ -0,0 +1,13 @@
+title: Periodic Listing of Processes Using Network Interfaces
+name: nettop.stp
+version: 1.0
+author: anonymous
+keywords: network traffic per-process
+subsystem: network
+status: production
+exit: user-controlled
+output: timed
+scope: system-wide
+description: Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.
+test_check: stap -p4 nettop.stp
+test_installcheck: stap nettop.stp -c "sleep 1"
diff --git a/examples/nettop.stp b/testsuite/systemtap.examples/nettop.stp
index 96db413a..96db413a 100755
--- a/examples/nettop.stp
+++ b/testsuite/systemtap.examples/nettop.stp
diff --git a/examples/nettop.txt b/testsuite/systemtap.examples/nettop.txt
index 2bfd4967..2bfd4967 100644
--- a/examples/nettop.txt
+++ b/testsuite/systemtap.examples/nettop.txt
diff --git a/testsuite/systemtap.examples/pf2.meta b/testsuite/systemtap.examples/pf2.meta
new file mode 100644
index 00000000..d0a534bd
--- /dev/null
+++ b/testsuite/systemtap.examples/pf2.meta
@@ -0,0 +1,13 @@
+title: Profile kernel functions
+name: pf2.stp
+version: 1.0
+author: anonymous
+keywords: profiling
+subsystem: kernel
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The pf2.stp script sets up time-based sampling. Every five seconds it prints out a sorted list with the top ten kernel functions with samples.
+test_check: stap -p4 pf2.stp
+test_installcheck: stap pf2.stp -c "sleep 1"
diff --git a/examples/pf2.stp b/testsuite/systemtap.examples/pf2.stp
index 96fdb7e7..a804c3ff 100755
--- a/examples/pf2.stp
+++ b/testsuite/systemtap.examples/pf2.stp
@@ -6,10 +6,10 @@ probe timer.profile {
fn = probefunc ()
if (fn != "") profile[fn] <<< 1
}
-probe timer.ms(4000) {
+probe timer.ms(5000) {
printf ("\n--- %d samples recorded:\n", @count(pcount))
foreach (f in profile- limit 10) {
- printf ("%s\t%d\n", f, @count(profile[f]))
+ printf ("%-30s\t%6d\n", f, @count(profile[f]))
}
delete profile
delete pcount
diff --git a/examples/pf2.txt b/testsuite/systemtap.examples/pf2.txt
index 0fafe17e..0fafe17e 100644
--- a/examples/pf2.txt
+++ b/testsuite/systemtap.examples/pf2.txt
diff --git a/examples/sig_by_pid.stp b/testsuite/systemtap.examples/sig_by_pid.stp
index 9c1493f5..9c1493f5 100755
--- a/examples/sig_by_pid.stp
+++ b/testsuite/systemtap.examples/sig_by_pid.stp
diff --git a/examples/sig_by_pid.txt b/testsuite/systemtap.examples/sig_by_pid.txt
index 927b4607..927b4607 100644
--- a/examples/sig_by_pid.txt
+++ b/testsuite/systemtap.examples/sig_by_pid.txt
diff --git a/examples/sig_by_proc.stp b/testsuite/systemtap.examples/sig_by_proc.stp
index ce845aed..ce845aed 100755
--- a/examples/sig_by_proc.stp
+++ b/testsuite/systemtap.examples/sig_by_proc.stp
diff --git a/examples/sig_by_proc.txt b/testsuite/systemtap.examples/sig_by_proc.txt
index d09da9fe..d09da9fe 100644
--- a/examples/sig_by_proc.txt
+++ b/testsuite/systemtap.examples/sig_by_proc.txt
diff --git a/examples/sigmon.stp b/testsuite/systemtap.examples/sigmon.stp
index 31d7822e..31d7822e 100755
--- a/examples/sigmon.stp
+++ b/testsuite/systemtap.examples/sigmon.stp
diff --git a/examples/sleeptime.stp b/testsuite/systemtap.examples/sleeptime.stp
index 252e50cc..252e50cc 100755
--- a/examples/sleeptime.stp
+++ b/testsuite/systemtap.examples/sleeptime.stp
diff --git a/examples/small_demos/ansi_colors.stp b/testsuite/systemtap.examples/small_demos/ansi_colors.stp
index 0d9d7c47..0d9d7c47 100755
--- a/examples/small_demos/ansi_colors.stp
+++ b/testsuite/systemtap.examples/small_demos/ansi_colors.stp
diff --git a/examples/small_demos/click.wav b/testsuite/systemtap.examples/small_demos/click.wav
index 8214b229..8214b229 100644
--- a/examples/small_demos/click.wav
+++ b/testsuite/systemtap.examples/small_demos/click.wav
Binary files differ
diff --git a/examples/small_demos/close.stp b/testsuite/systemtap.examples/small_demos/close.stp
index 7ba2a036..7ba2a036 100755
--- a/examples/small_demos/close.stp
+++ b/testsuite/systemtap.examples/small_demos/close.stp
diff --git a/examples/small_demos/demo_script.txt b/testsuite/systemtap.examples/small_demos/demo_script.txt
index f3166a49..f3166a49 100644
--- a/examples/small_demos/demo_script.txt
+++ b/testsuite/systemtap.examples/small_demos/demo_script.txt
diff --git a/examples/small_demos/fileopen.stp b/testsuite/systemtap.examples/small_demos/fileopen.stp
index c1298f9c..c1298f9c 100755
--- a/examples/small_demos/fileopen.stp
+++ b/testsuite/systemtap.examples/small_demos/fileopen.stp
diff --git a/examples/small_demos/key.stp b/testsuite/systemtap.examples/small_demos/key.stp
index 6d2d6c3f..6d2d6c3f 100755
--- a/examples/small_demos/key.stp
+++ b/testsuite/systemtap.examples/small_demos/key.stp
diff --git a/examples/small_demos/keyhack.stp b/testsuite/systemtap.examples/small_demos/keyhack.stp
index 3137baad..3137baad 100755
--- a/examples/small_demos/keyhack.stp
+++ b/testsuite/systemtap.examples/small_demos/keyhack.stp
diff --git a/examples/small_demos/kmalloc.stp b/testsuite/systemtap.examples/small_demos/kmalloc.stp
index 9157928d..9157928d 100755
--- a/examples/small_demos/kmalloc.stp
+++ b/testsuite/systemtap.examples/small_demos/kmalloc.stp
diff --git a/examples/small_demos/kmalloc2.stp b/testsuite/systemtap.examples/small_demos/kmalloc2.stp
index 2622dd2f..2622dd2f 100755
--- a/examples/small_demos/kmalloc2.stp
+++ b/testsuite/systemtap.examples/small_demos/kmalloc2.stp
diff --git a/examples/small_demos/proc_snoop.stp b/testsuite/systemtap.examples/small_demos/proc_snoop.stp
index 24499b4b..24499b4b 100755
--- a/examples/small_demos/proc_snoop.stp
+++ b/testsuite/systemtap.examples/small_demos/proc_snoop.stp
diff --git a/examples/small_demos/prof.stp b/testsuite/systemtap.examples/small_demos/prof.stp
index 389f743a..389f743a 100755
--- a/examples/small_demos/prof.stp
+++ b/testsuite/systemtap.examples/small_demos/prof.stp
diff --git a/examples/small_demos/return.wav b/testsuite/systemtap.examples/small_demos/return.wav
index 20f978cc..20f978cc 100644
--- a/examples/small_demos/return.wav
+++ b/testsuite/systemtap.examples/small_demos/return.wav
Binary files differ
diff --git a/examples/small_demos/rwtiming.stp b/testsuite/systemtap.examples/small_demos/rwtiming.stp
index d570c581..d570c581 100755
--- a/examples/small_demos/rwtiming.stp
+++ b/testsuite/systemtap.examples/small_demos/rwtiming.stp
diff --git a/examples/small_demos/sched_snoop.stp b/testsuite/systemtap.examples/small_demos/sched_snoop.stp
index 623643dd..623643dd 100755
--- a/examples/small_demos/sched_snoop.stp
+++ b/testsuite/systemtap.examples/small_demos/sched_snoop.stp
diff --git a/examples/small_demos/sys.stp b/testsuite/systemtap.examples/small_demos/sys.stp
index 2df20bc3..2df20bc3 100755
--- a/examples/small_demos/sys.stp
+++ b/testsuite/systemtap.examples/small_demos/sys.stp
diff --git a/examples/small_demos/top.stp b/testsuite/systemtap.examples/small_demos/top.stp
index b46b9940..b46b9940 100755
--- a/examples/small_demos/top.stp
+++ b/testsuite/systemtap.examples/small_demos/top.stp
diff --git a/examples/socket-trace.stp b/testsuite/systemtap.examples/socket-trace.stp
index 13ab8e06..13ab8e06 100755
--- a/examples/socket-trace.stp
+++ b/testsuite/systemtap.examples/socket-trace.stp
diff --git a/examples/socktop b/testsuite/systemtap.examples/socktop
index 123e37e9..123e37e9 100755
--- a/examples/socktop
+++ b/testsuite/systemtap.examples/socktop
diff --git a/examples/socktop.txt b/testsuite/systemtap.examples/socktop.txt
index 0ebce003..0ebce003 100644
--- a/examples/socktop.txt
+++ b/testsuite/systemtap.examples/socktop.txt
diff --git a/examples/syscalls_by_pid.stp b/testsuite/systemtap.examples/syscalls_by_pid.stp
index 47aa4955..47aa4955 100755
--- a/examples/syscalls_by_pid.stp
+++ b/testsuite/systemtap.examples/syscalls_by_pid.stp
diff --git a/examples/syscalls_by_pid.txt b/testsuite/systemtap.examples/syscalls_by_pid.txt
index 4943a139..4943a139 100644
--- a/examples/syscalls_by_pid.txt
+++ b/testsuite/systemtap.examples/syscalls_by_pid.txt
diff --git a/examples/syscalls_by_proc.stp b/testsuite/systemtap.examples/syscalls_by_proc.stp
index af7d6932..af7d6932 100755
--- a/examples/syscalls_by_proc.stp
+++ b/testsuite/systemtap.examples/syscalls_by_proc.stp
diff --git a/examples/syscalls_by_proc.txt b/testsuite/systemtap.examples/syscalls_by_proc.txt
index dd554083..dd554083 100644
--- a/examples/syscalls_by_proc.txt
+++ b/testsuite/systemtap.examples/syscalls_by_proc.txt
diff --git a/examples/syscalltimes b/testsuite/systemtap.examples/syscalltimes
index 84ca77a9..84ca77a9 100755
--- a/examples/syscalltimes
+++ b/testsuite/systemtap.examples/syscalltimes
diff --git a/examples/syscalltimes.txt b/testsuite/systemtap.examples/syscalltimes.txt
index d50f73ad..d50f73ad 100644
--- a/examples/syscalltimes.txt
+++ b/testsuite/systemtap.examples/syscalltimes.txt
diff --git a/examples/wait4time.stp b/testsuite/systemtap.examples/wait4time.stp
index 568239b9..568239b9 100755
--- a/examples/wait4time.stp
+++ b/testsuite/systemtap.examples/wait4time.stp
diff --git a/testsuite/systemtap.pass1-4/buildok.exp b/testsuite/systemtap.pass1-4/buildok.exp
index 77e77181..07580550 100644
--- a/testsuite/systemtap.pass1-4/buildok.exp
+++ b/testsuite/systemtap.pass1-4/buildok.exp
@@ -8,9 +8,7 @@ foreach file [lsort [glob -nocomplain $srcdir/$self/*.stp]] {
buildok/perfmon01.stp {setup_kfail 909 *-*-*}
buildok/twentysix.stp {setup_kfail 4105 *-*-*}
buildok/twentyseven.stp {setup_kfail 4166 *-*-*}
- buildok/process_test.stp {setup_kfail 1155 *-*-*}
buildok/sched_test.stp {setup_kfail 1155 *-*-*}
- buildok/socket.stp {setup_kfail 4413 *-*-*}
}
if {$rc == 0} { pass $test } else { fail $test }
}
diff --git a/testsuite/systemtap.samples/args.exp b/testsuite/systemtap.samples/args.exp
index 54647998..8bed7c9e 100644
--- a/testsuite/systemtap.samples/args.exp
+++ b/testsuite/systemtap.samples/args.exp
@@ -47,7 +47,7 @@ if [file exists $modpath] {
return
}
-spawn $staprunpath -d [pid] $modpath foo=hello bar=999
+spawn $staprunpath $modpath foo=hello bar=999
set ok 0
expect {
-timeout 120
@@ -62,7 +62,7 @@ if {$ok == 1} {
fail "$test run 1"
}
-spawn $staprunpath -d [pid] $modpath foo=goodbye bar=0
+spawn $staprunpath $modpath foo=goodbye bar=0
set ok 0
expect {
-timeout 120
diff --git a/testsuite/transok/eight.stp b/testsuite/transok/eight.stp
index 6723b993..9198536e 100755
--- a/testsuite/transok/eight.stp
+++ b/testsuite/transok/eight.stp
@@ -2,10 +2,11 @@
global foo
global baz
+global zoo
function bar()
{
- return foo["hello"]
+ return foo["hello"]+(zoo++)
}
probe begin
diff --git a/translate.cxx b/translate.cxx
index 6aef37f0..1782abd1 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -849,6 +849,7 @@ translator_output::line ()
void
c_unparser::emit_common_header ()
{
+ o->newline();
o->newline() << "typedef char string_t[MAXSTRINGLEN];";
o->newline();
o->newline() << "#define STAP_SESSION_STARTING 0";
@@ -4359,83 +4360,127 @@ c_unparser::visit_hist_op (hist_op*)
assert(false);
}
-int
-emit_symbol_data (systemtap_session& s)
+
+static map< Dwarf_Addr, string> addrmap;
+
+#include <string.h>
+
+static int
+kernel_filter (const char *module, const char *file __attribute__((unused)))
{
- int rc = 0;
+ return !strcmp(module,"kernel");
+}
- // Instead of processing elf symbol tables, for now we just snatch
- // /proc/kallsyms and convert it to our use. We need it sorted by
- // address (so we can binary search) , and filtered (to show text
- // symbols only), a task that we defer to grep(1) and sort(1). It
- // may be useful to cache the symbols.sorted file, perhaps indexed
- // by md5sum(/proc/modules), but let's not until this simple method
- // proves too costly. LC_ALL=C is already set to avoid the
- // excessive penalty of i18n code in some glibc/coreutils versions.
-
- string sorted_kallsyms = s.tmpdir + "/symbols.sorted";
- string sortcmd = "grep \" [AtT] \" /proc/kallsyms | ";
-
- if (s.symtab == false)
+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)))
+{
+ int syments = dwfl_module_getsymtab(m);
+ assert(syments);
+ for (int i = 1; i < syments; ++i)
{
- s.op->newline() << "/* filled in by runtime */";
- s.op->newline() << "struct stap_symbol *stap_symbols;";
- s.op->newline() << "unsigned stap_num_symbols;\n";
- return 0;
+ 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;
+ }
}
+ return DWARF_CB_OK;
+}
- sortcmd += "sort ";
-#if __LP64__
- sortcmd += "-k 1,16 ";
-#else
- sortcmd += "-k 1,8 ";
-#endif
- sortcmd += "-s -o " + sorted_kallsyms;
-
- if (s.verbose>1) clog << "Running " << sortcmd << endl;
- rc = system(sortcmd.c_str());
- if (rc == 0)
+int
+emit_symbol_data_from_debuginfo(systemtap_session& s, ofstream& kallsyms_out)
+{
+ 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 Dwfl_Callbacks kernel_callbacks =
{
- ifstream kallsyms (sorted_kallsyms.c_str());
- char kallsyms_outbuf [4096];
- ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
- kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf,
- sizeof(kallsyms_outbuf));
+ dwfl_linux_kernel_find_elf,
+ dwfl_standard_find_debuginfo,
+ dwfl_offline_section_address,
+ & debuginfo_path
+ };
+
+ Dwfl *dwfl = dwfl_begin (&kernel_callbacks);
+ 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);
+ dwfl_report_end (dwfl, NULL, NULL);
+ if (rc < 0)
+ return rc;
- s.op->newline() << "\n\n#include \"stap-symbols.h\"";
+ dwfl_getmodules (dwfl, &get_symbols, NULL, 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++;
+ }
- unsigned i=0;
- kallsyms_out << "struct stap_symbol _stp_stap_symbols [] = {";
- string lastaddr;
- while (! kallsyms.eof())
- {
- string addr, type, sym, module;
- kallsyms >> addr >> type >> sym;
- kallsyms >> ws;
- if (kallsyms.peek() == '[')
- {
- string bracketed;
- kallsyms >> bracketed;
- module = bracketed.substr (1, bracketed.length()-2);
- }
-
- // NB: kallsyms includes some duplicate addresses
- if ((type == "t" || type == "T" || type == "A") && lastaddr != addr)
- {
- kallsyms_out << " { 0x" << addr << ", "
- << "\"" << sym << "\", "
- << "\"" << module << "\" },"
- << "\n";
- lastaddr = addr;
- i ++;
- }
- }
kallsyms_out << "};\n";
- kallsyms_out << "struct stap_symbol *stap_symbols = _stp_stap_symbols;";
- kallsyms_out << "unsigned stap_num_symbols = " << i << ";\n";
- }
+ kallsyms_out << "unsigned _stp_num_kernel_symbols = " << dec << i << ";\n";
+ return i == 0;
+}
- return rc;
+int
+emit_symbol_data (systemtap_session& s)
+{
+ unsigned i=0;
+ char kallsyms_outbuf [4096];
+ ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
+ kallsyms_out.rdbuf()->pubsetbuf (kallsyms_outbuf,
+ sizeof(kallsyms_outbuf));
+ s.op->newline() << "\n\n#include \"stap-symbols.h\"";
+
+ // FIXME for non-debuginfo use.
+ if (true) {
+ return emit_symbol_data_from_debuginfo(s, kallsyms_out);
+ } else {
+ // For symbol-table only operation, we don't have debuginfo,
+ // so parse /proc/kallsyms.
+
+ ifstream kallsyms("/proc/kallsyms");
+ string lastaddr, modules_op_addr;
+
+ kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {";
+ while (! kallsyms.eof())
+ {
+ string addr, type, sym;
+ kallsyms >> addr >> type >> sym >> ws;
+
+ if (kallsyms.peek() == '[')
+ break;
+
+ // NB: kallsyms includes some duplicate addresses
+ if ((type == "t" || type == "T" || type == "A" || sym == "modules_op") && lastaddr != addr)
+ {
+ kallsyms_out << " { 0x" << addr << ", " << "\"" << sym << "\" },\n";
+ lastaddr = addr;
+ i ++;
+ }
+ }
+ kallsyms_out << "};\n";
+ kallsyms_out << "unsigned _stp_num_kernel_symbols = " << i << ";\n";
+ }
+ return (i == 0);
}
@@ -4452,9 +4497,6 @@ translate_pass (systemtap_session& s)
{
// This is at the very top of the file.
- // XXX: the runtime uses #ifdef TEST_MODE to infer systemtap usage.
- s.op->line() << "#define TEST_MODE 0\n";
-
s.op->newline() << "#ifndef MAXNESTING";
s.op->newline() << "#define MAXNESTING 10";
s.op->newline() << "#endif";
@@ -4521,16 +4563,12 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#include <linux/random.h>";
s.op->newline() << "#include <linux/utsname.h>";
s.op->newline() << "#include \"loc2c-runtime.h\" ";
-
+
// XXX: old 2.6 kernel hack
s.op->newline() << "#ifndef read_trylock";
s.op->newline() << "#define read_trylock(x) ({ read_lock(x); 1; })";
s.op->newline() << "#endif";
- s.op->newline() << "#if defined(CONFIG_MARKERS)";
- s.op->newline() << "#include <linux/marker.h>";
- s.op->newline() << "#endif";
-
s.up->emit_common_header (); // context etc.
for (unsigned i=0; i<s.embeds.size(); i++)
diff --git a/vim/syntax/stap.vim b/vim/syntax/stap.vim
index 86c7d260..e9ba136f 100644
--- a/vim/syntax/stap.vim
+++ b/vim/syntax/stap.vim
@@ -1,7 +1,7 @@
" Vim syntax file
-" Language: SystemTap
-" Maintainer: Josh Stone <joshua.i.stone@intel.com>
-" Last Change: 2005 Dec 20
+" Language: SystemTap
+" Maintainer: Josh Stone <joshua.i.stone@intel.com>
+" Last Change: 2008 Apr 17
" For version 5.x: Clear all syntax items
" For version 6.x: Quit when a syntax file was already loaded
@@ -11,11 +11,13 @@ elseif exists("b:current_syntax")
finish
endif
-syn keyword stapStatement contained break continue return next delete containedin=stapBlock
-syn keyword stapRepeat contained while for foreach in containedin=stapBlock
+setlocal iskeyword=@,48-57,_,$
+
+syn keyword stapStatement contained break continue return next delete containedin=stapBlock
+syn keyword stapRepeat contained while for foreach in limit containedin=stapBlock
syn keyword stapConditional contained if else containedin=stapBlock
syn keyword stapDeclaration global probe function
-syn keyword stapType string long
+syn keyword stapType string long
syn region stapProbeDec start="\<probe\>"lc=5 end="{"me=s-1 contains=stapString,stapNumber
syn match stapProbe contained "\<\w\+\>" containedin=stapProbeDec
@@ -27,17 +29,25 @@ syn match stapFunc contained "\<\w\+\>" containedin=stapFuncDec,stapFuncCall
syn match stapStat contained "@\<\w\+\ze\(\s\|\n\)*(" containedin=stapBlock
" decimal number
-syn match stapNumber "\<\d\+\>" containedin=stapBlock
+syn match stapNumber "\<\d\+\>" containedin=stapBlock
" octal number
-syn match stapNumber "\<0\o\+\>" contains=stapOctalZero containedin=stapBlock
+syn match stapNumber "\<0\o\+\>" contains=stapOctalZero containedin=stapBlock
" Flag the first zero of an octal number as something special
-syn match stapOctalZero contained "\<0"
+syn match stapOctalZero contained "\<0"
" flag an octal number with wrong digits
-syn match stapOctalError "\<0\o*[89]\d*" containedin=stapBlock
+syn match stapOctalError "\<0\o*[89]\d*" containedin=stapBlock
" hex number
-syn match stapNumber "0x\x\+\>" containedin=stapBlock
+syn match stapNumber "\<0x\x\+\>" containedin=stapBlock
+" numeric arguments
+syn match stapNumber "\<\$\d\+\>" containedin=stapBlock
+syn match stapNumber "\<\$#" containedin=stapBlock
+
+syn region stapString oneline start=+"+ skip=+\\"+ end=+"+ containedin=stapBlock
+" string arguments
+syn match stapString "@\d\+\>" containedin=stapBlock
+syn match stapString "@#" containedin=stapBlock
-syn region stapString oneline start=+"+ skip=+\\"+ end=+"+ containedin=stapBlock
+syn match stapTarget contained "\w\@<!\$\h\w*\>" containedin=stapBlock
syn region stapPreProc fold start="%(" end="%)" contains=stapNumber,stapString containedin=ALL
syn keyword stapPreProcCond contained kernel_v kernel_vr arch containedin=stapPreProc
@@ -48,15 +58,15 @@ syn region stapCBlock fold matchgroup=stapCBlockDelims start="%{"rs=e end="%}"r
syn region stapBlock fold matchgroup=stapBlockEnds start="{"rs=e end="}"re=s containedin=stapBlock
-syn keyword stapTodo contained TODO FIXME XXX
+syn keyword stapTodo contained TODO FIXME XXX
-syn match stapComment "#.*" contains=stapTodo containedin=stapBlock
-syn match stapComment "//.*" contains=stapTodo containedin=stapBlock
-syn region stapComment matchgroup=stapComment start="/\*" end="\*/" contains=stapTodo,stapCommentBad containedin=stapBlock
-syn match stapCommentBad contained "/\*"
+syn match stapComment "#.*" contains=stapTodo containedin=stapBlock
+syn match stapComment "//.*" contains=stapTodo containedin=stapBlock
+syn region stapComment matchgroup=stapComment start="/\*" end="\*/" contains=stapTodo,stapCommentBad containedin=stapBlock
+syn match stapCommentBad contained "/\*"
" treat ^#! as special
-syn match stapSharpBang "^#!.*"
+syn match stapSharpBang "^#!.*"
" define the default highlighting
@@ -70,26 +80,27 @@ if version >= 508 || !exists("did_stap_syn_inits")
command -nargs=+ HiLink hi def link <args>
endif
- HiLink stapNumber Number
- HiLink stapOctalZero PreProc " c.vim does it this way...
- HiLink stapOctalError Error
- HiLink stapString String
- HiLink stapTodo Todo
- HiLink stapComment Comment
+ HiLink stapNumber Number
+ HiLink stapOctalZero PreProc " c.vim does it this way...
+ HiLink stapOctalError Error
+ HiLink stapString String
+ HiLink stapTodo Todo
+ HiLink stapComment Comment
HiLink stapCommentBad Error
- HiLink stapSharpBang PreProc
- HiLink stapCBlockDelims Special
+ HiLink stapSharpBang PreProc
+ HiLink stapCBlockDelims Special
HiLink stapCMacro Macro
- HiLink stapStatement Statement
- HiLink stapConditional Conditional
- HiLink stapRepeat Repeat
- HiLink stapType Type
- HiLink stapProbe Function
- HiLink stapFunc Function
- HiLink stapStat Function
- HiLink stapPreProc PreProc
- HiLink stapPreProcCond Special
- HiLink stapDeclaration Typedef
+ HiLink stapStatement Statement
+ HiLink stapConditional Conditional
+ HiLink stapRepeat Repeat
+ HiLink stapType Type
+ HiLink stapProbe Function
+ HiLink stapFunc Function
+ HiLink stapStat Function
+ HiLink stapPreProc PreProc
+ HiLink stapPreProcCond Special
+ HiLink stapDeclaration Typedef
+ HiLink stapTarget Special
delcommand HiLink
endif