summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore11
-rw-r--r--ChangeLog242
-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.cxx213
-rw-r--r--runtime/.gitignore1
-rw-r--r--runtime/ChangeLog128
-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/probes.c12
-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.h10
-rw-r--r--stap.1.in13
-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/ChangeLog15
-rw-r--r--tapset/context.stp4
-rw-r--r--tapset/scsi.stp5
-rw-r--r--tapset/tcp.stp65
-rw-r--r--tapsets.cxx744
-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)7
-rw-r--r--testsuite/systemtap.examples/README (renamed from examples/README)0
-rw-r--r--testsuite/systemtap.examples/check.exp75
-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
-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
-rwxr-xr-xtestsuite/systemtap.examples/pf2.stp (renamed from examples/pf2.stp)0
-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.cxx169
-rw-r--r--vim/syntax/stap.vim83
149 files changed, 5793 insertions, 2073 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..ee84b636 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -28,6 +28,248 @@
* hash.cxx, session.h, stap.1.in: Added --kelf, --kmap,
--ignore-vmlinux, and --ignore-dwarf.
* testsuite/{semok,semko}/nodwf*.stp
+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>
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..7a086a66 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
@@ -102,6 +105,17 @@ usage (systemtap_session& s, int exitcode)
<< " -c CMD start the probes, run CMD, and exit when it finishes"
<< endl
<< " -x PID sets target() to PID" << endl
+ << " -d OBJECT add unwind/symbol data for OBJECT file";
+ if (s.unwindsym_modules.size() == 0)
+ clog << endl;
+ else
+ clog << ", in addition to" << endl;
+ {
+ vector<string> syms (s.unwindsym_modules.begin(), s.unwindsym_modules.end());
+ for (unsigned i=0; i<syms.size(); i++)
+ clog << " " << syms[i] << endl;
+ }
+ clog
<< " -t collect probe timing information" << endl
#ifdef HAVE_LIBSQLITE3
<< " -q generate information on tapset coverage" << endl
@@ -124,75 +138,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 +293,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 +380,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:d:",
long_options, NULL);
if (grc < 0)
break;
@@ -345,6 +407,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)
{
@@ -357,6 +424,10 @@ main (int argc, char * const argv [])
s.include_path.push_back (string (optarg));
break;
+ case 'd':
+ s.unwindsym_modules.insert (string (optarg));
+ break;
+
case 'e':
if (have_script)
{
@@ -450,9 +521,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 +548,18 @@ main (int argc, char * const argv [])
usage (s, 0);
break;
+ case 'l':
+ 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;
+
case 0:
switch (long_opt)
{
@@ -785,7 +868,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 +917,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..8410b918 100644
--- a/runtime/ChangeLog
+++ b/runtime/ChangeLog
@@ -1,3 +1,105 @@
+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 +108,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/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.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..dcaa1bc3 100644
--- a/runtime/vsprintf.c
+++ b/runtime/vsprintf.c
@@ -256,18 +256,18 @@ int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
break;
case 2:
if((str + 1) <= end)
- *(int16_t *)str = (int16_t)num;
+ memcpy(str, &num, 2);
str+=2;
break;
case 4:
if((str + 3) <= end)
- *(int32_t *)str = num;
+ memcpy(str, &num, 4);
str+=4;
break;
default: // "%.8b" by default
case 8:
if((str + 7) <= end)
- *(int64_t *)str = num;
+ memcpy(str, &num, 8);
str+=8;
break;
}
diff --git a/session.h b/session.h
index e44e5c98..4122d0ac 100644
--- a/session.h
+++ b/session.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-// Copyright (C) 2005-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
@@ -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;
@@ -157,6 +162,9 @@ struct systemtap_session
Dwarf_Addr sym_kprobes_text_end;
Dwarf_Addr sym_stext;
+ // List of libdwfl module names to extract symbol/unwind data for.
+ std::set<std::string> unwindsym_modules;
+
std::set<std::string> seen_errors;
unsigned num_errors () { return seen_errors.size(); }
// void print_error (const parse_error& e);
diff --git a/stap.1.in b/stap.1.in
index 1b9fe466..aa32fa52 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,10 @@ 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.
.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..cf41c9cb 100644
--- a/tapset/ChangeLog
+++ b/tapset/ChangeLog
@@ -1,3 +1,18 @@
+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/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/tapsets.cxx b/tapsets.cxx
index 47bb20e2..d6867e35 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,
@@ -3025,6 +3049,7 @@ dwarf_query::add_probe_point(const string& funcname,
if (! bad)
{
+ sess.unwindsym_modules.insert (module);
probe = new dwarf_derived_probe(funcname, filename, line,
module, reloc_section, addr, reloc_addr, *this, scope_die);
results.push_back(probe);
@@ -3071,7 +3096,6 @@ dwarf_query::assess_dbinfo_reqt()
}
-
// The critical determining factor when interpreting a pattern
// string is, perhaps surprisingly: "presence of a lineno". The
// presence of a lineno changes the search strategy completely.
@@ -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.
@@ -4594,6 +4618,7 @@ dwarf_builder::build(systemtap_session & sess,
q.statement_num_val, q.statement_num_val,
q, 0);
finished_results.push_back (p);
+ sess.unwindsym_modules.insert ("kernel");
return;
}
@@ -4896,6 +4921,648 @@ 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;
+
+ // XXX: these checks should be done in terms of filesystem
+ // operations.
+
+ // 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);
+
+ sess.unwindsym_modules.insert (path);
+ }
+
+ 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 +6026,7 @@ profile_derived_probe_group::emit_module_exit (systemtap_session& s)
}
+
// ------------------------------------------------------------------------
// procfs file derived probes
// ------------------------------------------------------------------------
@@ -5426,7 +6094,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 +6505,7 @@ procfs_builder::build(systemtap_session & sess,
}
+
// ------------------------------------------------------------------------
// statically inserted macro-based derived probes
// ------------------------------------------------------------------------
@@ -6085,7 +6754,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 +6906,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 +6997,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 +7148,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 +7215,7 @@ mark_builder::build(systemtap_session & sess,
}
+
// ------------------------------------------------------------------------
// hrtimer derived probes
// ------------------------------------------------------------------------
@@ -6828,6 +7509,7 @@ timer_builder::register_patterns(match_node *root)
}
+
// ------------------------------------------------------------------------
// perfmon derived probes
// ------------------------------------------------------------------------
@@ -6970,7 +7652,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 +7960,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 +8016,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..ad46276c 100644
--- a/examples/ChangeLog
+++ b/testsuite/systemtap.examples/ChangeLog
@@ -1,3 +1,10 @@
+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/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/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/examples/pf2.stp b/testsuite/systemtap.examples/pf2.stp
index 96fdb7e7..96fdb7e7 100755
--- a/examples/pf2.stp
+++ b/testsuite/systemtap.examples/pf2.stp
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..b1037fef 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,98 @@ 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)
- {
- 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));
-
- s.op->newline() << "\n\n#include \"stap-symbols.h\"";
+void
+emit_symbol_data (systemtap_session& s)
+{
+ ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
+ s.op->newline() << "\n\n#include \"stap-symbols.h\"";
- 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";
+ if (s.verbose > 1)
+ {
+ std::set<std::string>::iterator it = s.unwindsym_modules.begin();
+ clog << "unwindsym modules: ";
+ while (it != s.unwindsym_modules.end())
+ {
+ clog << *(it++) << " ";
+ }
+ clog << endl;
}
- return rc;
+ 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 =
+ {
+ 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)
+ throw semantic_error ("dwfl rc");
+
+ 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++;
+ }
+
+ kallsyms_out << "};\n";
+ kallsyms_out << "unsigned _stp_num_kernel_symbols = " << dec << i << ";\n";
}
@@ -4452,9 +4468,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 +4534,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++)
@@ -4605,16 +4614,16 @@ translate_pass (systemtap_session& s)
s.up->emit_global_param (s.globals[i]);
}
- s.op->newline() << "MODULE_DESCRIPTION(\"systemtap probe\");";
- s.op->newline() << "MODULE_LICENSE(\"GPL\");"; // XXX
+ emit_symbol_data (s);
+
+ s.op->newline() << "MODULE_DESCRIPTION(\"systemtap-generated probe\");";
+ s.op->newline() << "MODULE_LICENSE(\"GPL\");";
}
catch (const semantic_error& e)
{
s.print_error (e);
}
- rc |= emit_symbol_data (s);
-
s.op->line() << "\n";
delete s.op;
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