summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Smith <dsmith@redhat.com>2009-05-21 16:57:04 -0500
committerDavid Smith <dsmith@redhat.com>2009-05-21 16:57:04 -0500
commitc8e9eb18d8d13d099a4a177fe53de507c1d9ce8b (patch)
treeab2388afb795ed1a7ead2fbbf8b9d1b368a8231f
parentdd9a3bcbef65bde65491d959e9458bc641924811 (diff)
parent3863e7999255deeaa7f8f4bba7df893773812537 (diff)
downloadsystemtap-steved-c8e9eb18d8d13d099a4a177fe53de507c1d9ce8b.tar.gz
systemtap-steved-c8e9eb18d8d13d099a4a177fe53de507c1d9ce8b.tar.xz
systemtap-steved-c8e9eb18d8d13d099a4a177fe53de507c1d9ce8b.zip
Merge commit 'origin/master' into pr7043
Conflicts: runtime/print.c runtime/transport/transport.c runtime/transport/transport_msgs.h
-rw-r--r--.gitignore4
-rw-r--r--.mailmap1
-rw-r--r--AUTHORS8
-rw-r--r--Makefile.am44
-rw-r--r--Makefile.in435
-rw-r--r--NEWS127
-rw-r--r--README4
-rw-r--r--aclocal.m4196
-rw-r--r--buildrun.cxx202
-rw-r--r--buildrun.h4
-rw-r--r--cache.cxx68
-rw-r--r--config.in3
-rwxr-xr-xconfigure451
-rw-r--r--configure.ac59
-rw-r--r--doc/Makefile.in21
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/References.xml2
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-ioblktime.xml111
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcp_connections.xml86
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcpdumplike.xml116
-rw-r--r--doc/SystemTap_Beginners_Guide/en-US/Useful_SystemTap_Scripts.xml4
-rw-r--r--doc/SystemTap_Tapset_Reference/.gitignore3
-rw-r--r--doc/SystemTap_Tapset_Reference/Makefile.am20
-rw-r--r--doc/SystemTap_Tapset_Reference/Makefile.in42
-rw-r--r--doc/SystemTap_Tapset_Reference/tapsets.tmpl70
-rw-r--r--doc/Tapset_Reference_Guide/en-US/Tapset_Dev_Guide.xml24
-rwxr-xr-xdoc/Tapset_Reference_Guide/manpager.sh120
-rwxr-xr-xdoc/Tapset_Reference_Guide/publicanize.sh117
-rwxr-xr-xdtrace61
-rw-r--r--elaborate.cxx22
-rw-r--r--elaborate.h5
-rwxr-xr-xgit_version.sh4
-rw-r--r--grapher/.gitignore1
-rw-r--r--grapher/CairoWidget.cxx42
-rw-r--r--grapher/CairoWidget.hxx42
-rw-r--r--grapher/GraphData.hxx44
-rw-r--r--grapher/GraphWidget.cxx323
-rw-r--r--grapher/GraphWidget.hxx62
-rw-r--r--grapher/Makefile.am7
-rw-r--r--grapher/Makefile.in490
-rw-r--r--grapher/grapher.cxx127
-rw-r--r--hash.cxx84
-rw-r--r--hash.h4
-rw-r--r--includes/sys/sdt.h285
-rw-r--r--initscript/.gitignore1
-rw-r--r--initscript/README.initscript2
-rw-r--r--initscript/systemtap.in22
-rw-r--r--main.cxx109
-rw-r--r--man/stapprobes.iosched.3stap.in (renamed from man/stapprobes.iosched.5.in)4
-rw-r--r--man/stapprobes.kprocess.3stap.in (renamed from man/stapprobes.process.5.in)24
-rw-r--r--man/stapprobes.netdev.3stap.in (renamed from man/stapprobes.netdev.5.in)4
-rw-r--r--man/stapprobes.nfs.3stap.in (renamed from man/stapprobes.nfs.5.in)42
-rw-r--r--man/stapprobes.nfsd.3stap.in (renamed from man/stapprobes.nfsd.5.in)26
-rw-r--r--man/stapprobes.pagefault.3stap.in (renamed from man/stapprobes.pagefault.5.in)4
-rw-r--r--man/stapprobes.rpc.3stap.in (renamed from man/stapprobes.rpc.5.in)12
-rw-r--r--man/stapprobes.scsi.3stap.in (renamed from man/stapprobes.scsi.5.in)4
-rw-r--r--man/stapprobes.signal.3stap.in (renamed from man/stapprobes.signal.5.in)14
-rw-r--r--man/stapprobes.socket.3stap.in (renamed from man/stapprobes.socket.5.in)8
-rw-r--r--man/stapprobes.tcp.3stap.in (renamed from man/stapprobes.tcp.5.in)4
-rw-r--r--man/stapprobes.udp.3stap.in (renamed from man/stapprobes.udp.5.in)4
-rw-r--r--modsign.cxx555
-rw-r--r--modsign.h3
-rw-r--r--nsscommon.c85
-rw-r--r--nsscommon.h4
-rw-r--r--parse.cxx6
-rw-r--r--run-stap.in7
-rw-r--r--run-staprun.in24
-rw-r--r--runtime/autoconf-asm-syscall.c2
-rw-r--r--runtime/autoconf-find-task-pid.c6
-rw-r--r--runtime/autoconf-x86-gs.c5
-rw-r--r--runtime/itrace.c60
-rw-r--r--runtime/loc2c-runtime.h42
-rw-r--r--runtime/map-gen.c291
-rw-r--r--runtime/map.c23
-rw-r--r--runtime/pmap-gen.c343
-rw-r--r--runtime/print.c27
-rw-r--r--runtime/ptrace_compatibility.h50
-rw-r--r--runtime/runtime.h19
-rw-r--r--runtime/stack-arm.c3
-rw-r--r--runtime/stack-i386.c25
-rw-r--r--runtime/stack-ia64.c3
-rw-r--r--runtime/stack-ppc64.c3
-rw-r--r--runtime/stack-s390.c3
-rw-r--r--runtime/stack-x86_64.c23
-rw-r--r--runtime/stack.c40
-rw-r--r--runtime/staprun/common.c123
-rw-r--r--runtime/staprun/mainloop.c70
-rw-r--r--runtime/staprun/modverify.c391
-rw-r--r--runtime/staprun/modverify.h9
-rw-r--r--runtime/staprun/relay.c149
-rw-r--r--runtime/staprun/relay_old.c138
-rw-r--r--runtime/staprun/staprun.h29
-rw-r--r--runtime/staprun/staprun_funcs.c190
-rw-r--r--runtime/sym.c220
-rw-r--r--runtime/sym.h2
-rw-r--r--runtime/syscall.h407
-rw-r--r--runtime/task_finder.c539
-rw-r--r--runtime/task_finder_map.c191
-rw-r--r--runtime/task_finder_vma.c87
-rw-r--r--runtime/transport/control.c7
-rw-r--r--runtime/transport/transport.c14
-rw-r--r--runtime/transport/transport_msgs.h6
-rw-r--r--runtime/unwind.c24
-rw-r--r--runtime/unwind/unwind.h4
-rw-r--r--runtime/uprobes/.gitignore7
-rw-r--r--runtime/uprobes/uprobes.c34
-rw-r--r--runtime/uprobes/uprobes.h6
-rw-r--r--runtime/uprobes/uprobes_i386.c40
-rw-r--r--runtime/uprobes/uprobes_x86.c22
-rw-r--r--runtime/uprobes/uprobes_x86_64.c7
-rw-r--r--runtime/uprobes2/uprobes.c52
-rw-r--r--runtime/uprobes2/uprobes.h11
-rw-r--r--runtime/uprobes2/uprobes_x86.c9
-rw-r--r--runtime/uprobes2/uprobes_x86.h13
-rw-r--r--runtime/utrace_compatibility.h14
-rw-r--r--runtime/vsprintf.c372
-rwxr-xr-xscripts/kernel-doc8
-rw-r--r--session.h30
-rw-r--r--[-rwxr-xr-x]stap-authorize-cert (renamed from stap-add-server-cert)27
-rw-r--r--stap-authorize-server-cert30
-rw-r--r--stap-authorize-signing-cert30
-rwxr-xr-xstap-client84
-rw-r--r--stap-env38
-rwxr-xr-xstap-find-or-start-server18
-rwxr-xr-xstap-find-servers19
-rw-r--r--[-rwxr-xr-x]stap-gen-cert (renamed from stap-gen-server-cert)28
-rwxr-xr-xstap-server25
-rw-r--r--stap-server-connect.c14
-rw-r--r--stap-server.8.in59
-rwxr-xr-xstap-serverd54
-rwxr-xr-xstap-start-server10
-rw-r--r--stap.1.in130
-rw-r--r--stapex.3stap.in (renamed from stapex.5.in)6
-rw-r--r--stapfuncs.3stap.in (renamed from stapfuncs.5.in)15
-rw-r--r--stapprobes.3stap.in (renamed from stapprobes.5.in)139
-rw-r--r--staprun.8.in24
-rw-r--r--staptree.h1
-rw-r--r--stapvars.3stap.in (renamed from stapvars.5.in)2
-rw-r--r--systemtap.spec41
-rw-r--r--tapset-been.cxx228
-rw-r--r--tapset-itrace.cxx337
-rw-r--r--tapset-mark.cxx712
-rw-r--r--tapset-perfmon.cxx463
-rw-r--r--tapset-procfs.cxx521
-rw-r--r--tapset-timers.cxx626
-rw-r--r--tapset-utrace.cxx1061
-rw-r--r--tapset/DEVGUIDE6
-rw-r--r--tapset/ansi.stp70
-rw-r--r--tapset/aux_syscalls.stp18
-rw-r--r--tapset/context-symbols.stp84
-rw-r--r--tapset/context-unwind.stp32
-rw-r--r--tapset/context.stp120
-rw-r--r--tapset/conversions.stp5
-rw-r--r--tapset/errno.stp14
-rw-r--r--tapset/i686/registers.stp50
-rw-r--r--tapset/i686/syscalls.stp2
-rw-r--r--tapset/ioscheduler.stp20
-rw-r--r--tapset/ip.stp78
-rw-r--r--tapset/kprocess.stp (renamed from tapset/process.stp)34
-rw-r--r--tapset/memory.stp13
-rw-r--r--tapset/networking.stp8
-rw-r--r--tapset/s390x/syscalls.stp24
-rw-r--r--tapset/scsi.stp18
-rw-r--r--tapset/signal.stp210
-rw-r--r--tapset/socket.stp80
-rw-r--r--tapset/string.stp12
-rw-r--r--tapset/syscalls.stp8
-rw-r--r--tapset/task.stp24
-rw-r--r--tapset/tcp.stp132
-rw-r--r--tapset/timestamp.stp6
-rw-r--r--tapset/ucontext-symbols.stp75
-rw-r--r--tapset/ucontext-unwind.stp52
-rw-r--r--tapset/udp.stp46
-rw-r--r--tapset/utrace.stp22
-rw-r--r--tapsets.cxx5103
-rw-r--r--tapsets.h42
-rw-r--r--task_finder.cxx103
-rw-r--r--task_finder.h20
-rw-r--r--testsuite/.gitignore3
-rw-r--r--testsuite/Makefile.in99
-rw-r--r--testsuite/aclocal.m436
-rwxr-xr-xtestsuite/buildko/two.stp14
-rwxr-xr-xtestsuite/buildok/context_test.stp22
-rwxr-xr-xtestsuite/buildok/maxactive01.stp2
-rwxr-xr-xtestsuite/buildok/modname.stp8
-rwxr-xr-xtestsuite/buildok/process-all-probes.stp12
-rwxr-xr-xtestsuite/buildok/process_test.stp12
-rwxr-xr-xtestsuite/buildok/seventeen.stp9
-rwxr-xr-xtestsuite/buildok/symdata.stp8
-rwxr-xr-xtestsuite/buildok/symname.stp8
-rwxr-xr-xtestsuite/buildok/task-embedded.stp4
-rwxr-xr-xtestsuite/buildok/task_test.stp2
-rwxr-xr-xtestsuite/buildok/tcp_test.stp14
-rwxr-xr-xtestsuite/buildok/thirteen.stp2
-rwxr-xr-xtestsuite/buildok/thirty.stp49
-rwxr-xr-xtestsuite/buildok/thirtyone.stp4
-rwxr-xr-xtestsuite/buildok/twentysix.stp7
-rwxr-xr-xtestsuite/buildok/uaddr.stp8
-rwxr-xr-xtestsuite/buildok/ustack.stp10
-rwxr-xr-xtestsuite/buildok/usymdata.stp8
-rwxr-xr-xtestsuite/buildok/usymname.stp8
-rwxr-xr-xtestsuite/configure20
-rw-r--r--testsuite/configure.ac2
-rw-r--r--testsuite/lib/stap_run.exp1
-rw-r--r--testsuite/lib/stap_run2.exp23
-rw-r--r--testsuite/lib/systemtap.exp32
-rwxr-xr-xtestsuite/parseko/cmdline17.stp8
-rwxr-xr-xtestsuite/parseko/cmdline18.stp10
-rwxr-xr-xtestsuite/parseko/cmdline19.stp10
-rwxr-xr-xtestsuite/parseko/cmdline20.stp9
-rwxr-xr-xtestsuite/parseko/cmdline21.stp15
-rwxr-xr-xtestsuite/parseko/utrace01.stp2
-rwxr-xr-xtestsuite/semko/forty.stp2
-rwxr-xr-xtestsuite/semko/fortyone.stp2
-rwxr-xr-xtestsuite/semko/fortytwo.stp2
-rwxr-xr-xtestsuite/semko/maxactive04.stp2
-rwxr-xr-xtestsuite/semko/maxactive05.stp2
-rwxr-xr-xtestsuite/semko/return02.stp2
-rwxr-xr-xtestsuite/semko/thirtyfour.stp4
-rwxr-xr-xtestsuite/semko/twentytwo.stp2
-rwxr-xr-xtestsuite/semko/utrace01.stp4
-rwxr-xr-xtestsuite/semko/utrace03.stp2
-rwxr-xr-xtestsuite/semko/utrace04.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/badvar.stp4
-rwxr-xr-xtestsuite/semok/cast.stp10
-rwxr-xr-xtestsuite/semok/thirtythree.stp6
-rwxr-xr-xtestsuite/semok/thirtytwo.stp2
-rwxr-xr-xtestsuite/semok/twentynine.stp2
-rwxr-xr-xtestsuite/semok/utrace01.stp4
-rw-r--r--testsuite/systemtap.base/alternatives.exp17
-rw-r--r--testsuite/systemtap.base/badkprobe.exp32
-rw-r--r--testsuite/systemtap.base/bitfield.exp3
-rw-r--r--testsuite/systemtap.base/bitfield.stp46
-rw-r--r--testsuite/systemtap.base/bz10078.c22
-rw-r--r--testsuite/systemtap.base/bz10078.exp35
-rwxr-xr-xtestsuite/systemtap.base/bz10078.stp4
-rwxr-xr-xtestsuite/systemtap.base/bz5274.exp9
-rw-r--r--testsuite/systemtap.base/bz6850.exp9
-rw-r--r--testsuite/systemtap.base/cast.exp6
-rw-r--r--testsuite/systemtap.base/cast.stp25
-rw-r--r--testsuite/systemtap.base/flightrec1.exp43
-rw-r--r--testsuite/systemtap.base/flightrec2.exp68
-rw-r--r--testsuite/systemtap.base/flightrec2.stp5
-rw-r--r--testsuite/systemtap.base/flightrec3.exp79
-rw-r--r--testsuite/systemtap.base/flightrec3.stp5
-rw-r--r--testsuite/systemtap.base/itrace.exp49
-rw-r--r--testsuite/systemtap.base/kprobes.exp2
-rw-r--r--testsuite/systemtap.base/kprobes.stp25
-rw-r--r--testsuite/systemtap.base/labels.exp82
-rw-r--r--testsuite/systemtap.base/maxactive.exp16
-rw-r--r--testsuite/systemtap.base/onoffprobe.stp4
-rw-r--r--testsuite/systemtap.base/optionalprobe.exp9
-rw-r--r--testsuite/systemtap.base/optionalprobe.stp14
-rw-r--r--testsuite/systemtap.base/overload.exp2
-rw-r--r--testsuite/systemtap.base/sdt.exp28
-rw-r--r--testsuite/systemtap.base/sdt.stp20
-rw-r--r--testsuite/systemtap.base/sdt_types.c168
-rw-r--r--testsuite/systemtap.base/sdt_types.stp371
-rw-r--r--testsuite/systemtap.base/skipped.exp6
-rw-r--r--testsuite/systemtap.base/static_uprobes.exp100
-rw-r--r--testsuite/systemtap.base/stmt_rel.exp46
-rw-r--r--testsuite/systemtap.base/stmt_rel.stp71
-rw-r--r--testsuite/systemtap.base/stmtvars.exp6
-rw-r--r--testsuite/systemtap.base/strftime.exp49
-rw-r--r--testsuite/systemtap.base/system_func.stp4
-rw-r--r--testsuite/systemtap.base/tracepoints.exp23
-rw-r--r--testsuite/systemtap.base/uprobes.exp9
-rw-r--r--testsuite/systemtap.base/uprobes_exe.c29
-rw-r--r--testsuite/systemtap.base/uprobes_lib.c21
-rw-r--r--testsuite/systemtap.base/uprobes_lib.exp46
-rw-r--r--testsuite/systemtap.base/uprobes_lib.stp15
-rw-r--r--testsuite/systemtap.base/uprobes_uname.exp46
-rw-r--r--testsuite/systemtap.base/uprobes_uname.stp7
-rw-r--r--testsuite/systemtap.base/uprobes_ustack.exp97
-rw-r--r--testsuite/systemtap.base/uprobes_ustack.stp35
-rw-r--r--testsuite/systemtap.base/utrace_p4.exp34
-rw-r--r--testsuite/systemtap.base/utrace_p5.exp21
-rw-r--r--testsuite/systemtap.base/utrace_syscall_args.c67
-rw-r--r--testsuite/systemtap.base/utrace_syscall_args.exp82
-rw-r--r--testsuite/systemtap.base/utrace_syscall_args.stp406
-rw-r--r--testsuite/systemtap.base/x86_gs.exp12
-rw-r--r--testsuite/systemtap.base/x86_gs.stp10
-rw-r--r--testsuite/systemtap.context/args.tcl2
-rw-r--r--testsuite/systemtap.context/backtrace.tcl3
-rw-r--r--testsuite/systemtap.context/context.exp3
-rw-r--r--testsuite/systemtap.context/num_args.tcl2
-rw-r--r--testsuite/systemtap.context/pid.tcl2
-rw-r--r--testsuite/systemtap.context/usymbols.c39
-rw-r--r--testsuite/systemtap.context/usymbols.exp82
-rw-r--r--testsuite/systemtap.context/usymbols_lib.c29
-rw-r--r--testsuite/systemtap.examples/README146
-rw-r--r--testsuite/systemtap.examples/general/ansi_colors.meta13
-rwxr-xr-xtestsuite/systemtap.examples/general/ansi_colors.stp43
-rw-r--r--testsuite/systemtap.examples/general/ansi_colors2.meta13
-rwxr-xr-xtestsuite/systemtap.examples/general/ansi_colors2.stp31
-rw-r--r--testsuite/systemtap.examples/general/grapher.stp32
-rw-r--r--testsuite/systemtap.examples/general/para-callgraph.meta4
-rw-r--r--testsuite/systemtap.examples/index.html20
-rw-r--r--testsuite/systemtap.examples/index.txt56
-rw-r--r--testsuite/systemtap.examples/io/ioblktime.meta13
-rwxr-xr-xtestsuite/systemtap.examples/io/ioblktime.stp29
-rwxr-xr-xtestsuite/systemtap.examples/io/traceio.stp33
-rw-r--r--testsuite/systemtap.examples/keyword-index.html52
-rw-r--r--testsuite/systemtap.examples/keyword-index.txt105
-rw-r--r--testsuite/systemtap.examples/network/dropwatch.meta13
-rwxr-xr-xtestsuite/systemtap.examples/network/dropwatch.stp30
-rwxr-xr-xtestsuite/systemtap.examples/network/nettop.stp10
-rwxr-xr-xtestsuite/systemtap.examples/network/tcp.stp13
-rw-r--r--testsuite/systemtap.examples/network/tcpdumplike.meta12
-rwxr-xr-xtestsuite/systemtap.examples/network/tcpdumplike.stp14
-rw-r--r--testsuite/systemtap.examples/process/errsnoop.meta7
-rwxr-xr-xtestsuite/systemtap.examples/process/errsnoop.stp44
-rwxr-xr-xtestsuite/systemtap.examples/process/proc_snoop.stp12
-rw-r--r--testsuite/systemtap.examples/process/sigmon.meta4
-rwxr-xr-xtestsuite/systemtap.examples/profiling/latencytap.stp2
-rwxr-xr-xtestsuite/systemtap.examples/profiling/timeout.stp4
-rw-r--r--testsuite/systemtap.pass1-4/buildok.exp2
-rw-r--r--testsuite/systemtap.printf/basic6.exp3
-rw-r--r--testsuite/systemtap.printf/basic6.stp5
-rw-r--r--testsuite/systemtap.printf/char1.exp2
-rw-r--r--testsuite/systemtap.printf/char1.stp1
-rw-r--r--testsuite/systemtap.printf/end1.exp2
-rw-r--r--testsuite/systemtap.printf/end1b.exp2
-rw-r--r--testsuite/systemtap.printf/memory1.stp14
-rw-r--r--testsuite/systemtap.printf/mixed_out.exp2
-rw-r--r--testsuite/systemtap.printf/mixed_outb.exp2
-rw-r--r--testsuite/systemtap.printf/out1.exp2
-rw-r--r--testsuite/systemtap.printf/out1b.exp2
-rw-r--r--testsuite/systemtap.printf/out2.exp2
-rw-r--r--testsuite/systemtap.printf/out2b.exp2
-rw-r--r--testsuite/systemtap.printf/out3.exp2
-rw-r--r--testsuite/systemtap.printf/out3b.exp2
-rw-r--r--testsuite/systemtap.samples/ioblocktest.exp11
-rw-r--r--testsuite/systemtap.samples/ioblocktest.stp12
-rw-r--r--testsuite/systemtap.server/server.exp1
-rw-r--r--testsuite/systemtap.stress/whitelist.exp1
-rw-r--r--testsuite/systemtap.syscall/access.c24
-rw-r--r--testsuite/systemtap.syscall/acct.c2
-rw-r--r--[-rwxr-xr-x]testsuite/systemtap.syscall/alarm.c20
-rw-r--r--testsuite/systemtap.syscall/chmod.c44
-rw-r--r--testsuite/systemtap.syscall/clock.c38
-rw-r--r--testsuite/systemtap.syscall/dir.c24
-rw-r--r--testsuite/systemtap.syscall/forkwait.c4
-rw-r--r--testsuite/systemtap.syscall/futimes.c14
-rw-r--r--testsuite/systemtap.syscall/itimer.c14
-rw-r--r--testsuite/systemtap.syscall/link.c20
-rw-r--r--testsuite/systemtap.syscall/mmap.c22
-rw-r--r--testsuite/systemtap.syscall/mount.c10
-rw-r--r--testsuite/systemtap.syscall/net1.c12
-rw-r--r--testsuite/systemtap.syscall/openclose.c32
-rw-r--r--testsuite/systemtap.syscall/poll.c10
-rw-r--r--testsuite/systemtap.syscall/readwrite.c34
-rw-r--r--testsuite/systemtap.syscall/rt_signal.c12
-rw-r--r--testsuite/systemtap.syscall/select.c8
-rw-r--r--testsuite/systemtap.syscall/sendfile.c2
-rw-r--r--testsuite/systemtap.syscall/signal.c14
-rw-r--r--testsuite/systemtap.syscall/stat.c18
-rw-r--r--testsuite/systemtap.syscall/statfs.c6
-rw-r--r--[-rwxr-xr-x]testsuite/systemtap.syscall/swap.c12
-rw-r--r--testsuite/systemtap.syscall/sync.c6
-rw-r--r--testsuite/systemtap.syscall/syscall.exp12
-rwxr-xr-xtestsuite/systemtap.syscall/test-debug.tcl2
-rwxr-xr-xtestsuite/systemtap.syscall/test.tcl17
-rw-r--r--testsuite/systemtap.syscall/timer.c10
-rw-r--r--testsuite/systemtap.syscall/trunc.c4
-rw-r--r--testsuite/systemtap.syscall/uid.c32
-rw-r--r--testsuite/systemtap.syscall/uid16.c32
-rw-r--r--testsuite/systemtap.syscall/umask.c12
-rw-r--r--testsuite/systemtap.syscall/unlink.c12
-rw-r--r--translate.cxx181
-rw-r--r--util.cxx89
-rw-r--r--util.h4
377 files changed, 18229 insertions, 6949 deletions
diff --git a/.gitignore b/.gitignore
index 48ee168d..5869f401 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,10 +9,12 @@ gmon.out
config.h
config.log
config.status
-*.[158]
+*.[18]
+*.3stap
.deps
loc2c-test
run-stap
+run-staprun
stamp-h1
stap
staprun
diff --git a/.mailmap b/.mailmap
index 2bf15895..b55c9ee3 100644
--- a/.mailmap
+++ b/.mailmap
@@ -19,6 +19,7 @@ Graydon Hoare <graydon>
Hien Nguyen <hien>
Jim Keniston <kenistoj>
Josh Stone <jistone>
+Kai Meyer <kai@fiber.net>
Kent Sebastian <ksebasti>
Kevin Stafford <kevinrs>
K.Prasad <prasadkr>
diff --git a/AUTHORS b/AUTHORS
index 6a20ef72..46c1e008 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,6 +1,8 @@
Ananth N Mavinakayanahalli
+Andre Detsch
Anil Keshavamurthy
Anithra Janakiraman
+Breno Leitao
Charles Spirakis
Dan Horak
Dave Brolley
@@ -18,9 +20,13 @@ James Bottomley
Jim Keniston
Josh Stone
K.Prasad
+Kai Meyer
Kent Sebastian
Kevin Stafford
Li Guanglei
+Lubomir Rintel
+Mahesh J Salgaonkar
+Malte Nuhn
Mark McLoughlin
Mark Wielaard
Martin Hunt
@@ -31,12 +37,14 @@ Mike Mason
Nobuhiro Tachino
Phil Muldoon
Prerna Saxena
+Przemyslaw Pawelczyk
Rajan Arora
Roland McGrath
Shaohua Li
Srikar Dronamraju
Srinivasa DS
Stan Cox
+Sunzen Wang
Thang Nguyen
Theodore Ts'o
Tim Moore
diff --git a/Makefile.am b/Makefile.am
index 9681381d..35f9a68b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,29 +7,40 @@ AUTOMAKE_OPTIONS = no-dist foreign
pkglibexecdir = ${libexecdir}/${PACKAGE}
oldincludedir = ${includedir}/sys
-AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"'
+AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"'
AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wunused -Wformat=2 -W
AM_CXXFLAGS = -Wall -Werror
-man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 man/stapprobes.nfs.5 man/stapprobes.nfsd.5 man/stapprobes.pagefault.5 man/stapprobes.process.5 man/stapprobes.rpc.5 man/stapprobes.scsi.5 man/stapprobes.signal.5 man/stapprobes.socket.5 man/stapprobes.tcp.5 man/stapprobes.udp.5
+man_MANS = stap.1 \
+stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap \
+staprun.8 \
+man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap \
+man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap \
+man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap \
+man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap \
+man/stapprobes.signal.3stap man/stapprobes.socket.3stap \
+man/stapprobes.tcp.3stap man/stapprobes.udp.3stap
# see also configure.ac
bin_PROGRAMS = stap staprun
-bin_SCRIPTS = stap-report
+bin_SCRIPTS = stap-report stap-env stap-gen-cert stap-authorize-cert stap-authorize-signing-cert
oldinclude_HEADERS = includes/sys/sdt.h
if BUILD_SERVER
man_MANS += stap-server.8
bin_PROGRAMS += stap-client-connect stap-server-connect
bin_SCRIPTS += stap-client stap-serverd stap-server stap-find-servers \
stap-start-server stap-find-or-start-server stap-stop-server \
- stap-gen-server-cert stap-add-server-cert
+ stap-authorize-server-cert
endif
bin_SCRIPTS += dtrace
stap_SOURCES = main.cxx \
parse.cxx staptree.cxx elaborate.cxx translate.cxx \
tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \
- cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx
+ cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \
+ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \
+ tapset-perfmon.cxx tapset-mark.cxx tapset-itrace.cxx \
+ tapset-utrace.cxx task_finder.cxx
stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@
BUILT_SOURCES =
@@ -78,7 +89,11 @@ stap_CXXFLAGS = $(AM_CXXFLAGS) @PIECXXFLAGS@
stap_CPPFLAGS = $(AM_CPPFLAGS)
stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
-if BUILD_SERVER
+if HAVE_NSS
+stap_SOURCES += modsign.cxx nsscommon.c
+stap_CPPFLAGS += $(nss_CFLAGS) $(nspr_CFLAGS)
+stap_LDADD += -lnss3
+
stap_client_connect_LDFLAGS = $(AM_LDFLAGS)
stap_server_connect_LDFLAGS = $(AM_LDFLAGS)
endif
@@ -114,9 +129,10 @@ if BUILD_SERVER
install-exec-local: install-scripts
PHONIES += install-scripts
-install-scripts:
+# scripts should be installed before this rule is run
+install-scripts: install-binSCRIPTS
for f in $(bin_SCRIPTS); do \
- sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir)," $(DESTDIR)$(bindir)/$$f; \
+ sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=.*,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir)," $(DESTDIR)$(bindir)/$$f; \
done
endif
@@ -124,15 +140,21 @@ staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\
runtime/staprun/ctl.c runtime/staprun/common.c
staprun_CPPFLAGS = $(AM_CPPFLAGS)
-staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -DSINGLE_THREADED -fno-strict-aliasing
+staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -DSINGLE_THREADED -fno-strict-aliasing -fno-builtin-strftime
staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
staprun_LDADD = @PROCFLAGS@
+if HAVE_NSS
+staprun_SOURCES += runtime/staprun/modverify.c nsscommon.c
+staprun_CFLAGS += $(nss_CFLAGS) $(nspr_CFLAGS)
+staprun_LDADD += -lnss3
+endif
+
stapio_SOURCES = runtime/staprun/stapio.c \
runtime/staprun/mainloop.c runtime/staprun/common.c \
runtime/staprun/ctl.c \
runtime/staprun/relay.c runtime/staprun/relay_old.c
-stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -fno-strict-aliasing
+stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -fno-strict-aliasing -fno-builtin-strftime
stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
stapio_LDADD = @PROCFLAGS@ -lpthread
@@ -256,7 +278,7 @@ uninstall-local:
rm -rf $(DESTDIR)$(sysconfdir)/systemtap
# XXX: leaves behind man pages
-SUBDIRS = doc
+SUBDIRS = doc grapher
DIST_SUBDIRS = testsuite $(SUBDIRS)
check-local:
diff --git a/Makefile.in b/Makefile.in
index 73ef5bac..d111d397 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -39,40 +39,46 @@ bin_PROGRAMS = stap$(EXEEXT) staprun$(EXEEXT) $(am__EXEEXT_1)
@BUILD_SERVER_TRUE@am__append_2 = stap-client-connect stap-server-connect
@BUILD_SERVER_TRUE@am__append_3 = stap-client stap-serverd stap-server stap-find-servers \
@BUILD_SERVER_TRUE@ stap-start-server stap-find-or-start-server stap-stop-server \
-@BUILD_SERVER_TRUE@ stap-gen-server-cert stap-add-server-cert
+@BUILD_SERVER_TRUE@ stap-authorize-server-cert
-@BUILD_ELFUTILS_TRUE@am__append_4 = -Iinclude-elfutils
-@BUILD_ELFUTILS_TRUE@am__append_5 = -Llib-elfutils -Wl,-rpath-link,lib-elfutils \
+@HAVE_NSS_TRUE@am__append_4 = modsign.cxx nsscommon.c
+@HAVE_NSS_TRUE@am__append_5 = $(nss_CFLAGS) $(nspr_CFLAGS)
+@HAVE_NSS_TRUE@am__append_6 = -lnss3
+@BUILD_ELFUTILS_TRUE@am__append_7 = -Iinclude-elfutils
+@BUILD_ELFUTILS_TRUE@am__append_8 = -Llib-elfutils -Wl,-rpath-link,lib-elfutils \
@BUILD_ELFUTILS_TRUE@ -Wl,--enable-new-dtags,-rpath,$(pkglibdir)
-@BUILD_ELFUTILS_TRUE@am__append_6 = stamp-elfutils
-@BUILD_ELFUTILS_TRUE@am__append_7 = stamp-elfutils
-@BUILD_ELFUTILS_TRUE@am__append_8 = lib-elfutils/libdw.so
-@BUILD_ELFUTILS_TRUE@am__append_9 = install-elfutils
-@BUILD_SERVER_TRUE@am__append_10 = install-scripts
+@BUILD_ELFUTILS_TRUE@am__append_9 = stamp-elfutils
+@BUILD_ELFUTILS_TRUE@am__append_10 = stamp-elfutils
+@BUILD_ELFUTILS_TRUE@am__append_11 = lib-elfutils/libdw.so
+@BUILD_ELFUTILS_TRUE@am__append_12 = install-elfutils
+@BUILD_SERVER_TRUE@am__append_13 = install-scripts
+@HAVE_NSS_TRUE@am__append_14 = runtime/staprun/modverify.c nsscommon.c
+@HAVE_NSS_TRUE@am__append_15 = $(nss_CFLAGS) $(nspr_CFLAGS)
+@HAVE_NSS_TRUE@am__append_16 = -lnss3
pkglibexec_PROGRAMS = stapio$(EXEEXT)
noinst_PROGRAMS = loc2c-test$(EXEEXT)
subdir = .
DIST_COMMON = INSTALL NEWS README AUTHORS $(srcdir)/Makefile.in \
$(srcdir)/Makefile.am $(top_srcdir)/configure \
$(am__configure_deps) $(srcdir)/config.in $(srcdir)/stap.1.in \
- $(srcdir)/stapprobes.5.in $(srcdir)/stapfuncs.5.in \
- $(srcdir)/stapvars.5.in $(srcdir)/stapex.5.in \
+ $(srcdir)/stapprobes.3stap.in $(srcdir)/stapfuncs.3stap.in \
+ $(srcdir)/stapvars.3stap.in $(srcdir)/stapex.3stap.in \
$(srcdir)/staprun.8.in $(srcdir)/stap-server.8.in \
- $(top_srcdir)/man/stapprobes.iosched.5.in \
- $(top_srcdir)/man/stapprobes.netdev.5.in \
- $(top_srcdir)/man/stapprobes.nfs.5.in \
- $(top_srcdir)/man/stapprobes.nfsd.5.in \
- $(top_srcdir)/man/stapprobes.pagefault.5.in \
- $(top_srcdir)/man/stapprobes.process.5.in \
- $(top_srcdir)/man/stapprobes.rpc.5.in \
- $(top_srcdir)/man/stapprobes.scsi.5.in \
- $(top_srcdir)/man/stapprobes.signal.5.in \
- $(top_srcdir)/man/stapprobes.socket.5.in \
- $(top_srcdir)/man/stapprobes.tcp.5.in \
- $(top_srcdir)/man/stapprobes.udp.5.in \
+ $(top_srcdir)/man/stapprobes.iosched.3stap.in \
+ $(top_srcdir)/man/stapprobes.netdev.3stap.in \
+ $(top_srcdir)/man/stapprobes.nfs.3stap.in \
+ $(top_srcdir)/man/stapprobes.nfsd.3stap.in \
+ $(top_srcdir)/man/stapprobes.pagefault.3stap.in \
+ $(top_srcdir)/man/stapprobes.kprocess.3stap.in \
+ $(top_srcdir)/man/stapprobes.rpc.3stap.in \
+ $(top_srcdir)/man/stapprobes.scsi.3stap.in \
+ $(top_srcdir)/man/stapprobes.signal.3stap.in \
+ $(top_srcdir)/man/stapprobes.socket.3stap.in \
+ $(top_srcdir)/man/stapprobes.tcp.3stap.in \
+ $(top_srcdir)/man/stapprobes.udp.3stap.in \
$(top_srcdir)/initscript/systemtap.in $(srcdir)/run-stap.in \
- depcomp $(oldinclude_HEADERS)
+ $(srcdir)/run-staprun.in depcomp $(oldinclude_HEADERS)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
@@ -81,19 +87,20 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES = stap.1 stapprobes.5 stapfuncs.5 stapvars.5 \
- stapex.5 staprun.8 stap-server.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 initscript/systemtap run-stap
+CONFIG_CLEAN_FILES = stap.1 stapprobes.3stap stapfuncs.3stap \
+ stapvars.3stap stapex.3stap staprun.8 stap-server.8 \
+ man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap \
+ man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap \
+ man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap \
+ man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap \
+ man/stapprobes.signal.3stap man/stapprobes.socket.3stap \
+ man/stapprobes.tcp.3stap man/stapprobes.udp.3stap \
+ initscript/systemtap run-stap run-staprun
@BUILD_SERVER_TRUE@am__EXEEXT_1 = stap-client-connect$(EXEEXT) \
@BUILD_SERVER_TRUE@ stap-server-connect$(EXEEXT)
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" \
"$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \
- "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" \
+ "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man8dir)" \
"$(DESTDIR)$(oldincludedir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
pkglibexecPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
@@ -102,16 +109,23 @@ am_loc2c_test_OBJECTS = loc2c_test-loc2c-test.$(OBJEXT) \
loc2c_test-loc2c.$(OBJEXT)
loc2c_test_OBJECTS = $(am_loc2c_test_OBJECTS)
am__DEPENDENCIES_1 =
-loc2c_test_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+loc2c_test_DEPENDENCIES = $(am__DEPENDENCIES_2)
loc2c_test_LINK = $(CCLD) $(loc2c_test_CFLAGS) $(CFLAGS) \
$(loc2c_test_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_NSS_TRUE@am__objects_1 = stap-modsign.$(OBJEXT) \
+@HAVE_NSS_TRUE@ stap-nsscommon.$(OBJEXT)
am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \
stap-staptree.$(OBJEXT) stap-elaborate.$(OBJEXT) \
stap-translate.$(OBJEXT) stap-tapsets.$(OBJEXT) \
stap-buildrun.$(OBJEXT) stap-loc2c.$(OBJEXT) \
stap-hash.$(OBJEXT) stap-mdfour.$(OBJEXT) stap-cache.$(OBJEXT) \
stap-util.$(OBJEXT) stap-coveragedb.$(OBJEXT) \
- stap-dwarf_wrappers.$(OBJEXT)
+ stap-dwarf_wrappers.$(OBJEXT) stap-tapset-been.$(OBJEXT) \
+ stap-tapset-procfs.$(OBJEXT) stap-tapset-timers.$(OBJEXT) \
+ stap-tapset-perfmon.$(OBJEXT) stap-tapset-mark.$(OBJEXT) \
+ stap-tapset-itrace.$(OBJEXT) stap-tapset-utrace.$(OBJEXT) \
+ stap-task_finder.$(OBJEXT) $(am__objects_1)
stap_OBJECTS = $(am_stap_OBJECTS)
stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \
$(LDFLAGS) -o $@
@@ -132,11 +146,13 @@ stapio_OBJECTS = $(am_stapio_OBJECTS)
stapio_DEPENDENCIES =
stapio_LINK = $(CCLD) $(stapio_CFLAGS) $(CFLAGS) $(stapio_LDFLAGS) \
$(LDFLAGS) -o $@
+@HAVE_NSS_TRUE@am__objects_2 = staprun-modverify.$(OBJEXT) \
+@HAVE_NSS_TRUE@ staprun-nsscommon.$(OBJEXT)
am_staprun_OBJECTS = staprun-staprun.$(OBJEXT) \
staprun-staprun_funcs.$(OBJEXT) staprun-ctl.$(OBJEXT) \
- staprun-common.$(OBJEXT)
+ staprun-common.$(OBJEXT) $(am__objects_2)
staprun_OBJECTS = $(am_staprun_OBJECTS)
-staprun_DEPENDENCIES =
+staprun_DEPENDENCIES = $(am__DEPENDENCIES_1)
staprun_LINK = $(CCLD) $(staprun_CFLAGS) $(CFLAGS) $(staprun_LDFLAGS) \
$(LDFLAGS) -o $@
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
@@ -164,7 +180,7 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
installcheck-recursive installdirs-recursive pdf-recursive \
ps-recursive uninstall-recursive
man1dir = $(mandir)/man1
-man5dir = $(mandir)/man5
+man3dir = $(mandir)/man3
man8dir = $(mandir)/man8
NROFF = nroff
MANS = $(man_MANS)
@@ -204,6 +220,8 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@@ -229,6 +247,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PIECFLAGS = @PIECFLAGS@
PIECXXFLAGS = @PIECXXFLAGS@
PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
@@ -256,6 +275,7 @@ docdir = @docdir@
dvidir = @dvidir@
elfutils_abs_srcdir = @elfutils_abs_srcdir@
exec_prefix = @exec_prefix@
+have_certutil = @have_certutil@
have_dvips = @have_dvips@
have_latex = @have_latex@
have_latex2html = @have_latex2html@
@@ -294,24 +314,27 @@ top_srcdir = @top_srcdir@
# we don't maintain a ChangeLog, which makes us non-GNU -> foreign
AUTOMAKE_OPTIONS = no-dist foreign
pkglibexecdir = ${libexecdir}/${PACKAGE}
-AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"'
+AM_CPPFLAGS = -DBINDIR='"$(bindir)"' -DSYSCONFDIR='"$(sysconfdir)"' -DPKGDATADIR='"${pkgdatadir}"' -DPKGLIBDIR='"$(pkglibexecdir)"'
AM_CFLAGS = -D_GNU_SOURCE -fexceptions -Wall -Werror -Wunused -Wformat=2 -W
AM_CXXFLAGS = -Wall -Werror
-man_MANS = stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 \
- staprun.8 man/stapprobes.iosched.5 man/stapprobes.netdev.5 \
- man/stapprobes.nfs.5 man/stapprobes.nfsd.5 \
- man/stapprobes.pagefault.5 man/stapprobes.process.5 \
- man/stapprobes.rpc.5 man/stapprobes.scsi.5 \
- man/stapprobes.signal.5 man/stapprobes.socket.5 \
- man/stapprobes.tcp.5 man/stapprobes.udp.5 $(am__append_1)
-bin_SCRIPTS = stap-report $(am__append_3) dtrace
+man_MANS = stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap \
+ stapex.3stap staprun.8 man/stapprobes.iosched.3stap \
+ man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap \
+ man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap \
+ man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap \
+ man/stapprobes.scsi.3stap man/stapprobes.signal.3stap \
+ man/stapprobes.socket.3stap man/stapprobes.tcp.3stap \
+ man/stapprobes.udp.3stap $(am__append_1)
+bin_SCRIPTS = stap-report stap-env stap-gen-cert stap-authorize-cert \
+ stap-authorize-signing-cert $(am__append_3) dtrace
oldinclude_HEADERS = includes/sys/sdt.h
-stap_SOURCES = main.cxx \
- parse.cxx staptree.cxx elaborate.cxx translate.cxx \
- tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \
- cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx
-
-stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@
+stap_SOURCES = main.cxx parse.cxx staptree.cxx elaborate.cxx \
+ translate.cxx tapsets.cxx buildrun.cxx loc2c.c hash.cxx \
+ mdfour.c cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \
+ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \
+ tapset-perfmon.cxx tapset-mark.cxx tapset-itrace.cxx \
+ tapset-utrace.cxx task_finder.cxx $(am__append_4)
+stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ $(am__append_6)
# Arrange for git_version.h to be regenerated at every "make".
# Code fragment is based upon RadeonHD.am.
@@ -321,30 +344,32 @@ stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@
# of foo-bar.c if it is newer than the foo-bar.o file. Using noinst_foo_SOURCES
# instead of foo_SOURCES prevents shipping git_version.h in dist tarballs,
# which may cause false GIT_FOO readings.
-BUILT_SOURCES = git_version.stamp $(am__append_6)
-CLEANFILES = git_version.h $(am__append_7) $(pkglibexec_PROGRAMS)
-stap_DEPENDENCIES = $(am__append_8)
+BUILT_SOURCES = git_version.stamp $(am__append_9)
+CLEANFILES = git_version.h $(am__append_10) $(pkglibexec_PROGRAMS)
+stap_DEPENDENCIES = $(am__append_11)
GIT_VERSION_CMD = $(SHELL) $(top_srcdir)/git_version.sh
stap_CFLAGS = $(AM_CFLAGS) @PIECFLAGS@
stap_CXXFLAGS = $(AM_CXXFLAGS) @PIECXXFLAGS@
-stap_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_4)
-stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ $(am__append_5)
-@BUILD_SERVER_TRUE@stap_client_connect_LDFLAGS = $(AM_LDFLAGS)
-@BUILD_SERVER_TRUE@stap_server_connect_LDFLAGS = $(AM_LDFLAGS)
-PHONIES = $(am__append_9) $(am__append_10) dist-gzip
-staprun_SOURCES = runtime/staprun/staprun.c runtime/staprun/staprun_funcs.c\
- runtime/staprun/ctl.c runtime/staprun/common.c
-
+stap_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_5) $(am__append_7)
+stap_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@ $(am__append_8)
+@HAVE_NSS_TRUE@stap_client_connect_LDFLAGS = $(AM_LDFLAGS)
+@HAVE_NSS_TRUE@stap_server_connect_LDFLAGS = $(AM_LDFLAGS)
+PHONIES = $(am__append_12) $(am__append_13) dist-gzip
+staprun_SOURCES = runtime/staprun/staprun.c \
+ runtime/staprun/staprun_funcs.c runtime/staprun/ctl.c \
+ runtime/staprun/common.c $(am__append_14)
staprun_CPPFLAGS = $(AM_CPPFLAGS)
-staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -DSINGLE_THREADED -fno-strict-aliasing
+staprun_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ \
+ -DSINGLE_THREADED -fno-strict-aliasing -fno-builtin-strftime \
+ $(am__append_15)
staprun_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
-staprun_LDADD = @PROCFLAGS@
+staprun_LDADD = @PROCFLAGS@ $(am__append_16)
stapio_SOURCES = runtime/staprun/stapio.c \
runtime/staprun/mainloop.c runtime/staprun/common.c \
runtime/staprun/ctl.c \
runtime/staprun/relay.c runtime/staprun/relay_old.c
-stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -fno-strict-aliasing
+stapio_CFLAGS = @PROCFLAGS@ $(AM_CFLAGS) @PIECFLAGS@ -fno-strict-aliasing -fno-builtin-strftime
stapio_LDFLAGS = $(AM_LDFLAGS) @PIELDFLAGS@
stapio_LDADD = @PROCFLAGS@ -lpthread
@BUILD_SERVER_TRUE@stap_client_connect_SOURCES = stap-client-connect.c
@@ -368,7 +393,7 @@ EXAMPLE_SOURCE_DIR = $(srcdir)/testsuite/systemtap.examples
EXAMPLE_META_FILES = $(EXAMPLE_SOURCE_DIR)/*/*.meta
TEST_COV_DIR = coverage
# XXX: leaves behind man pages
-SUBDIRS = doc
+SUBDIRS = doc grapher
DIST_SUBDIRS = testsuite $(SUBDIRS)
# Any extra flags, such as:
@@ -432,46 +457,48 @@ distclean-hdr:
-rm -f config.h stamp-h1
stap.1: $(top_builddir)/config.status $(srcdir)/stap.1.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-stapprobes.5: $(top_builddir)/config.status $(srcdir)/stapprobes.5.in
+stapprobes.3stap: $(top_builddir)/config.status $(srcdir)/stapprobes.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-stapfuncs.5: $(top_builddir)/config.status $(srcdir)/stapfuncs.5.in
+stapfuncs.3stap: $(top_builddir)/config.status $(srcdir)/stapfuncs.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-stapvars.5: $(top_builddir)/config.status $(srcdir)/stapvars.5.in
+stapvars.3stap: $(top_builddir)/config.status $(srcdir)/stapvars.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-stapex.5: $(top_builddir)/config.status $(srcdir)/stapex.5.in
+stapex.3stap: $(top_builddir)/config.status $(srcdir)/stapex.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
staprun.8: $(top_builddir)/config.status $(srcdir)/staprun.8.in
cd $(top_builddir) && $(SHELL) ./config.status $@
stap-server.8: $(top_builddir)/config.status $(srcdir)/stap-server.8.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.iosched.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.iosched.5.in
+man/stapprobes.iosched.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.iosched.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.netdev.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.netdev.5.in
+man/stapprobes.netdev.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.netdev.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.nfs.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.nfs.5.in
+man/stapprobes.nfs.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.nfs.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.nfsd.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.nfsd.5.in
+man/stapprobes.nfsd.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.nfsd.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.pagefault.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.pagefault.5.in
+man/stapprobes.pagefault.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.pagefault.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.process.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.process.5.in
+man/stapprobes.kprocess.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.kprocess.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.rpc.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.rpc.5.in
+man/stapprobes.rpc.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.rpc.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.scsi.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.scsi.5.in
+man/stapprobes.scsi.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.scsi.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.signal.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.signal.5.in
+man/stapprobes.signal.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.signal.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.socket.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.socket.5.in
+man/stapprobes.socket.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.socket.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.tcp.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.tcp.5.in
+man/stapprobes.tcp.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.tcp.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
-man/stapprobes.udp.5: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.udp.5.in
+man/stapprobes.udp.3stap: $(top_builddir)/config.status $(top_srcdir)/man/stapprobes.udp.3stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
initscript/systemtap: $(top_builddir)/config.status $(top_srcdir)/initscript/systemtap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
run-stap: $(top_builddir)/config.status $(srcdir)/run-stap.in
cd $(top_builddir) && $(SHELL) ./config.status $@
+run-staprun: $(top_builddir)/config.status $(srcdir)/run-staprun.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@@ -576,9 +603,19 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-loc2c.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-mdfour.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-modsign.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-nsscommon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-parse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-staptree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-been.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-itrace.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-mark.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-perfmon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-procfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-timers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-utrace.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapsets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-task_finder.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-translate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap_client_connect-stap-client-connect.Po@am__quote@
@@ -591,6 +628,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stapio-stapio.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-modverify.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/staprun-nsscommon.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@
@@ -664,6 +703,20 @@ stap-mdfour.obj: mdfour.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CFLAGS) $(CFLAGS) -c -o stap-mdfour.obj `if test -f 'mdfour.c'; then $(CYGPATH_W) 'mdfour.c'; else $(CYGPATH_W) '$(srcdir)/mdfour.c'; fi`
+stap-nsscommon.o: nsscommon.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CFLAGS) $(CFLAGS) -MT stap-nsscommon.o -MD -MP -MF $(DEPDIR)/stap-nsscommon.Tpo -c -o stap-nsscommon.o `test -f 'nsscommon.c' || echo '$(srcdir)/'`nsscommon.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stap-nsscommon.Tpo $(DEPDIR)/stap-nsscommon.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nsscommon.c' object='stap-nsscommon.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CFLAGS) $(CFLAGS) -c -o stap-nsscommon.o `test -f 'nsscommon.c' || echo '$(srcdir)/'`nsscommon.c
+
+stap-nsscommon.obj: nsscommon.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CFLAGS) $(CFLAGS) -MT stap-nsscommon.obj -MD -MP -MF $(DEPDIR)/stap-nsscommon.Tpo -c -o stap-nsscommon.obj `if test -f 'nsscommon.c'; then $(CYGPATH_W) 'nsscommon.c'; else $(CYGPATH_W) '$(srcdir)/nsscommon.c'; fi`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stap-nsscommon.Tpo $(DEPDIR)/stap-nsscommon.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nsscommon.c' object='stap-nsscommon.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CFLAGS) $(CFLAGS) -c -o stap-nsscommon.obj `if test -f 'nsscommon.c'; then $(CYGPATH_W) 'nsscommon.c'; else $(CYGPATH_W) '$(srcdir)/nsscommon.c'; fi`
+
stap_client_connect-stap-client-connect.o: stap-client-connect.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stap_client_connect_CFLAGS) $(CFLAGS) -MT stap_client_connect-stap-client-connect.o -MD -MP -MF $(DEPDIR)/stap_client_connect-stap-client-connect.Tpo -c -o stap_client_connect-stap-client-connect.o `test -f 'stap-client-connect.c' || echo '$(srcdir)/'`stap-client-connect.c
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/stap_client_connect-stap-client-connect.Tpo $(DEPDIR)/stap_client_connect-stap-client-connect.Po
@@ -832,6 +885,34 @@ staprun-common.obj: runtime/staprun/common.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-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`
+staprun-modverify.o: runtime/staprun/modverify.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-modverify.o -MD -MP -MF $(DEPDIR)/staprun-modverify.Tpo -c -o staprun-modverify.o `test -f 'runtime/staprun/modverify.c' || echo '$(srcdir)/'`runtime/staprun/modverify.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-modverify.Tpo $(DEPDIR)/staprun-modverify.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/modverify.c' object='staprun-modverify.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-modverify.o `test -f 'runtime/staprun/modverify.c' || echo '$(srcdir)/'`runtime/staprun/modverify.c
+
+staprun-modverify.obj: runtime/staprun/modverify.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-modverify.obj -MD -MP -MF $(DEPDIR)/staprun-modverify.Tpo -c -o staprun-modverify.obj `if test -f 'runtime/staprun/modverify.c'; then $(CYGPATH_W) 'runtime/staprun/modverify.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/modverify.c'; fi`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-modverify.Tpo $(DEPDIR)/staprun-modverify.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/staprun/modverify.c' object='staprun-modverify.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-modverify.obj `if test -f 'runtime/staprun/modverify.c'; then $(CYGPATH_W) 'runtime/staprun/modverify.c'; else $(CYGPATH_W) '$(srcdir)/runtime/staprun/modverify.c'; fi`
+
+staprun-nsscommon.o: nsscommon.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-nsscommon.o -MD -MP -MF $(DEPDIR)/staprun-nsscommon.Tpo -c -o staprun-nsscommon.o `test -f 'nsscommon.c' || echo '$(srcdir)/'`nsscommon.c
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-nsscommon.Tpo $(DEPDIR)/staprun-nsscommon.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nsscommon.c' object='staprun-nsscommon.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-nsscommon.o `test -f 'nsscommon.c' || echo '$(srcdir)/'`nsscommon.c
+
+staprun-nsscommon.obj: nsscommon.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(staprun_CPPFLAGS) $(CPPFLAGS) $(staprun_CFLAGS) $(CFLAGS) -MT staprun-nsscommon.obj -MD -MP -MF $(DEPDIR)/staprun-nsscommon.Tpo -c -o staprun-nsscommon.obj `if test -f 'nsscommon.c'; then $(CYGPATH_W) 'nsscommon.c'; else $(CYGPATH_W) '$(srcdir)/nsscommon.c'; fi`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/staprun-nsscommon.Tpo $(DEPDIR)/staprun-nsscommon.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nsscommon.c' object='staprun-nsscommon.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-nsscommon.obj `if test -f 'nsscommon.c'; then $(CYGPATH_W) 'nsscommon.c'; else $(CYGPATH_W) '$(srcdir)/nsscommon.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
@@ -1013,6 +1094,132 @@ stap-dwarf_wrappers.obj: dwarf_wrappers.cxx
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dwarf_wrappers.cxx' object='stap-dwarf_wrappers.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-dwarf_wrappers.obj `if test -f 'dwarf_wrappers.cxx'; then $(CYGPATH_W) 'dwarf_wrappers.cxx'; else $(CYGPATH_W) '$(srcdir)/dwarf_wrappers.cxx'; fi`
+
+stap-tapset-been.o: tapset-been.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-been.o -MD -MP -MF $(DEPDIR)/stap-tapset-been.Tpo -c -o stap-tapset-been.o `test -f 'tapset-been.cxx' || echo '$(srcdir)/'`tapset-been.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-been.Tpo $(DEPDIR)/stap-tapset-been.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-been.cxx' object='stap-tapset-been.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-been.o `test -f 'tapset-been.cxx' || echo '$(srcdir)/'`tapset-been.cxx
+
+stap-tapset-been.obj: tapset-been.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-been.obj -MD -MP -MF $(DEPDIR)/stap-tapset-been.Tpo -c -o stap-tapset-been.obj `if test -f 'tapset-been.cxx'; then $(CYGPATH_W) 'tapset-been.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-been.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-been.Tpo $(DEPDIR)/stap-tapset-been.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-been.cxx' object='stap-tapset-been.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-been.obj `if test -f 'tapset-been.cxx'; then $(CYGPATH_W) 'tapset-been.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-been.cxx'; fi`
+
+stap-tapset-procfs.o: tapset-procfs.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-procfs.o -MD -MP -MF $(DEPDIR)/stap-tapset-procfs.Tpo -c -o stap-tapset-procfs.o `test -f 'tapset-procfs.cxx' || echo '$(srcdir)/'`tapset-procfs.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-procfs.Tpo $(DEPDIR)/stap-tapset-procfs.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-procfs.cxx' object='stap-tapset-procfs.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-procfs.o `test -f 'tapset-procfs.cxx' || echo '$(srcdir)/'`tapset-procfs.cxx
+
+stap-tapset-procfs.obj: tapset-procfs.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-procfs.obj -MD -MP -MF $(DEPDIR)/stap-tapset-procfs.Tpo -c -o stap-tapset-procfs.obj `if test -f 'tapset-procfs.cxx'; then $(CYGPATH_W) 'tapset-procfs.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-procfs.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-procfs.Tpo $(DEPDIR)/stap-tapset-procfs.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-procfs.cxx' object='stap-tapset-procfs.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-procfs.obj `if test -f 'tapset-procfs.cxx'; then $(CYGPATH_W) 'tapset-procfs.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-procfs.cxx'; fi`
+
+stap-tapset-timers.o: tapset-timers.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-timers.o -MD -MP -MF $(DEPDIR)/stap-tapset-timers.Tpo -c -o stap-tapset-timers.o `test -f 'tapset-timers.cxx' || echo '$(srcdir)/'`tapset-timers.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-timers.Tpo $(DEPDIR)/stap-tapset-timers.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-timers.cxx' object='stap-tapset-timers.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-timers.o `test -f 'tapset-timers.cxx' || echo '$(srcdir)/'`tapset-timers.cxx
+
+stap-tapset-timers.obj: tapset-timers.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-timers.obj -MD -MP -MF $(DEPDIR)/stap-tapset-timers.Tpo -c -o stap-tapset-timers.obj `if test -f 'tapset-timers.cxx'; then $(CYGPATH_W) 'tapset-timers.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-timers.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-timers.Tpo $(DEPDIR)/stap-tapset-timers.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-timers.cxx' object='stap-tapset-timers.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-timers.obj `if test -f 'tapset-timers.cxx'; then $(CYGPATH_W) 'tapset-timers.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-timers.cxx'; fi`
+
+stap-tapset-perfmon.o: tapset-perfmon.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-perfmon.o -MD -MP -MF $(DEPDIR)/stap-tapset-perfmon.Tpo -c -o stap-tapset-perfmon.o `test -f 'tapset-perfmon.cxx' || echo '$(srcdir)/'`tapset-perfmon.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-perfmon.Tpo $(DEPDIR)/stap-tapset-perfmon.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-perfmon.cxx' object='stap-tapset-perfmon.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-perfmon.o `test -f 'tapset-perfmon.cxx' || echo '$(srcdir)/'`tapset-perfmon.cxx
+
+stap-tapset-perfmon.obj: tapset-perfmon.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-perfmon.obj -MD -MP -MF $(DEPDIR)/stap-tapset-perfmon.Tpo -c -o stap-tapset-perfmon.obj `if test -f 'tapset-perfmon.cxx'; then $(CYGPATH_W) 'tapset-perfmon.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-perfmon.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-perfmon.Tpo $(DEPDIR)/stap-tapset-perfmon.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-perfmon.cxx' object='stap-tapset-perfmon.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-perfmon.obj `if test -f 'tapset-perfmon.cxx'; then $(CYGPATH_W) 'tapset-perfmon.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-perfmon.cxx'; fi`
+
+stap-tapset-mark.o: tapset-mark.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-mark.o -MD -MP -MF $(DEPDIR)/stap-tapset-mark.Tpo -c -o stap-tapset-mark.o `test -f 'tapset-mark.cxx' || echo '$(srcdir)/'`tapset-mark.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-mark.Tpo $(DEPDIR)/stap-tapset-mark.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-mark.cxx' object='stap-tapset-mark.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-mark.o `test -f 'tapset-mark.cxx' || echo '$(srcdir)/'`tapset-mark.cxx
+
+stap-tapset-mark.obj: tapset-mark.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-mark.obj -MD -MP -MF $(DEPDIR)/stap-tapset-mark.Tpo -c -o stap-tapset-mark.obj `if test -f 'tapset-mark.cxx'; then $(CYGPATH_W) 'tapset-mark.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-mark.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-mark.Tpo $(DEPDIR)/stap-tapset-mark.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-mark.cxx' object='stap-tapset-mark.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-mark.obj `if test -f 'tapset-mark.cxx'; then $(CYGPATH_W) 'tapset-mark.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-mark.cxx'; fi`
+
+stap-tapset-itrace.o: tapset-itrace.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-itrace.o -MD -MP -MF $(DEPDIR)/stap-tapset-itrace.Tpo -c -o stap-tapset-itrace.o `test -f 'tapset-itrace.cxx' || echo '$(srcdir)/'`tapset-itrace.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-itrace.Tpo $(DEPDIR)/stap-tapset-itrace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-itrace.cxx' object='stap-tapset-itrace.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-itrace.o `test -f 'tapset-itrace.cxx' || echo '$(srcdir)/'`tapset-itrace.cxx
+
+stap-tapset-itrace.obj: tapset-itrace.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-itrace.obj -MD -MP -MF $(DEPDIR)/stap-tapset-itrace.Tpo -c -o stap-tapset-itrace.obj `if test -f 'tapset-itrace.cxx'; then $(CYGPATH_W) 'tapset-itrace.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-itrace.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-itrace.Tpo $(DEPDIR)/stap-tapset-itrace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-itrace.cxx' object='stap-tapset-itrace.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-itrace.obj `if test -f 'tapset-itrace.cxx'; then $(CYGPATH_W) 'tapset-itrace.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-itrace.cxx'; fi`
+
+stap-tapset-utrace.o: tapset-utrace.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-utrace.o -MD -MP -MF $(DEPDIR)/stap-tapset-utrace.Tpo -c -o stap-tapset-utrace.o `test -f 'tapset-utrace.cxx' || echo '$(srcdir)/'`tapset-utrace.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-utrace.Tpo $(DEPDIR)/stap-tapset-utrace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-utrace.cxx' object='stap-tapset-utrace.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-utrace.o `test -f 'tapset-utrace.cxx' || echo '$(srcdir)/'`tapset-utrace.cxx
+
+stap-tapset-utrace.obj: tapset-utrace.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-utrace.obj -MD -MP -MF $(DEPDIR)/stap-tapset-utrace.Tpo -c -o stap-tapset-utrace.obj `if test -f 'tapset-utrace.cxx'; then $(CYGPATH_W) 'tapset-utrace.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-utrace.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-utrace.Tpo $(DEPDIR)/stap-tapset-utrace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-utrace.cxx' object='stap-tapset-utrace.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-utrace.obj `if test -f 'tapset-utrace.cxx'; then $(CYGPATH_W) 'tapset-utrace.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-utrace.cxx'; fi`
+
+stap-task_finder.o: task_finder.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-task_finder.o -MD -MP -MF $(DEPDIR)/stap-task_finder.Tpo -c -o stap-task_finder.o `test -f 'task_finder.cxx' || echo '$(srcdir)/'`task_finder.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-task_finder.Tpo $(DEPDIR)/stap-task_finder.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='task_finder.cxx' object='stap-task_finder.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-task_finder.o `test -f 'task_finder.cxx' || echo '$(srcdir)/'`task_finder.cxx
+
+stap-task_finder.obj: task_finder.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-task_finder.obj -MD -MP -MF $(DEPDIR)/stap-task_finder.Tpo -c -o stap-task_finder.obj `if test -f 'task_finder.cxx'; then $(CYGPATH_W) 'task_finder.cxx'; else $(CYGPATH_W) '$(srcdir)/task_finder.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-task_finder.Tpo $(DEPDIR)/stap-task_finder.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='task_finder.cxx' object='stap-task_finder.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-task_finder.obj `if test -f 'task_finder.cxx'; then $(CYGPATH_W) 'task_finder.cxx'; else $(CYGPATH_W) '$(srcdir)/task_finder.cxx'; fi`
+
+stap-modsign.o: modsign.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-modsign.o -MD -MP -MF $(DEPDIR)/stap-modsign.Tpo -c -o stap-modsign.o `test -f 'modsign.cxx' || echo '$(srcdir)/'`modsign.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-modsign.Tpo $(DEPDIR)/stap-modsign.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='modsign.cxx' object='stap-modsign.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-modsign.o `test -f 'modsign.cxx' || echo '$(srcdir)/'`modsign.cxx
+
+stap-modsign.obj: modsign.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-modsign.obj -MD -MP -MF $(DEPDIR)/stap-modsign.Tpo -c -o stap-modsign.obj `if test -f 'modsign.cxx'; then $(CYGPATH_W) 'modsign.cxx'; else $(CYGPATH_W) '$(srcdir)/modsign.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-modsign.Tpo $(DEPDIR)/stap-modsign.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='modsign.cxx' object='stap-modsign.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-modsign.obj `if test -f 'modsign.cxx'; then $(CYGPATH_W) 'modsign.cxx'; else $(CYGPATH_W) '$(srcdir)/modsign.cxx'; fi`
install-man1: $(man1_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
@@ -1058,14 +1265,14 @@ uninstall-man1:
echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
done
-install-man5: $(man5_MANS) $(man_MANS)
+install-man3: $(man3_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
- test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
- @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)"
+ @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
- *.5*) list="$$list $$i" ;; \
+ *.3*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
@@ -1073,35 +1280,35 @@ install-man5: $(man5_MANS) $(man_MANS)
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
- 5*) ;; \
- *) ext='5' ;; \
+ 3*) ;; \
+ *) ext='3' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
- $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \
done
-uninstall-man5:
+uninstall-man3:
@$(NORMAL_UNINSTALL)
- @list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
+ @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
- *.5*) list="$$list $$i" ;; \
+ *.3*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
- 5*) ;; \
- *) ext='5' ;; \
+ 3*) ;; \
+ *) ext='3' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
- echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
- rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
+ echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \
+ rm -f "$(DESTDIR)$(man3dir)/$$inst"; \
done
install-man8: $(man8_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
@@ -1241,8 +1448,8 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
@@ -1267,8 +1474,8 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
@@ -1278,12 +1485,13 @@ ctags: CTAGS
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
+ here=`pwd`; \
list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
@@ -1303,7 +1511,7 @@ all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(MANS) $(HEADERS) config.h \
all-local
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(oldincludedir)"; do \
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(oldincludedir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
@@ -1368,7 +1576,7 @@ install-html: install-html-recursive
install-info: install-info-recursive
-install-man: install-man1 install-man5 install-man8
+install-man: install-man1 install-man3 install-man8
install-pdf: install-pdf-recursive
@@ -1399,7 +1607,7 @@ uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \
uninstall-local uninstall-man uninstall-oldincludeHEADERS \
uninstall-pkglibexecPROGRAMS
-uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8
+uninstall-man: uninstall-man1 uninstall-man3 uninstall-man8
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
install-exec-am install-strip
@@ -1415,7 +1623,7 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8
install-data-local install-dvi install-dvi-am install-exec \
install-exec-am install-exec-hook install-exec-local \
install-html install-html-am install-info install-info-am \
- install-man install-man1 install-man5 install-man8 \
+ install-man install-man1 install-man3 install-man8 \
install-oldincludeHEADERS install-pdf install-pdf-am \
install-pkglibexecPROGRAMS install-ps install-ps-am \
install-strip installcheck installcheck-am installdirs \
@@ -1423,7 +1631,7 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-man8
mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
ps ps-am tags tags-recursive uninstall uninstall-am \
uninstall-binPROGRAMS uninstall-binSCRIPTS uninstall-local \
- uninstall-man uninstall-man1 uninstall-man5 uninstall-man8 \
+ uninstall-man uninstall-man1 uninstall-man3 uninstall-man8 \
uninstall-oldincludeHEADERS uninstall-pkglibexecPROGRAMS
git_version.stamp:
@@ -1465,9 +1673,10 @@ cscope:
@BUILD_ELFUTILS_TRUE@install-exec-local: install-elfutils
@BUILD_SERVER_TRUE@install-exec-local: install-scripts
-@BUILD_SERVER_TRUE@install-scripts:
+# scripts should be installed before this rule is run
+@BUILD_SERVER_TRUE@install-scripts: install-binSCRIPTS
@BUILD_SERVER_TRUE@ for f in $(bin_SCRIPTS); do \
-@BUILD_SERVER_TRUE@ sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir)," $(DESTDIR)$(bindir)/$$f; \
+@BUILD_SERVER_TRUE@ sed -i -e "/INSTALL-HOOK/d;s,exec_prefix=.*,exec_prefix=$(exec_prefix)/bin/,;s,sysconfdir=.*,sysconfdir=$(sysconfdir)," $(DESTDIR)$(bindir)/$$f; \
@BUILD_SERVER_TRUE@ done
install-exec-hook:
diff --git a/NEWS b/NEWS
index 74fd1df5..664753d3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,130 @@
* What's new
+- Module signing: If the appropriate nss libraries are available on your system,
+ stap will sign each compiled module using a self-generated certificate.
+ This is the first step toward extending authority to load certain modules to
+ unprivileged users. For now, if the system administrator adds a certificate
+ to a database of trusted signers (stap-authorize-signing-cert), modules signed
+ using that certificate will be verified by staprun against tampering.
+ Otherwise, you should notice no difference in the operation of stap or staprun.
+
+* What's new in version 0.9.7
+
+- @cast can now determine its type information using an explicit header
+ specification. For example:
+ @cast(tv, "timeval", "<sys/time.h>")->tv_sec
+ @cast(task, "task_struct", "kernel<linux/sched.h>")->tgid
+
+- The overlapping process.* tapsets are now separated. Those probe points
+ documented in stapprobes(3stap) remain the same. Those that were formerly
+ in stapprobes.process(3stap) have been renamed to kprocess, to reflect
+ their kernel perspective on processes.
+
+- The --skip-badvars option now also suppresses run-time error
+ messages that would otherwise result from erroneous memory accesses.
+ Such accesses can originate from $context expressions fueled by
+ erroneous debug data, or by kernel_{long,string,...}() tapset calls.
+
+- New probes kprobe.function(FUNCTION) and kprobe.function(FUNCTION).return
+ for dwarfless probing. These postpone function address resolution to
+ run-time and use the kprobe symbol-resolution mechanism.
+ Probing of absolute statements can be done using the
+ kprobe.statement(ADDRESS).absolute construct.
+
+- EXPERIMENTAL support for user process unwinding. A new collection of
+ tapset functions have been added to handle user space backtraces from
+ probe points that support them (currently process and timer probes -
+ for timer probes test whether or not in user space first with the
+ already existing user_mode() function). The new tapset functions are:
+ uaddr - User space address of current running task.
+ usymname - Return the symbol of an address in the current task.
+ usymdata - Return the symbol and module offset of an address.
+ print_ustack - Print out stack for the current task from string.
+ print_ubacktrace - Print stack back trace for current task.
+ ubacktrace - Hex backtrace of current task stack.
+ Please read http://sourceware.org/ml/systemtap/2009-q2/msg00364.html
+ on the current restrictions and possible changes in the future and
+ give feedback if you want to influence future developments.
+
+* What's new in version 0.9.5
+
+- New probes process().insn and process().insn.block that allows
+ inspection of the process after each instruction or block of
+ instructions executed. So to count the total number of instructions
+ a process executes during a run do something like:
+ $ stap -e 'global steps; probe process("/bin/ls").insn {steps++}
+ probe end {printf("Total instructions: %d\n", steps);}' \
+ -c /bin/ls
+ This feature can slow down execution of a process somewhat.
+
+- Systemtap probes and function man pages extracted from the tapsets
+ are now available under 3stap. To show the page for probe vm.pagefault
+ or the stap function pexecname do:
+ $ man 3stap vm.pagefault
+ $ man 3stap pexecname
+
+- Kernel tracepoints are now supported for probing predefined kernel
+ events without any debuginfo. Tracepoints incur less overhead than
+ kprobes, and context parameters are available with full type
+ information. Any kernel 2.6.28 and later should have defined
+ tracepoints. Try the following to see what's available:
+ $ stap -L 'kernel.trace("*")'
+
+- Typecasting with @cast now supports modules search paths, which is
+ useful in case there are multiple places where the type definition
+ may be found. For example:
+ @cast(sdev, "scsi_device", "kernel:scsi_mod")->sdev_state
+
+- On-file flight recorder is supported. It allows stap to record huge
+ trace log on the disk and to run in background.
+ Passing -F option with -o option runs stap in background mode. In this
+ mode, staprun is detached from console, and stap itself shows staprun's
+ pid and exits.
+ Specifying the max size and the max number of log files are also available
+ by passing -S option. This option has one or two arguments seperated by
+ a comma. The first argument is the max size of a log file in MB. If the
+ size of a log file exceeds it, stap switches to the next log file
+ automatically. The second is how many files are kept on the disk. If the
+ number of log files exceeds it, the oldest log file is removed
+ automatically. The second argument can be omitted.
+
+ For example, this will record output on log files each of them is smaller
+ than 1024MB and keep last 3 logs, in background.
+ % stap -F -o /tmp/staplog -S 1024,3 script.stp
+
+- In guru mode (-g), the kernel probing blacklist is disabled, leaving
+ only a subset - the kernel's own internal kprobe blacklist - to attempt
+ to filter out areas unsafe to probe. The differences may be enough to
+ probe more interrupt handlers.
+
- Variables unavailable in current context may be skipped by setting a
- session level flag with command line option --skip-badvars now available.
- This will simply substitute the otherwise error causing variable with a
- literal 0 and print a warning message when the substitution has been made.
+ session level flag with command line option --skip-badvars now available.
+ This replaces any dwarf $variable expressions that could not be resolved
+ with literal numeric zeros, along with a warning message.
+
+- Both kernel markers and kernel tracepoint support argument listing
+ through stap -L 'kernel.mark("*")' or stap -L 'kernel.trace("*")'
+
+- Users can use -DINTERRUPTIBLE=0 to prevent interrupt reentrancy in
+ their script, at the cost of a bit more overhead to toggle the
+ interrupt mask.
+
+- Added reentrancy debugging. If stap is run with the arguments
+ "-t -DDEBUG_REENTRANCY", additional warnings will be printed for
+ every reentrancy event, including the probe points of the
+ resident and interloper probes.
+
+- Default to --disable-pie for configure.
+ Use --enable-pie to turn it back on.
+
+- Improved sdt.h compatibility and test suite for static dtrace
+ compatible user space markers.
+
+- Some architectures now use syscall wrappers (HAVE_SYSCALL_WRAPPERS).
+ The syscall tapset has been enhanced to take care of the syscall
+ wrappers in this release.
+
+- Security fix for CVE-2009-0784: stapusr module-path checking race.
* What's new in version 0.9
diff --git a/README b/README
index 7c1ab412..ac6f0a97 100644
--- a/README
+++ b/README
@@ -106,3 +106,7 @@ Building a kernel.org kernel:
- Or else, if you wish to install the kernel build/debuginfo data into
a place where systemtap will find it without the "-r" option:
% ln -s /path/to/kernel/build/tree /lib/modules/RELEASE/build
+
+- Instead of using the "-r" option, you can also use the environment
+ variable SYSTEMTAP_RELEASE to direct systemtap to the kernel data.
+
diff --git a/aclocal.m4 b/aclocal.m4
index 0e2027cd..b64e85be 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,7 +1,7 @@
-# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.10 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2005, 2006 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -11,15 +11,170 @@
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
-m4_ifndef([AC_AUTOCONF_VERSION],
- [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(AC_AUTOCONF_VERSION, [2.61],,
-[m4_warning([this file was generated for autoconf 2.61.
-You have another version of autoconf. It may work, but is not guaranteed to.
-If you have problems, you may need to regenerate the build system entirely.
-To do so, use the procedure documented by the package, typically `autoreconf'.])])
+m4_if(m4_PACKAGE_VERSION, [2.61],,
+[m4_fatal([this file was generated for autoconf 2.61.
+You have another version of autoconf. If you want to use that,
+you should regenerate the build system entirely.], [63])])
-# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+ if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ else
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ fi
+else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [AC_MSG_RESULT([no])
+ $4])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
+ [$4])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -34,7 +189,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.10'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.10.1], [],
+m4_if([$1], [1.10], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -50,10 +205,8 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.10.1])dnl
-m4_ifndef([AC_AUTOCONF_VERSION],
- [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
+[AM_AUTOMAKE_VERSION([1.10])dnl
+_AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
@@ -348,7 +501,7 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
# 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 -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then
dirpart=`AS_DIRNAME("$mf")`
else
continue
@@ -396,13 +549,13 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2008 Free Software Foundation, Inc.
+# 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
-# serial 13
+# serial 12
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
@@ -507,17 +660,16 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJC],
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
-_am_arg=$1
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
- $_am_arg | $_am_arg:* )
+ $1 | $1:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
-echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
@@ -878,7 +1030,7 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])])
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
-# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# Prevent Automake from outputing VARIABLE = @VARIABLE@ in Makefile.in.
# This macro is traced by Automake.
AC_DEFUN([_AM_SUBST_NOTMAKE])
diff --git a/buildrun.cxx b/buildrun.cxx
index b9d648ef..54aa5d4f 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -10,6 +10,9 @@
#include "buildrun.h"
#include "session.h"
#include "util.h"
+#if HAVE_NSS
+#include "modsign.h"
+#endif
#include <cstdlib>
#include <fstream>
@@ -48,6 +51,12 @@ run_make_cmd(systemtap_session& s, string& make_cmd)
cerr << "unsetenv failed: " << e << endl;
}
+ // Disable ccache to avoid saving files that will never be reused.
+ // (ccache is useless to us, because our compiler commands always
+ // include the randomized tmpdir path.)
+ // It's not critical if this fails, so the return is ignored.
+ (void) setenv("CCACHE_DISABLE", "1", 0);
+
if (s.verbose > 2)
make_cmd += " V=1";
else if (s.verbose > 1)
@@ -56,8 +65,9 @@ run_make_cmd(systemtap_session& s, string& make_cmd)
make_cmd += " -s >/dev/null 2>&1";
if (s.verbose > 1) clog << "Running " << make_cmd << endl;
- rc = system (make_cmd.c_str());
-
+ rc = stap_system (make_cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return rc;
}
@@ -148,6 +158,8 @@ compile_pass (systemtap_session& s)
output_autoconf(s, o, "autoconf-vm-area.c", "STAPCONF_VM_AREA", NULL);
output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL);
output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL);
+ output_autoconf(s, o, "autoconf-find-task-pid.c", "STAPCONF_FIND_TASK_PID", NULL);
+ output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL);
#if 0
/* NB: For now, the performance hit of probe_kernel_read/write (vs. our
@@ -157,6 +169,8 @@ compile_pass (systemtap_session& s)
#endif
output_autoconf(s, o, "autoconf-save-stack-trace.c",
"STAPCONF_KERNEL_STACKTRACE", NULL);
+ output_autoconf(s, o, "autoconf-asm-syscall.c",
+ "STAPCONF_ASM_SYSCALL_H", NULL);
o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl;
@@ -208,6 +222,15 @@ compile_pass (systemtap_session& s)
rc = run_make_cmd(s, make_cmd);
+#if HAVE_NSS
+ // If a certificate database was specified, then try to sign the module.
+ // Failure to do so is not a fatal error. If the signature is actually needed,
+ // staprun will complain at that time.
+ assert (! s.cert_db_path.empty());
+ if (!rc)
+ sign_module (s);
+#endif
+
return rc;
}
@@ -221,7 +244,9 @@ kernel_built_uprobes (systemtap_session& s)
{
string grep_cmd = string ("/bin/grep -q unregister_uprobe ") +
s.kernel_build_tree + string ("/Module.symvers");
- int rc = system (grep_cmd.c_str());
+ int rc = stap_system (grep_cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return (rc == 0);
}
@@ -272,7 +297,9 @@ copy_uprobes_symbols (systemtap_session& s)
string uprobes_home = s.runtime_path + "/uprobes";
string cp_cmd = string("/bin/cp ") + uprobes_home +
string("/Module.symvers ") + s.tmpdir;
- int rc = system (cp_cmd.c_str());
+ int rc = stap_system (cp_cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return rc;
}
@@ -328,20 +355,25 @@ run_pass (systemtap_session& s)
staprun_cmd += "-u ";
if (s.load_only)
- staprun_cmd += "-L ";
+ staprun_cmd += (s.output_file.empty() ? "-L " : "-D ");
+
+ if (!s.size_option.empty())
+ staprun_cmd += "-S " + s.size_option + " ";
staprun_cmd += s.tmpdir + "/" + s.module_name + ".ko";
if (s.verbose>1) clog << "Running " << staprun_cmd << endl;
- rc = system (staprun_cmd.c_str ());
+ rc = stap_system (staprun_cmd.c_str ());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return rc;
}
// Build a tiny kernel module to query tracepoints
int
-make_tracequery(systemtap_session& s, string& name)
+make_tracequery(systemtap_session& s, string& name, const vector<string>& extra_headers)
{
// create a subdirectory for the module
string dir(s.tmpdir + "/tracequery");
@@ -357,14 +389,14 @@ make_tracequery(systemtap_session& s, string& name)
// create a simple Makefile
string makefile(dir + "/Makefile");
ofstream omf(makefile.c_str());
- omf << "EXTRA_CFLAGS := -g" << endl; // force debuginfo generation
+ // force debuginfo generation, and relax implicit functions
+ omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration" << endl;
omf << "obj-m := tracequery.o" << endl;
omf.close();
// create our source file
string source(dir + "/tracequery.c");
ofstream osrc(source.c_str());
- osrc << "#include <linux/module.h>" << endl;
osrc << "#ifdef CONFIG_TRACEPOINTS" << endl;
osrc << "#include <linux/tracepoint.h>" << endl;
@@ -378,30 +410,45 @@ make_tracequery(systemtap_session& s, string& name)
osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl;
osrc << " DECLARE_TRACE(name, TPPROTO(proto), TPARGS(args))" << endl;
+ // PR9993: Add extra headers to work around undeclared types in individual
+ // include/trace/foo.h files
+ for (unsigned z=0; z<extra_headers.size(); z++)
+ osrc << "#include <" << extra_headers[z] << ">\n";
+
// dynamically pull in all tracepoint headers from include/trace/
glob_t trace_glob;
- string glob_str(s.kernel_build_tree + "/include/trace/*.h");
- glob(glob_str.c_str(), 0, NULL, &trace_glob);
- for (unsigned i = 0; i < trace_glob.gl_pathc; ++i)
+ string globs[] = {
+ "/include/trace/*.h",
+ "/include/trace/events/*.h",
+ "/source/include/trace/*.h",
+ "/source/include/trace/events/*.h",
+ };
+ for (unsigned z = 0; z < sizeof(globs) / sizeof(globs[0]); z++)
{
- string header(basename(trace_glob.gl_pathv[i]));
-
- // filter out a few known "internal-only" headers
- if (header == "trace_events.h")
- continue;
- if (header.find("_event_types.h") != string::npos)
- continue;
-
- osrc << "#include <trace/" << header << ">" << endl;
+ string glob_str(s.kernel_build_tree + globs[z]);
+ glob(glob_str.c_str(), 0, NULL, &trace_glob);
+ for (unsigned i = 0; i < trace_glob.gl_pathc; ++i)
+ {
+ string header(trace_glob.gl_pathv[i]);
+ size_t root_pos = header.rfind("/include/");
+ assert(root_pos != string::npos);
+ header.erase(0, root_pos + 9);
+
+ // filter out a few known "internal-only" headers
+ if (header.find("/ftrace.h") != string::npos)
+ continue;
+ if (header.find("/trace_events.h") != string::npos)
+ continue;
+ if (header.find("_event_types.h") != string::npos)
+ continue;
+
+ osrc << "#include <" << header << ">" << endl;
+ }
+ globfree(&trace_glob);
}
- globfree(&trace_glob);
// finish up the module source
osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
- osrc << "int init_module(void) { return 0; }" << endl;
- osrc << "void cleanup_module(void) {}" << endl;
- osrc << "MODULE_DESCRIPTION(\"tracepoint query\");" << endl;
- osrc << "MODULE_LICENSE(\"GPL\");" << endl;
osrc.close();
// make the module
@@ -412,4 +459,107 @@ make_tracequery(systemtap_session& s, string& name)
return run_make_cmd(s, make_cmd);
}
+
+// Build a tiny kernel module to query type information
+static int
+make_typequery_kmod(systemtap_session& s, const string& header, string& name)
+{
+ static unsigned tick = 0;
+ string basename("typequery_kmod_" + lex_cast<string>(++tick));
+
+ // create a subdirectory for the module
+ string dir(s.tmpdir + "/" + basename);
+ if (create_dir(dir.c_str()) != 0)
+ {
+ if (! s.suppress_warnings)
+ cerr << "Warning: failed to create directory for querying types." << endl;
+ return 1;
+ }
+
+ name = dir + "/" + basename + ".ko";
+
+ // create a simple Makefile
+ string makefile(dir + "/Makefile");
+ ofstream omf(makefile.c_str());
+ omf << "EXTRA_CFLAGS := -g -fno-eliminate-unused-debug-types" << endl;
+
+ // NB: We use -include instead of #include because that gives us more power.
+ // Using #include searches relative to the source's path, which in this case
+ // is /tmp/..., so that's not helpful. Using -include will search relative
+ // to the cwd, which will be the kernel build root. This means if you have a
+ // full kernel build tree, it's possible to get at types that aren't in the
+ // normal include path, e.g.:
+ // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->...
+ omf << "CFLAGS_" << basename << ".o := -include " << header << endl;
+
+ omf << "obj-m := " + basename + ".o" << endl;
+ omf.close();
+
+ // create our empty source file
+ string source(dir + "/" + basename + ".c");
+ ofstream osrc(source.c_str());
+ osrc.close();
+
+ // make the module
+ string make_cmd = "make -C '" + s.kernel_build_tree + "'"
+ + " M='" + dir + "' modules";
+ if (s.verbose < 4)
+ make_cmd += " >/dev/null 2>&1";
+ return run_make_cmd(s, make_cmd);
+}
+
+
+// Build a tiny user module to query type information
+static int
+make_typequery_umod(systemtap_session& s, const string& header, string& name)
+{
+ static unsigned tick = 0;
+
+ name = s.tmpdir + "/typequery_umod_" + lex_cast<string>(++tick) + ".so";
+
+ // make the module
+ //
+ // NB: As with kmod, using -include makes relative paths more useful. The
+ // cwd in this case will be the cwd of stap itself though, which may be
+ // trickier to deal with. It might be better to "cd `dirname $script`"
+ // first...
+ string cmd = "gcc -shared -g -fno-eliminate-unused-debug-types -o "
+ + name + " -xc /dev/null -include " + header;
+ if (s.verbose < 4)
+ cmd += " >/dev/null 2>&1";
+ int rc = stap_system (cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
+ return rc;
+}
+
+
+int
+make_typequery(systemtap_session& s, string& module)
+{
+ int rc;
+ string new_module;
+
+ if (module[module.size() - 1] != '>')
+ return -1;
+
+ if (module[0] == '<')
+ {
+ string header = module.substr(1, module.size() - 2);
+ rc = make_typequery_umod(s, header, new_module);
+ }
+ else if (module.compare(0, 7, "kernel<") == 0)
+ {
+ string header = module.substr(7, module.size() - 8);
+ rc = make_typequery_kmod(s, header, new_module);
+ }
+ else
+ return -1;
+
+ if (!rc)
+ module = new_module;
+
+ return rc;
+}
+
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/buildrun.h b/buildrun.h
index 88127449..7fa4ccfc 100644
--- a/buildrun.h
+++ b/buildrun.h
@@ -14,7 +14,9 @@
int compile_pass (systemtap_session& s);
int run_pass (systemtap_session& s);
-int make_tracequery(systemtap_session& s, std::string& name);
+int make_tracequery(systemtap_session& s, std::string& name,
+ const std::vector<std::string>& extra_headers);
+int make_typequery(systemtap_session& s, std::string& module);
#endif // BUILDRUN_H
diff --git a/cache.cxx b/cache.cxx
index 86f7213a..bfe2b527 100644
--- a/cache.cxx
+++ b/cache.cxx
@@ -1,12 +1,12 @@
// systemtap cache manager
-// Copyright (C) 2006-2008 Red Hat Inc.
+// Copyright (C) 2006-2009 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 "config.h"
#include "session.h"
#include "cache.h"
#include "util.h"
@@ -14,6 +14,7 @@
#include <string>
#include <fstream>
#include <cstring>
+#include <cassert>
extern "C" {
#include <sys/types.h>
@@ -68,6 +69,29 @@ add_to_cache(systemtap_session& s)
return;
}
+#if HAVE_NSS
+ // This is the name of the cached module signature.
+ string module_signature_dest_path = s.hash_path;
+ module_signature_dest_path += ".sgn";
+
+ // Copy the module signature.
+ assert (! s.cert_db_path.empty());
+ string module_signature_src_path = module_src_path;
+ module_signature_src_path += ".sgn";
+
+ if (s.verbose > 1)
+ clog << "Copying " << module_signature_src_path << " to " << module_signature_dest_path << endl;
+ if (copy_file(module_signature_src_path.c_str(), module_signature_dest_path.c_str()) != 0)
+ {
+ cerr << "Copy failed (\"" << module_signature_src_path << "\" to \""
+ << module_signature_dest_path << "\"): " << strerror(errno) << endl;
+ // NB: this is not so severe as to prevent reuse of the .ko
+ // already copied.
+ //
+ // s.use_cache = false;
+ }
+#endif /* HAVE_NSS */
+
string c_dest_path = s.hash_path;
if (c_dest_path.rfind(".ko") == (c_dest_path.size() - 3))
c_dest_path.resize(c_dest_path.size() - 3);
@@ -98,6 +122,10 @@ get_from_cache(systemtap_session& s)
string module_dest_path = s.tmpdir + "/" + s.module_name + ".ko";
string c_src_path = s.hash_path;
int fd_stapconf, fd_module, fd_c;
+#if HAVE_NSS
+ string hash_signature_path = s.hash_path + ".sgn";
+ int fd_signature;
+#endif
if (c_src_path.rfind(".ko") == (c_src_path.size() - 3))
c_src_path.resize(c_src_path.size() - 3);
@@ -167,6 +195,24 @@ get_from_cache(systemtap_session& s)
close(fd_c);
return false;
}
+#if HAVE_NSS
+ // See if module signature exists. It's not an error if it doesn't. It just
+ // means that the module is unsigned.
+ fd_signature = open(hash_signature_path.c_str(), O_RDONLY);
+ if (fd_signature != -1) {
+ string signature_dest_path = module_dest_path + ".sgn";
+ close(fd_signature);
+ if (copy_file(hash_signature_path.c_str(), signature_dest_path.c_str()) != 0)
+ {
+ cerr << "Copy failed (\"" << hash_signature_path << "\" to \""
+ << signature_dest_path << "\"): " << strerror(errno) << endl;
+ unlink(c_src_path.c_str());
+ close(fd_module);
+ close(fd_c);
+ return false;
+ }
+ }
+#endif
}
// We're done with these file handles.
@@ -253,14 +299,28 @@ clean_cache(systemtap_session& s)
globfree(&cache_glob);
+ //grab info for each typequery user module (.so)
+ glob_str = s.cache_path + "/*/*.so";
+ glob(glob_str.c_str(), 0, NULL, &cache_glob);
+ for (unsigned int i = 0; i < cache_glob.gl_pathc; i++)
+ {
+ string cache_ent_path = cache_glob.gl_pathv[i];
+ struct cache_ent_info cur_info(cache_ent_path, false);
+ if (cur_info.size != 0 && cur_info.weight != 0)
+ {
+ cache_size_b += cur_info.size;
+ cache_contents.insert(cur_info);
+ }
+ }
+
+ globfree(&cache_glob);
+
//grab info for each stapconf cache entry (.h)
glob_str = s.cache_path + "/*/*.h";
glob(glob_str.c_str(), 0, NULL, &cache_glob);
for (unsigned int i = 0; i < cache_glob.gl_pathc; i++)
{
string cache_ent_path = cache_glob.gl_pathv[i];
- cache_ent_path.resize(cache_ent_path.length() - 3);
-
struct cache_ent_info cur_info(cache_ent_path, false);
if (cur_info.size != 0 && cur_info.weight != 0)
{
diff --git a/config.in b/config.in
index 74b5a738..dc6be35c 100644
--- a/config.in
+++ b/config.in
@@ -27,6 +27,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
+/* Define to 1 if you have the nss libraries. */
+#undef HAVE_NSS
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
diff --git a/configure b/configure
index 779dd4de..629d2dac 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for systemtap 0.9.
+# Generated by GNU Autoconf 2.61 for systemtap 0.9.7.
#
# Report bugs to <systemtap@sources.redhat.com>.
#
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='systemtap'
PACKAGE_TARNAME='systemtap'
-PACKAGE_VERSION='0.9'
-PACKAGE_STRING='systemtap 0.9'
+PACKAGE_VERSION='0.9.7'
+PACKAGE_STRING='systemtap 0.9.7'
PACKAGE_BUGREPORT='systemtap@sources.redhat.com'
# Factoring default headers for most tests.
@@ -722,10 +722,20 @@ BUILD_DOCS_FALSE
have_xmlto
BUILD_REFDOCS_TRUE
BUILD_REFDOCS_FALSE
+BUILD_PDFREFDOCS_TRUE
+BUILD_PDFREFDOCS_FALSE
+have_certutil
nss_CFLAGS
nspr_CFLAGS
BUILD_SERVER_TRUE
BUILD_SERVER_FALSE
+HAVE_NSS_TRUE
+HAVE_NSS_FALSE
+PKG_CONFIG
+GRAPHER_CFLAGS
+GRAPHER_LIBS
+BUILD_GRAPHER_TRUE
+BUILD_GRAPHER_FALSE
BUILD_ELFUTILS_TRUE
BUILD_ELFUTILS_FALSE
elfutils_abs_srcdir
@@ -749,6 +759,9 @@ CXX
CXXFLAGS
CCC
CPP
+PKG_CONFIG
+GRAPHER_CFLAGS
+GRAPHER_LIBS
CXXCPP'
ac_subdirs_all='testsuite'
@@ -1252,7 +1265,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures systemtap 0.9 to adapt to many kinds of systems.
+\`configure' configures systemtap 0.9.7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1318,7 +1331,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of systemtap 0.9:";;
+ short | recursive ) echo "Configuration of systemtap 0.9.7:";;
esac
cat <<\_ACEOF
@@ -1336,7 +1349,7 @@ Optional Features:
location).
--enable-prologues make -P prologue-searching default
--disable-ssp disable gcc stack-protector
- --disable-pie disable position-independent-executable
+ --enable-pie enable position-independent-executable
--enable-sqlite build with sqlite support
--enable-crash[=DIRECTORY]
enable crash extension (default is disabled).
@@ -1349,6 +1362,8 @@ Optional Features:
if xmlto etc. found and other documentation built).
--enable-server enable building of stap-server/client (default on if
nss etc. found).
+ --enable-grapher enable building of grapher (default on if gtkmm is
+ found).
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -1367,6 +1382,11 @@ Some influential environment variables:
CXX C++ compiler command
CXXFLAGS C++ compiler flags
CPP C preprocessor
+ PKG_CONFIG path to pkg-config utility
+ GRAPHER_CFLAGS
+ C compiler flags for GRAPHER, overriding pkg-config
+ GRAPHER_LIBS
+ linker flags for GRAPHER, overriding pkg-config
CXXCPP C++ preprocessor
Use these variables to override the choices made by `configure' or to help
@@ -1433,7 +1453,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-systemtap configure 0.9
+systemtap configure 0.9.7
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1447,7 +1467,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by systemtap $as_me 0.9, which was
+It was created by systemtap $as_me 0.9.7, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@@ -2139,7 +2159,7 @@ fi
# Define the identity of the package.
PACKAGE='systemtap'
- VERSION='0.9'
+ VERSION='0.9.7'
cat >>confdefs.h <<_ACEOF
@@ -5990,12 +6010,13 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
+# Compiling without fPIE by default (see PR 9922)
# Check whether --enable-pie was given.
if test "${enable_pie+set}" = set; then
enableval=$enable_pie;
fi
-if test "x$enable_pie" != xno; then
+if test "x$enable_pie" == xyes; then
save_CFLAGS="$CFLAGS"
save_CXXFLAGS="$CXXFLAGS"
@@ -6471,7 +6492,26 @@ echo "${ECHO_T}no" >&6; }
fi
-if test "x${have_xmlto}" == "xyes"; then
+if test "$enable_refdocs" == "yes"; then
+ if test "x${have_xmlto}" != "xyes"; then
+ { { echo "$as_me:$LINENO: error: cannot find xmlto for building reference documentation" >&5
+echo "$as_me: error: cannot find xmlto for building reference documentation" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+fi
+if test "x${have_xmlto}" == "xyes" -a "$enable_refdocs" != "no" -a "${building_docs}" == "yes"; then
+ building_refdocs="yes"
+fi
+ if test "$building_refdocs" == "yes"; then
+ BUILD_REFDOCS_TRUE=
+ BUILD_REFDOCS_FALSE='#'
+else
+ BUILD_REFDOCS_TRUE='#'
+ BUILD_REFDOCS_FALSE=
+fi
+
+
+if test "x${building_refdocs}" == "xyes"; then
{ echo "$as_me:$LINENO: checking for xmlto pdf support" >&5
echo $ECHO_N "checking for xmlto pdf support... $ECHO_C" >&6; }
cat > conftest.$ac_ext << EOF
@@ -6479,6 +6519,9 @@ cat > conftest.$ac_ext << EOF
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" >
<book id="pdffromxml">
+ <bookinfo>
+ <title>test</title>
+ </bookinfo>
</book>
EOF
xmlto pdf conftest.$ac_ext >& /dev/null
@@ -6489,24 +6532,16 @@ echo "${ECHO_T}yes" >&6; }
else
{ echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6; }
+ { echo "$as_me:$LINENO: WARNING: Not building reference documentation in PDF format" >&5
+echo "$as_me: WARNING: Not building reference documentation in PDF format" >&2;}
fi
fi
-if test "$enable_refdocs" == "yes"; then
- if test "x${have_xmlto}${have_xmlto_pdf}" != "xyesyes"; then
- { { echo "$as_me:$LINENO: error: cannot find proper yxmlto for building reference documentation" >&5
-echo "$as_me: error: cannot find proper yxmlto for building reference documentation" >&2;}
- { (exit 1); exit 1; }; }
- fi
-fi
-if test "x${have_xmlto}${have_xmlto_pdf}" == "xyesyes" -a "$enable_refdocs" != "no" -a "${building_docs}" == "yes"; then
- building_refdocs="yes"
-fi
- if test "$building_refdocs" == "yes"; then
- BUILD_REFDOCS_TRUE=
- BUILD_REFDOCS_FALSE='#'
+ if test "have_xmlto_pdf" == "yes"; then
+ BUILD_PDFREFDOCS_TRUE=
+ BUILD_PDFREFDOCS_FALSE='#'
else
- BUILD_REFDOCS_TRUE='#'
- BUILD_REFDOCS_FALSE=
+ BUILD_PDFREFDOCS_TRUE='#'
+ BUILD_PDFREFDOCS_FALSE=
fi
@@ -6517,6 +6552,44 @@ else
enable_server="check"
fi
+# Extract the first word of "certutil", so it can be a program name with args.
+set dummy certutil; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_have_certutil+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$have_certutil"; then
+ ac_cv_prog_have_certutil="$have_certutil" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_have_certutil="yes"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_have_certutil" && ac_cv_prog_have_certutil="no"
+fi
+fi
+have_certutil=$ac_cv_prog_have_certutil
+if test -n "$have_certutil"; then
+ { echo "$as_me:$LINENO: result: $have_certutil" >&5
+echo "${ECHO_T}$have_certutil" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
{ echo "$as_me:$LINENO: checking for /usr/include/nss3" >&5
echo $ECHO_N "checking for /usr/include/nss3... $ECHO_C" >&6; }
if test "${ac_cv_file__usr_include_nss3+set}" = set; then
@@ -6901,18 +6974,24 @@ fi
fi
fi
-if test "x${have_nss_includes}${have_nss_libs}" != "xyesyes"; then
+if test "x${have_nss_includes}${have_nss_libs}${have_certutil}" != "xyesyesyes"; then
if test "$enable_server" == "yes"; then
- { { echo "$as_me:$LINENO: error: cannot find all libraries for stap-server" >&5
-echo "$as_me: error: cannot find all libraries for stap-server" >&2;}
+ { { echo "$as_me:$LINENO: error: cannot find all libraries or tools for stap-server" >&5
+echo "$as_me: error: cannot find all libraries or tools for stap-server" >&2;}
{ (exit 1); exit 1; }; }
fi
if test "$enable_server" == "check"; then
- { echo "$as_me:$LINENO: WARNING: will not build stap-server, cannot find all libraries" >&5
-echo "$as_me: WARNING: will not build stap-server, cannot find all libraries" >&2;}
+ { echo "$as_me:$LINENO: WARNING: will not build stap-server, cannot find all libraries or tools" >&5
+echo "$as_me: WARNING: will not build stap-server, cannot find all libraries or tools" >&2;}
fi
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_NSS 1
+_ACEOF
+
fi
- if test "x${have_nss_includes}${have_nss_libs}" == "xyesyes" -a "$enable_server" != "no"; then
+ if test "x${have_nss_includes}${have_nss_libs}${have_certutil}" == "xyesyesyes" -a "$enable_server" != "no"; then
BUILD_SERVER_TRUE=
BUILD_SERVER_FALSE='#'
else
@@ -6920,6 +6999,221 @@ else
BUILD_SERVER_FALSE=
fi
+ if test "x${have_nss_includes}${have_nss_libs}${have_certutil}" == "xyesyesyes"; then
+ HAVE_NSS_TRUE=
+ HAVE_NSS_FALSE='#'
+else
+ HAVE_NSS_TRUE='#'
+ HAVE_NSS_FALSE=
+fi
+
+
+# Check whether --enable-grapher was given.
+if test "${enable_grapher+set}" = set; then
+ enableval=$enable_grapher; enable_grapher=$enableval
+else
+ enable_grapher="check"
+fi
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5
+echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5
+echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ PKG_CONFIG=""
+ fi
+
+fi
+
+pkg_failed=no
+{ echo "$as_me:$LINENO: checking for GRAPHER" >&5
+echo $ECHO_N "checking for GRAPHER... $ECHO_C" >&6; }
+
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GRAPHER_CFLAGS"; then
+ pkg_cv_GRAPHER_CFLAGS="$GRAPHER_CFLAGS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GRAPHER_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.8.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+ if test -n "$GRAPHER_LIBS"; then
+ pkg_cv_GRAPHER_LIBS="$GRAPHER_LIBS"
+ else
+ if test -n "$PKG_CONFIG" && \
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ pkg_cv_GRAPHER_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.8.0" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ fi
+else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GRAPHER_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"`
+ else
+ GRAPHER_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GRAPHER_PKG_ERRORS" >&5
+
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+ have_gtkmm=no
+elif test $pkg_failed = untried; then
+ have_gtkmm=no
+else
+ GRAPHER_CFLAGS=$pkg_cv_GRAPHER_CFLAGS
+ GRAPHER_LIBS=$pkg_cv_GRAPHER_LIBS
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+ have_gtkmm=yes
+fi
+ if test "x${have_gtkmm}" == "xyes" -a x"$enable_grapher" != "xno"; then
+ BUILD_GRAPHER_TRUE=
+ BUILD_GRAPHER_FALSE='#'
+else
+ BUILD_GRAPHER_TRUE='#'
+ BUILD_GRAPHER_FALSE=
+fi
+
build_elfutils=no
@@ -7859,12 +8153,14 @@ _ACEOF
ac_config_headers="$ac_config_headers config.h:config.in"
-ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 stap-server.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 initscript/systemtap"
+ac_config_files="$ac_config_files Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile grapher/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap"
subdirs="$subdirs testsuite"
ac_config_files="$ac_config_files run-stap"
+ac_config_files="$ac_config_files run-staprun"
+
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -8017,6 +8313,13 @@ echo "$as_me: error: conditional \"BUILD_REFDOCS\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${BUILD_PDFREFDOCS_TRUE}" && test -z "${BUILD_PDFREFDOCS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"BUILD_PDFREFDOCS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"BUILD_PDFREFDOCS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
if test -z "${BUILD_SERVER_TRUE}" && test -z "${BUILD_SERVER_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"BUILD_SERVER\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
@@ -8024,6 +8327,20 @@ echo "$as_me: error: conditional \"BUILD_SERVER\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${HAVE_NSS_TRUE}" && test -z "${HAVE_NSS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"HAVE_NSS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"HAVE_NSS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${BUILD_GRAPHER_TRUE}" && test -z "${BUILD_GRAPHER_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"BUILD_GRAPHER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"BUILD_GRAPHER\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
if test -z "${BUILD_ELFUTILS_TRUE}" && test -z "${BUILD_ELFUTILS_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"BUILD_ELFUTILS\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
@@ -8331,7 +8648,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by systemtap $as_me 0.9, which was
+This file was extended by systemtap $as_me 0.9.7, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -8384,7 +8701,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-systemtap config.status 0.9
+systemtap config.status 0.9.7
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
@@ -8503,27 +8820,29 @@ do
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"doc/SystemTap_Tapset_Reference/Makefile") CONFIG_FILES="$CONFIG_FILES doc/SystemTap_Tapset_Reference/Makefile" ;;
+ "grapher/Makefile") CONFIG_FILES="$CONFIG_FILES grapher/Makefile" ;;
"stap.1") CONFIG_FILES="$CONFIG_FILES stap.1" ;;
- "stapprobes.5") CONFIG_FILES="$CONFIG_FILES stapprobes.5" ;;
- "stapfuncs.5") CONFIG_FILES="$CONFIG_FILES stapfuncs.5" ;;
- "stapvars.5") CONFIG_FILES="$CONFIG_FILES stapvars.5" ;;
- "stapex.5") CONFIG_FILES="$CONFIG_FILES stapex.5" ;;
+ "stapprobes.3stap") CONFIG_FILES="$CONFIG_FILES stapprobes.3stap" ;;
+ "stapfuncs.3stap") CONFIG_FILES="$CONFIG_FILES stapfuncs.3stap" ;;
+ "stapvars.3stap") CONFIG_FILES="$CONFIG_FILES stapvars.3stap" ;;
+ "stapex.3stap") CONFIG_FILES="$CONFIG_FILES stapex.3stap" ;;
"staprun.8") CONFIG_FILES="$CONFIG_FILES staprun.8" ;;
"stap-server.8") CONFIG_FILES="$CONFIG_FILES stap-server.8" ;;
- "man/stapprobes.iosched.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.iosched.5" ;;
- "man/stapprobes.netdev.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.netdev.5" ;;
- "man/stapprobes.nfs.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.nfs.5" ;;
- "man/stapprobes.nfsd.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.nfsd.5" ;;
- "man/stapprobes.pagefault.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.pagefault.5" ;;
- "man/stapprobes.process.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.process.5" ;;
- "man/stapprobes.rpc.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.rpc.5" ;;
- "man/stapprobes.scsi.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.scsi.5" ;;
- "man/stapprobes.signal.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.signal.5" ;;
- "man/stapprobes.socket.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.socket.5" ;;
- "man/stapprobes.tcp.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.tcp.5" ;;
- "man/stapprobes.udp.5") CONFIG_FILES="$CONFIG_FILES man/stapprobes.udp.5" ;;
+ "man/stapprobes.iosched.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.iosched.3stap" ;;
+ "man/stapprobes.netdev.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.netdev.3stap" ;;
+ "man/stapprobes.nfs.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.nfs.3stap" ;;
+ "man/stapprobes.nfsd.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.nfsd.3stap" ;;
+ "man/stapprobes.pagefault.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.pagefault.3stap" ;;
+ "man/stapprobes.kprocess.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.kprocess.3stap" ;;
+ "man/stapprobes.rpc.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.rpc.3stap" ;;
+ "man/stapprobes.scsi.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.scsi.3stap" ;;
+ "man/stapprobes.signal.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.signal.3stap" ;;
+ "man/stapprobes.socket.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.socket.3stap" ;;
+ "man/stapprobes.tcp.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.tcp.3stap" ;;
+ "man/stapprobes.udp.3stap") CONFIG_FILES="$CONFIG_FILES man/stapprobes.udp.3stap" ;;
"initscript/systemtap") CONFIG_FILES="$CONFIG_FILES initscript/systemtap" ;;
"run-stap") CONFIG_FILES="$CONFIG_FILES run-stap" ;;
+ "run-staprun") CONFIG_FILES="$CONFIG_FILES run-staprun" ;;
*) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
@@ -8735,10 +9054,20 @@ BUILD_DOCS_FALSE!$BUILD_DOCS_FALSE$ac_delim
have_xmlto!$have_xmlto$ac_delim
BUILD_REFDOCS_TRUE!$BUILD_REFDOCS_TRUE$ac_delim
BUILD_REFDOCS_FALSE!$BUILD_REFDOCS_FALSE$ac_delim
+BUILD_PDFREFDOCS_TRUE!$BUILD_PDFREFDOCS_TRUE$ac_delim
+BUILD_PDFREFDOCS_FALSE!$BUILD_PDFREFDOCS_FALSE$ac_delim
+have_certutil!$have_certutil$ac_delim
nss_CFLAGS!$nss_CFLAGS$ac_delim
nspr_CFLAGS!$nspr_CFLAGS$ac_delim
BUILD_SERVER_TRUE!$BUILD_SERVER_TRUE$ac_delim
BUILD_SERVER_FALSE!$BUILD_SERVER_FALSE$ac_delim
+HAVE_NSS_TRUE!$HAVE_NSS_TRUE$ac_delim
+HAVE_NSS_FALSE!$HAVE_NSS_FALSE$ac_delim
+PKG_CONFIG!$PKG_CONFIG$ac_delim
+GRAPHER_CFLAGS!$GRAPHER_CFLAGS$ac_delim
+GRAPHER_LIBS!$GRAPHER_LIBS$ac_delim
+BUILD_GRAPHER_TRUE!$BUILD_GRAPHER_TRUE$ac_delim
+BUILD_GRAPHER_FALSE!$BUILD_GRAPHER_FALSE$ac_delim
BUILD_ELFUTILS_TRUE!$BUILD_ELFUTILS_TRUE$ac_delim
BUILD_ELFUTILS_FALSE!$BUILD_ELFUTILS_FALSE$ac_delim
elfutils_abs_srcdir!$elfutils_abs_srcdir$ac_delim
@@ -8751,7 +9080,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` = 25; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 35; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
@@ -9152,22 +9481,21 @@ 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
- $_am_arg | $_am_arg:* )
+ $ac_file | $ac_file:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
-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" |
+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 |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -9204,7 +9532,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 -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then
dirpart=`$as_dirname -- "$mf" ||
$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$mf" : 'X\(//\)[^/]' \| \
@@ -9319,6 +9647,7 @@ echo "$as_me: error: cannot create directory $as_dir" >&2;}
done
;;
"run-stap":F) chmod +x run-stap ;;
+ "run-staprun":F) chmod +x run-staprun ;;
esac
done # for ac_tag
diff --git a/configure.ac b/configure.ac
index f74d8d99..198d77f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
dnl configure.ac --- autoconf input file for systemtap
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([systemtap], 0.9, systemtap@sources.redhat.com, systemtap)
+AC_INIT([systemtap], 0.9.7, systemtap@sources.redhat.com, systemtap)
dnl ^^^^^ see also NEWS, systemtap.spec, testsuite/configure.ac
AC_PREREQ(2.59)
@@ -82,9 +82,10 @@ AS_IF([test "x$enable_ssp" != xno],[
CFLAGS="$save_CFLAGS"
CXXFLAGS="$save_CXXFLAGS"])])
+# Compiling without fPIE by default (see PR 9922)
AC_ARG_ENABLE([pie],
- [AS_HELP_STRING([--disable-pie], [disable position-independent-executable])])
-AS_IF([test "x$enable_pie" != xno],[
+ [AS_HELP_STRING([--enable-pie], [enable position-independent-executable])])
+AS_IF([test "x$enable_pie" == xyes],[
save_CFLAGS="$CFLAGS"
save_CXXFLAGS="$CXXFLAGS"
save_LDFLAGS="$LDFLAGS"
@@ -188,13 +189,26 @@ if test "$building_docs" == "no" -a "$enable_refdocs" == "yes" ; then
AC_MSG_ERROR([must use --enable-docs with --enable-refdocs])
fi
AC_CHECK_PROG(have_xmlto, xmlto, yes, no)
-if test "x${have_xmlto}" == "xyes"; then
+if test "$enable_refdocs" == "yes"; then
+ if test "x${have_xmlto}" != "xyes"; then
+ AC_MSG_ERROR([cannot find xmlto for building reference documentation])
+ fi
+fi
+if test "x${have_xmlto}" == "xyes" -a "$enable_refdocs" != "no" -a "${building_docs}" == "yes"; then
+ building_refdocs="yes"
+fi
+AM_CONDITIONAL([BUILD_REFDOCS], [test "$building_refdocs" == "yes"])
+
+if test "x${building_refdocs}" == "xyes"; then
AC_MSG_CHECKING([for xmlto pdf support])
cat > conftest.$ac_ext << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<book id="pdffromxml">
+ <bookinfo>
+ <title>test</title>
+ </bookinfo>
</book>
EOF
xmlto pdf conftest.$ac_ext >& /dev/null
@@ -203,17 +217,10 @@ EOF
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
+ AC_MSG_WARN([Not building reference documentation in PDF format])
fi
fi
-if test "$enable_refdocs" == "yes"; then
- if test "x${have_xmlto}${have_xmlto_pdf}" != "xyesyes"; then
- AC_MSG_ERROR([cannot find proper yxmlto for building reference documentation])
- fi
-fi
-if test "x${have_xmlto}${have_xmlto_pdf}" == "xyesyes" -a "$enable_refdocs" != "no" -a "${building_docs}" == "yes"; then
- building_refdocs="yes"
-fi
-AM_CONDITIONAL([BUILD_REFDOCS], [test "$building_refdocs" == "yes"])
+AM_CONDITIONAL([BUILD_PDFREFDOCS], [test "have_xmlto_pdf" == "yes"])
dnl Handle the option to build the server setup.
AC_ARG_ENABLE([server],
@@ -221,7 +228,8 @@ AC_ARG_ENABLE([server],
[enable building of stap-server/client (default on if nss etc. found).]),
[enable_server=$enableval],
[enable_server="check"])
-dnl Find the location of nss and nspr headers
+dnl Find the location of nss and nspr headers and certutil
+AC_CHECK_PROG(have_certutil, certutil, [yes], [no])
AC_CHECK_FILE([/usr/include/nss3], nssdir=nss3, [
AC_CHECK_FILE([/usr/include/nss], nssdir=nss)
])
@@ -242,15 +250,27 @@ AC_CHECK_LIB(nspr4, PR_Connect, [
AC_CHECK_LIB(ssl3, SSL_ReHandshake, have_nss_libs=yes)
])
fi
-if test "x${have_nss_includes}${have_nss_libs}" != "xyesyes"; then
+if test "x${have_nss_includes}${have_nss_libs}${have_certutil}" != "xyesyesyes"; then
if test "$enable_server" == "yes"; then
- AC_MSG_ERROR([cannot find all libraries for stap-server])
+ AC_MSG_ERROR([cannot find all libraries or tools for stap-server])
fi
if test "$enable_server" == "check"; then
- AC_MSG_WARN([will not build stap-server, cannot find all libraries])
+ AC_MSG_WARN([will not build stap-server, cannot find all libraries or tools])
fi
+else
+ AC_DEFINE([HAVE_NSS], [1], [Define to 1 if you have the nss libraries.])
fi
-AM_CONDITIONAL([BUILD_SERVER], [test "x${have_nss_includes}${have_nss_libs}" == "xyesyes" -a "$enable_server" != "no"])
+AM_CONDITIONAL([BUILD_SERVER], [test "x${have_nss_includes}${have_nss_libs}${have_certutil}" == "xyesyesyes" -a "$enable_server" != "no"])
+AM_CONDITIONAL([HAVE_NSS], [test "x${have_nss_includes}${have_nss_libs}${have_certutil}" == "xyesyesyes"])
+
+dnl Handle the optional grapher
+AC_ARG_ENABLE([grapher],
+ AS_HELP_STRING([--enable-grapher],
+ [enable building of grapher (default on if gtkmm is found).]),
+ [enable_grapher=$enableval],
+ [enable_grapher="check"])
+PKG_CHECK_MODULES([GRAPHER], [gtkmm-2.4 >= 2.8.0],have_gtkmm=yes,have_gtkmm=no)
+AM_CONDITIONAL([BUILD_GRAPHER], [test "x${have_gtkmm}" == "xyes" -a x"$enable_grapher" != "xno"])
dnl Handle elfutils. If '--with-elfutils=DIR' wasn't specified, used
dnl the system's elfutils.
@@ -355,9 +375,10 @@ dnl Don't use this directly (when not given it is set to NONE).
AC_DEFINE_UNQUOTED(STAP_PREFIX, "$prefix", [configure prefix location])
AC_CONFIG_HEADERS([config.h:config.in])
-AC_CONFIG_FILES(Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile stap.1 stapprobes.5 stapfuncs.5 stapvars.5 stapex.5 staprun.8 stap-server.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 initscript/systemtap)
+AC_CONFIG_FILES(Makefile doc/Makefile doc/SystemTap_Tapset_Reference/Makefile grapher/Makefile stap.1 stapprobes.3stap stapfuncs.3stap stapvars.3stap stapex.3stap staprun.8 stap-server.8 man/stapprobes.iosched.3stap man/stapprobes.netdev.3stap man/stapprobes.nfs.3stap man/stapprobes.nfsd.3stap man/stapprobes.pagefault.3stap man/stapprobes.kprocess.3stap man/stapprobes.rpc.3stap man/stapprobes.scsi.3stap man/stapprobes.signal.3stap man/stapprobes.socket.3stap man/stapprobes.tcp.3stap man/stapprobes.udp.3stap initscript/systemtap)
AC_CONFIG_SUBDIRS(testsuite)
AC_CONFIG_FILES([run-stap], [chmod +x run-stap])
+AC_CONFIG_FILES([run-staprun], [chmod +x run-staprun])
AC_OUTPUT
if test "${prefix}" = "/usr/local"; then
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 93753666..25b8bba2 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -79,6 +79,8 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@@ -104,6 +106,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PIECFLAGS = @PIECFLAGS@
PIECXXFLAGS = @PIECXXFLAGS@
PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
@@ -131,6 +134,7 @@ docdir = @docdir@
dvidir = @dvidir@
elfutils_abs_srcdir = @elfutils_abs_srcdir@
exec_prefix = @exec_prefix@
+have_certutil = @have_certutil@
have_dvips = @have_dvips@
have_latex = @have_latex@
have_latex2html = @have_latex2html@
@@ -278,8 +282,8 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
@@ -304,8 +308,8 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
@@ -315,12 +319,13 @@ ctags: CTAGS
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
+ here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
diff --git a/doc/SystemTap_Beginners_Guide/en-US/References.xml b/doc/SystemTap_Beginners_Guide/en-US/References.xml
index ff993df2..6ab74f17 100644
--- a/doc/SystemTap_Beginners_Guide/en-US/References.xml
+++ b/doc/SystemTap_Beginners_Guide/en-US/References.xml
@@ -43,7 +43,7 @@
The <filename>stapprobes</filename> man page enumerates a variety of probe points supported by SystemTap, along with additional aliases
defined by the SystemTap tapset library. The bottom of the man page includes a list of other man pages
enumerating similar probe points for specific system components, such as
- <filename>stapprobes.scsi</filename>, <filename>stapprobes.process</filename>,
+ <filename>stapprobes.scsi</filename>, <filename>stapprobes.kprocess</filename>,
<filename>stapprobes.signal</filename>, etc.
</para>
</listitem>
diff --git a/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-ioblktime.xml b/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-ioblktime.xml
new file mode 100644
index 00000000..e586d81a
--- /dev/null
+++ b/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-ioblktime.xml
@@ -0,0 +1,111 @@
+<?xml version='1.0'?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+]>
+
+ <section id="ioblktimesect">
+ <title>Periodically Print I/O Block Time</title>
+<indexterm>
+<primary>script examples</primary>
+<secondary>monitoring I/O block time</secondary>
+</indexterm>
+
+<indexterm>
+<primary>examples of SystemTap scripts</primary>
+<secondary>monitoring I/O block time</secondary>
+</indexterm>
+
+<indexterm>
+<primary>monitoring I/O block time</primary>
+<secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+
+<indexterm>
+<primary>I/O block time, monitoring</primary>
+<secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+
+<indexterm>
+<primary>printing I/O block time (periodically)</primary>
+<secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+
+ <para>
+ This section describes how to track the amount of time each block I/O requests spends
+ waiting for completion. This is useful in determining whether there are too many
+ outstanding block I/O operations at any given time.
+ </para>
+
+<formalpara id="ioblktime">
+ <title>ioblktime.stp</title>
+<para>
+<programlisting>
+<xi:include parse="text" href="extras/testsuite/systemtap.examples/io/ioblktime.stp" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</programlisting>
+</para>
+</formalpara>
+
+<!-- <remark>what does $count do, specifically?</remark> -->
+
+<para>
+ <xref linkend="ioblktime"/> computes the average waiting time for block I/O per device,
+ and prints a list every 10 seconds. As always, you can revise this refresh rate by
+ editing the specified value in <command>probe timer.s(10), end {</command>.
+</para>
+<para>
+ In some cases, there can be too many outstanding block
+ I/O operations, at which point the script can exceed the default number of
+ <command>MAXMAPENTRIES</command>. <command>MAXMAPENTRIES</command> is the maximum number of
+ rows in an array if the array size is not specified explicitly when declared. If the script
+ exceeds the default <command>MAXMAPENTRIES</command> value of 2048, run the script again with
+ the <command>stap</command> option <command>-DMAXMAPENTRIES=10000</command>.
+</para>
+
+
+<example id="ioblktimeoutput">
+ <title><xref linkend="ioblktime"/> Sample Output</title>
+<screen>
+ device rw total (us) count avg (us)
+ sda W 9659 6 1609
+ dm-0 W 20278 6 3379
+ dm-0 R 20524 5 4104
+ sda R 19277 5 3855
+</screen>
+</example>
+
+<para>
+ <xref linkend="ioblktimeoutput"/> displays the device name, operations performed
+ (<command>rw</command>), total wait time of all operations (<command>total(us)</command>),
+ number of operations (<command>count</command>), and average
+ wait time for all those operations (<command>avg (us)</command>). The times tallied by the
+ script are in microseconds.
+</para>
+
+<!--
+global reads, writes, total_io
+
+probe kernel.function("vfs_read") {
+reads[execname()] += $count
+}
+
+probe kernel.function("vfs_write") {
+writes[execname()] += $count
+}
+
+# print top 10 IO processes every 5 seconds
+probe timer.s(5) {
+foreach (name in writes)
+total_io[name] += writes[name]
+foreach (name in reads)
+total_io[name] += reads[name]
+printf ("%16s\t%10s\t%10s\n", "Process", "KB Read", "KB Written")
+foreach (name in total_io- limit 10)
+printf("%16s\t%10d\t%10d\n", name,
+reads[name]/1024, writes[name]/1024)
+delete reads
+delete writes
+delete total_io
+print("\n")
+}
+-->
+
+</section> \ No newline at end of file
diff --git a/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcp_connections.xml b/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcp_connections.xml
new file mode 100644
index 00000000..c25465b4
--- /dev/null
+++ b/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcp_connections.xml
@@ -0,0 +1,86 @@
+<?xml version='1.0'?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+]>
+
+
+ <section id="tcpconnectionssect">
+ <title>Monitoring Incoming TCP Connections</title>
+<indexterm>
+<primary>script examples</primary>
+<secondary>monitoring incoming TCP connections</secondary>
+</indexterm>
+
+<indexterm>
+<primary>examples of SystemTap scripts</primary>
+<secondary>monitoring incoming TCP connections</secondary>
+</indexterm>
+
+<indexterm>
+<primary>monitoring incoming TCP connections</primary>
+<secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+<indexterm>
+ <primary>TCP connections (incoming), monitoring</primary>
+ <secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+<indexterm>
+ <primary>incoming TCP connections, monitoring</primary>
+ <secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+<!--
+<indexterm>
+ <primary>script examples</primary>
+ <secondary>net/socket.c, tracing functions from</secondary>
+</indexterm>
+
+<indexterm>
+ <primary>examples of SystemTap scripts</primary>
+ <secondary>net/socket.c, tracing functions from</secondary>
+</indexterm>
+
+<indexterm>
+ <primary>net/socket.c, tracing functions from</primary>
+ <secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+-->
+
+<para>
+ This section illustrates how to monitor incoming TCP connections. This task is useful in
+ identifying any unauthorized, suspicious, or otherwise unwanted network access requests
+ in real time.
+</para>
+
+<formalpara id="tcpconnections">
+ <title>tcp_connections.stp</title>
+<para>
+<programlisting>
+<xi:include parse="text" href="extras/testsuite/systemtap.examples/network/tcp_connections.stp" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</programlisting>
+</para>
+</formalpara>
+
+<para>
+ While <xref linkend="tcpconnections"/> is running, it will print out the following information
+ about any incoming TCP connections accepted by the system in real time:
+</para>
+
+<itemizedlist>
+ <listitem><para>Current <command>UID</command></para></listitem>
+ <listitem><para><command>CMD</command> - the command accepting the connection</para></listitem>
+ <listitem><para><command>PID</command> of the command</para></listitem>
+ <listitem><para>Port used by the connection</para></listitem>
+ <listitem><para>IP address from which the TCP connection originated</para></listitem>
+</itemizedlist>
+
+
+<example id="tcpconnectionsoutput">
+ <title><xref linkend="tcpconnections"/> Sample Output</title>
+<screen>
+UID CMD PID PORT IP_SOURCE
+0 sshd 3165 22 10.64.0.227
+0 sshd 3165 22 10.64.0.227
+</screen>
+</example>
+
+</section>
+
diff --git a/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcpdumplike.xml b/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcpdumplike.xml
new file mode 100644
index 00000000..cd42edc6
--- /dev/null
+++ b/doc/SystemTap_Beginners_Guide/en-US/Useful_Scripts-tcpdumplike.xml
@@ -0,0 +1,116 @@
+<?xml version='1.0'?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+]>
+
+
+ <section id="tcpdumplikesect">
+ <title>Monitoring TCP Packets</title>
+<indexterm>
+<primary>script examples</primary>
+<secondary>monitoring TCP packets</secondary>
+</indexterm>
+
+<indexterm>
+<primary>examples of SystemTap scripts</primary>
+<secondary>monitoring TCP packets</secondary>
+</indexterm>
+
+<indexterm>
+<primary>monitoring TCP packets</primary>
+<secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+<indexterm>
+ <primary>TCP packets, monitoring</primary>
+ <secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+<indexterm>
+ <primary>TCP packets, monitoring</primary>
+ <secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+<!--
+<indexterm>
+ <primary>script examples</primary>
+ <secondary>net/socket.c, tracing functions from</secondary>
+</indexterm>
+
+<indexterm>
+ <primary>examples of SystemTap scripts</primary>
+ <secondary>net/socket.c, tracing functions from</secondary>
+</indexterm>
+
+<indexterm>
+ <primary>net/socket.c, tracing functions from</primary>
+ <secondary>examples of SystemTap scripts</secondary>
+</indexterm>
+-->
+
+<para>
+ This section illustrates how to monitor TCP packets received by the system. This is useful in
+ analyzing network traffic generated by applications running on the system.
+</para>
+
+
+<formalpara id="tcpdumplike">
+ <title>tcpdumplike.stp</title>
+<para>
+<programlisting>
+ <xi:include parse="text" href="extras/testsuite/systemtap.examples/network/tcpdumplike.stp" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</programlisting>
+</para>
+</formalpara>
+
+<para>
+ While <xref linkend="tcpdumplike"/> is running, it will print out the following information
+ about any received TCP packets in real time:
+</para>
+
+<itemizedlist>
+ <listitem><para>Source and destination IP address (<command>saddr</command>,
+ <command>daddr</command>, respectively)</para></listitem>
+ <listitem><para>Source and destination ports (<command>sport</command>, <command>dport</command>,
+ respectively)</para></listitem>
+ <listitem><para>Packet flags</para></listitem>
+</itemizedlist>
+
+<para>
+ To determine the flags used by the packet, <xref linkend="tcpdumplike"/> uses the following
+ functions:
+</para>
+
+<itemizedlist>
+ <listitem><para><command>urg</command> - urgent</para></listitem>
+ <listitem><para><command>ack</command> - acknowledgement</para></listitem>
+ <listitem><para><command>psh</command> - push</para></listitem>
+ <listitem><para><command>rst</command> - reset</para></listitem>
+ <listitem><para><command>syn</command> - synchronize</para></listitem>
+ <listitem><para><command>fin</command> - finished</para></listitem>
+</itemizedlist>
+
+<para>
+ The aforementioned functions return <command>1</command> or <command>0</command> to
+ specify whether the packet uses the corresponding flag.
+</para>
+
+<example id="tcpdumplikeoutput">
+ <title><xref linkend="tcpdumplike"/> Sample Output</title>
+<screen>
+-----------------------------------------------------------------
+ Source IP Dest IP SPort DPort U A P R S F
+-----------------------------------------------------------------
+ 209.85.229.147 10.0.2.15 80 20373 0 1 1 0 0 0
+ 92.122.126.240 10.0.2.15 80 53214 0 1 0 0 1 0
+ 92.122.126.240 10.0.2.15 80 53214 0 1 0 0 0 0
+ 209.85.229.118 10.0.2.15 80 63433 0 1 0 0 1 0
+ 209.85.229.118 10.0.2.15 80 63433 0 1 0 0 0 0
+ 209.85.229.147 10.0.2.15 80 21141 0 1 1 0 0 0
+ 209.85.229.147 10.0.2.15 80 21141 0 1 1 0 0 0
+ 209.85.229.147 10.0.2.15 80 21141 0 1 1 0 0 0
+ 209.85.229.147 10.0.2.15 80 21141 0 1 1 0 0 0
+ 209.85.229.147 10.0.2.15 80 21141 0 1 1 0 0 0
+ 209.85.229.118 10.0.2.15 80 63433 0 1 1 0 0 0
+[...]
+</screen>
+</example>
+
+</section>
+
diff --git a/doc/SystemTap_Beginners_Guide/en-US/Useful_SystemTap_Scripts.xml b/doc/SystemTap_Beginners_Guide/en-US/Useful_SystemTap_Scripts.xml
index b18062f3..eeab9b27 100644
--- a/doc/SystemTap_Beginners_Guide/en-US/Useful_SystemTap_Scripts.xml
+++ b/doc/SystemTap_Beginners_Guide/en-US/Useful_SystemTap_Scripts.xml
@@ -41,6 +41,8 @@
<para>The following sections showcase scripts that trace network-related functions and build a profile of network activity.</para>
<xi:include href="Useful_Scripts-nettop.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="Useful_Scripts-sockettrace.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="Useful_Scripts-tcp_connections.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include condition="fedora" href="Useful_Scripts-tcpdumplike.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</section>
<section id="mainsect-disk">
<title>Disk</title>
@@ -54,6 +56,7 @@
<!-- <xi:include href="Useful_Scripts-Kernel.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> -->
<xi:include href="Useful_Scripts-inodewatch.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="Useful_Scripts-inodewatch2.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include condition="fedora" href="Useful_Scripts-ioblktime.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</section>
<section id="mainsect-profiling">
@@ -69,6 +72,7 @@
<!-- removed; handler function no longer working as expected
<xi:include href="Useful_Scripts-kernelprofiling.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> -->
+
<xi:include href="Useful_Scripts-futexes.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<!-- <xi:include href="Useful_Scripts-Network.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
diff --git a/doc/SystemTap_Tapset_Reference/.gitignore b/doc/SystemTap_Tapset_Reference/.gitignore
index af43f913..3b7d1c17 100644
--- a/doc/SystemTap_Tapset_Reference/.gitignore
+++ b/doc/SystemTap_Tapset_Reference/.gitignore
@@ -1 +1,4 @@
/docproc
+stamp-*
+tapsets/
+tapsets.xml
diff --git a/doc/SystemTap_Tapset_Reference/Makefile.am b/doc/SystemTap_Tapset_Reference/Makefile.am
index 9e7d2069..30c4ffef 100644
--- a/doc/SystemTap_Tapset_Reference/Makefile.am
+++ b/doc/SystemTap_Tapset_Reference/Makefile.am
@@ -2,7 +2,7 @@
## process this file with automake to produce Makefile.in
DOC_INSTALL_DIR = $(DESTDIR)$(datadir)/doc/systemtap
-MAN_INSTALL_DIR = $(DESTDIR)$(mandir)/man5
+MAN_INSTALL_DIR = $(DESTDIR)$(mandir)/man3
HTML_INSTALL_DIR = $(DESTDIR)$(datadir)/doc/systemtap/tapsets
@@ -18,12 +18,17 @@ noinst_PROGRAMS = docproc
SRCTREE=$(abs_top_srcdir)/
DOCPROC=$(abs_builddir)/docproc
+if BUILD_PDFREFDOCS
+PDFDOCS = tapsets.pdf
+endif
+
if BUILD_REFDOCS
-all: tapsets.pdf stamp-htmldocs stamp-mandocs
-tapsets.xml: docproc $(shell find $(SRCTREE) -name '*.stp')
+all: $(PDFDOCS) stamp-htmldocs stamp-mandocs
+tapsets.xml: docproc $(shell find $(SRCTREE)/tapset -name '*.stp')
SRCTREE=$(SRCTREE) $(DOCPROC) doc $(abs_srcdir)/tapsets.tmpl > tapsets.xml.new
if cmp tapsets.xml.new tapsets.xml >/dev/null ; then \
echo tapsets.xml unchanged; \
+ rm tapsets.xml.new; \
else \
mv tapsets.xml.new tapsets.xml; \
fi
@@ -32,20 +37,23 @@ stamp-htmldocs: tapsets.xml
xmlto html -o tapsets tapsets.xml
touch stamp-htmldocs
+# bump up the allocated space so "xmlto pdf" works
tapsets.pdf: tapsets.xml
- xmlto pdf tapsets.xml
+ env pool_size=2000000 hash_extra=2000000 xmlto pdf tapsets.xml
stamp-mandocs: tapsets.xml
- xmlto man -o man5 tapsets.xml
+ xmlto man -o man3 tapsets.xml
touch stamp-mandocs
#FIXME need to figure out where to install things appropriately
#installmandocs: mandocs
install-data-hook:
+if BUILD_PDFREFDOCS
$(MKDIR_P) $(DOC_INSTALL_DIR)
$(INSTALL_DATA) tapsets.pdf $(DOC_INSTALL_DIR)
+endif
$(MKDIR_P) $(MAN_INSTALL_DIR)
- $(INSTALL_DATA) man5/* $(MAN_INSTALL_DIR)
+ $(INSTALL_DATA) man3/* $(MAN_INSTALL_DIR)
$(MKDIR_P) $(HTML_INSTALL_DIR)
$(INSTALL_DATA) tapsets/* $(HTML_INSTALL_DIR)
endif
diff --git a/doc/SystemTap_Tapset_Reference/Makefile.in b/doc/SystemTap_Tapset_Reference/Makefile.in
index 84d2114c..2e8b411d 100644
--- a/doc/SystemTap_Tapset_Reference/Makefile.in
+++ b/doc/SystemTap_Tapset_Reference/Makefile.in
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -46,7 +46,7 @@ PROGRAMS = $(noinst_PROGRAMS)
docproc_SOURCES = docproc.c
docproc_OBJECTS = docproc.$(OBJEXT)
docproc_LDADD = $(LDADD)
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -82,6 +82,8 @@ ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@@ -107,6 +109,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PIECFLAGS = @PIECFLAGS@
PIECXXFLAGS = @PIECXXFLAGS@
PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
PROCFLAGS = @PROCFLAGS@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
@@ -134,6 +137,7 @@ docdir = @docdir@
dvidir = @dvidir@
elfutils_abs_srcdir = @elfutils_abs_srcdir@
exec_prefix = @exec_prefix@
+have_certutil = @have_certutil@
have_dvips = @have_dvips@
have_latex = @have_latex@
have_latex2html = @have_latex2html@
@@ -169,10 +173,11 @@ target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
DOC_INSTALL_DIR = $(DESTDIR)$(datadir)/doc/systemtap
-MAN_INSTALL_DIR = $(DESTDIR)$(mandir)/man5
+MAN_INSTALL_DIR = $(DESTDIR)$(mandir)/man3
HTML_INSTALL_DIR = $(DESTDIR)$(datadir)/doc/systemtap/tapsets
SRCTREE = $(abs_top_srcdir)/
DOCPROC = $(abs_builddir)/docproc
+@BUILD_PDFREFDOCS_TRUE@PDFDOCS = tapsets.pdf
all: all-am
.SUFFIXES:
@@ -240,8 +245,8 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
@@ -253,8 +258,8 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
@@ -264,12 +269,13 @@ ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
+ here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
- $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
- END { if (nonempty) { for (i in files) print i; }; }'`; \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
@@ -412,11 +418,12 @@ uninstall-am:
uninstall-am
-@BUILD_REFDOCS_TRUE@all: tapsets.pdf stamp-htmldocs stamp-mandocs
-@BUILD_REFDOCS_TRUE@tapsets.xml: docproc $(shell find $(SRCTREE) -name '*.stp')
+@BUILD_REFDOCS_TRUE@all: $(PDFDOCS) stamp-htmldocs stamp-mandocs
+@BUILD_REFDOCS_TRUE@tapsets.xml: docproc $(shell find $(SRCTREE)/tapset -name '*.stp')
@BUILD_REFDOCS_TRUE@ SRCTREE=$(SRCTREE) $(DOCPROC) doc $(abs_srcdir)/tapsets.tmpl > tapsets.xml.new
@BUILD_REFDOCS_TRUE@ if cmp tapsets.xml.new tapsets.xml >/dev/null ; then \
@BUILD_REFDOCS_TRUE@ echo tapsets.xml unchanged; \
+@BUILD_REFDOCS_TRUE@ rm tapsets.xml.new; \
@BUILD_REFDOCS_TRUE@ else \
@BUILD_REFDOCS_TRUE@ mv tapsets.xml.new tapsets.xml; \
@BUILD_REFDOCS_TRUE@ fi
@@ -425,20 +432,21 @@ uninstall-am:
@BUILD_REFDOCS_TRUE@ xmlto html -o tapsets tapsets.xml
@BUILD_REFDOCS_TRUE@ touch stamp-htmldocs
+# bump up the allocated space so "xmlto pdf" works
@BUILD_REFDOCS_TRUE@tapsets.pdf: tapsets.xml
-@BUILD_REFDOCS_TRUE@ xmlto pdf tapsets.xml
+@BUILD_REFDOCS_TRUE@ env pool_size=2000000 hash_extra=2000000 xmlto pdf tapsets.xml
@BUILD_REFDOCS_TRUE@stamp-mandocs: tapsets.xml
-@BUILD_REFDOCS_TRUE@ xmlto man -o man5 tapsets.xml
+@BUILD_REFDOCS_TRUE@ xmlto man -o man3 tapsets.xml
@BUILD_REFDOCS_TRUE@ touch stamp-mandocs
#FIXME need to figure out where to install things appropriately
#installmandocs: mandocs
@BUILD_REFDOCS_TRUE@install-data-hook:
-@BUILD_REFDOCS_TRUE@ $(MKDIR_P) $(DOC_INSTALL_DIR)
-@BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) tapsets.pdf $(DOC_INSTALL_DIR)
+@BUILD_PDFREFDOCS_TRUE@@BUILD_REFDOCS_TRUE@ $(MKDIR_P) $(DOC_INSTALL_DIR)
+@BUILD_PDFREFDOCS_TRUE@@BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) tapsets.pdf $(DOC_INSTALL_DIR)
@BUILD_REFDOCS_TRUE@ $(MKDIR_P) $(MAN_INSTALL_DIR)
-@BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) man5/* $(MAN_INSTALL_DIR)
+@BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) man3/* $(MAN_INSTALL_DIR)
@BUILD_REFDOCS_TRUE@ $(MKDIR_P) $(HTML_INSTALL_DIR)
@BUILD_REFDOCS_TRUE@ $(INSTALL_DATA) tapsets/* $(HTML_INSTALL_DIR)
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/doc/SystemTap_Tapset_Reference/tapsets.tmpl b/doc/SystemTap_Tapset_Reference/tapsets.tmpl
index 798cfb3b..767f9e05 100644
--- a/doc/SystemTap_Tapset_Reference/tapsets.tmpl
+++ b/doc/SystemTap_Tapset_Reference/tapsets.tmpl
@@ -5,24 +5,19 @@
<book id="TapsetRef">
<bookinfo>
<title>SystemTap Tapset Reference Manual</title>
-
+<!--starthere-->
+ <copyright>
+ <year>2008-2009</year>
+ <holder>Red Hat, Inc. and others</holder>
+ </copyright>
+
<authorgroup>
<author>
- <firstname>William</firstname>
- <surname>Cohen</surname>
- <contrib></contrib>
- <affiliation>
- <address>
- <email>wcohen@redhat.com</email>
- </address>
- </affiliation>
+ <othername>SystemTap</othername>
+ <contrib>Hackers</contrib>
</author>
</authorgroup>
- <copyright>
- <year>2008, 2009</year>
- <holder>Red Hat, Inc.</holder>
- </copyright>
<legalnotice>
<para>
@@ -53,7 +48,6 @@
</bookinfo>
<!-- pls dont remove marker comments, as they are used in publican conversion-->
<toc></toc>
-<!--starthere-->
<chapter id="introduction">
<title>Introduction</title>
<para>
@@ -117,8 +111,8 @@
<title>Context Functions</title>
<para>
The context functions provide additional information about where
- the event occurred.
- These functions can provide information such as a backtrace
+ an event occurred.
+ These functions can provide information such as a backtrace to
where the event occured
and the current register values for the processor.
</para>
@@ -132,22 +126,26 @@
<para>
Each timestamp function returns a value to indicate when
a function is executed.
- Thus, these returned values can be used to indicate
- when an event occurs, provide an ordering for events, or compute
- the amount of time elapsed between to time stamps.
+ These returned values can then be used to indicate
+ when an event occurred, provide an ordering for events, or compute
+ the amount of time elapsed between two time stamps.
</para>
!Itapset/timestamp.stp
</chapter>
<chapter id="memory_stp">
<title>Memory Tapset</title>
+ <para>
+ This family of probe points is used to probe memory-related events.
+ It contains the following probe points:
+ </para>
!Itapset/memory.stp
</chapter>
<chapter id="iosched.stp">
<title>IO Scheduler Tapset</title>
<para>
- This family of probe points is used to probe the IO scheduler activities.
+ This family of probe points is used to probe IO scheduler activities.
It contains the following probe points:
</para>
!Itapset/ioscheduler.stp
@@ -156,7 +154,7 @@
<chapter id="scsi.stp">
<title>SCSI Tapset</title>
<para>
- This family of probe points is used to probe the SCSI activities.
+ This family of probe points is used to probe SCSI activities.
It contains the following probe points:
</para>
!Itapset/scsi.stp
@@ -166,11 +164,12 @@
<title>Networking Tapset</title>
<para>
This family of probe points is used to probe the activities of
- the network device, TCP layer, and UDP layer.
+ the network device and protocol layers.
</para>
!Itapset/networking.stp
!Itapset/tcp.stp
!Itapset/udp.stp
+!Itapset/ip.stp
</chapter>
<chapter id="socket.stp">
@@ -181,32 +180,13 @@
</para>
!Itapset/socket.stp
</chapter>
-<!--
- <chapter id="tcp.stp">
- <title>TCP Tapset</title>
- <para>
- This family of probe points is used to probe TCP layer activities.
- It contains the following probe points:
- </para>
-
- </chapter>
-
- <chapter id="upd.stp">
- <title>UDP Tapset</title>
- <para>
- This family of probe points is used to probe UDP layer activities.
- It contains the following probe points:
- </para>
-
- </chapter>
--->
- <chapter id="process.stp">
- <title>Process Tapset</title>
+ <chapter id="kprocess.stp">
+ <title>Kernel Process Tapset</title>
<para>
- This family of probe points is used to probe the process activities.
+ This family of probe points is used to probe process-related activities.
It contains the following probe points:
</para>
-!Itapset/process.stp
+!Itapset/kprocess.stp
</chapter>
<chapter id="signal.stp">
<title>Signal Tapset</title>
diff --git a/doc/Tapset_Reference_Guide/en-US/Tapset_Dev_Guide.xml b/doc/Tapset_Reference_Guide/en-US/Tapset_Dev_Guide.xml
index 555fa7e6..293a0dc3 100644
--- a/doc/Tapset_Reference_Guide/en-US/Tapset_Dev_Guide.xml
+++ b/doc/Tapset_Reference_Guide/en-US/Tapset_Dev_Guide.xml
@@ -62,11 +62,13 @@
beginning of those functions:
</para>
+<para>
<programlisting>
-probe process.exec = kernel.function("do_execve"),
+probe kprocess.exec = kernel.function("do_execve"),
kernel.function("compat_do_execve")
{<replaceable>probe body</replaceable>}
</programlisting>
+</para>
<para>
Try to place probes on stable interfaces (i.e., functions
@@ -102,13 +104,15 @@ kernel.function("compat_do_execve")
defined in <filename>task.stp</filename>.
</para>
+<para>
<programlisting>
-probe process.create = kernel.function("copy_process").return
+probe kprocess.create = kernel.function("copy_process").return
{
task = $return
new_pid = task_pid(task)
}
</programlisting>
+</para>
<para>
It is not advisable to write probes for every function. Most SystemTap users
@@ -191,6 +195,7 @@ probe process.create = kernel.function("copy_process").return
The specified format for documenting tapsets is as follows:
</para>
+<para>
<programlisting>
/**
* probe tapset.name - Short summary of what the tapset does.
@@ -209,9 +214,11 @@ probe process.create = kernel.function("copy_process").return
* A paragraph that will appear under the heading "Header".
**/
</programlisting>
-
+</para>
+
<para>For example:</para>
+<para>
<programlisting>
/**
* probe vm.write_shared_copy- Page copy for shared page write.
@@ -226,17 +233,21 @@ probe process.create = kernel.function("copy_process").return
* always preceded by a <command>vm.shared_write</command>.
**/
</programlisting>
+</para>
-<para>To override the automatically-generated <command>Synopsis</command> content, use:
+<para>To override the automatically-generated <command>Synopsis</command> content, use:</para>
+<para>
<programlisting>
* Synopsis:
- * <programlisting>Synopsis string</programlisting>
+ * <replaceable>New Synopsis string</replaceable>
*
</programlisting>
+</para>
<para>For example:</para>
+<para>
<programlisting>
/**
* probe signal.handle - Fires when the signal handler is invoked
@@ -247,6 +258,7 @@ probe process.create = kernel.function("copy_process").return
* sigset_t *oldset, struct pt_regs * regs)&lt;/programlisting>
*/
</programlisting>
+</para>
<para>
It is recommended that you use the <command>&lt;programlisting&gt;</command> tag in
@@ -264,7 +276,7 @@ probe process.create = kernel.function("copy_process").return
<listitem><para><command>emphasis</command></para></listitem>
<listitem><para><command>programlisting</command></para></listitem>
<listitem><para><command>remark</command> (tagged strings will appear in Publican beta
- builds of the document.</para></listitem>
+ builds of the document)</para></listitem>
</itemizedlist>
diff --git a/doc/Tapset_Reference_Guide/manpager.sh b/doc/Tapset_Reference_Guide/manpager.sh
new file mode 100755
index 00000000..0051d208
--- /dev/null
+++ b/doc/Tapset_Reference_Guide/manpager.sh
@@ -0,0 +1,120 @@
+#!/bin/bash
+# This script builds the man pages from comments in tapsets. As such, the man page content
+# generated herein should be in sync with Tapset Reference Guide
+
+# cleanup
+rm -rf man_pages
+
+# create working directory
+mkdir workingdir ;
+
+# create list of man pages to generate
+cat ../SystemTap_Tapset_Reference/tapsets.tmpl | grep ^\!Itapset > manpageus ;
+sed -i -e 's/\!Itapset\///g' manpageus ;
+
+# copy list of man pages into working directory
+for i in `cat manpageus` ; do cp ../../tapset/$i workingdir ; done ;
+
+# enter workdir
+cd workingdir ;
+
+# copy tapsetdescriptions, then clean
+for i in `cat ../manpageus`; do
+sed -n '/\/\/ <tapsetdescription>/,/\/\/ <\/tapsetdescription>/ s/.*/&/w temp' < $i ;
+mv temp $i.tapsetdescription ;
+sed -i -e 's/\/\/ <tapsetdescription>//g' $i.tapsetdescription ;
+sed -i -e 's/\/\/ <\/tapsetdescription>//g' $i.tapsetdescription ;
+sed -i -e 's/\/\///g' $i.tapsetdescription ;
+done
+
+# strip all tapset files to just comments; but all comments must be exactly 1 space before and after "*"
+for i in `cat ../manpageus` ; do sed -i -e 's/^ \*/ \*/g' $i;
+sed -i -e 's/^ \* / \* /g' $i;
+# mark the start of each probe entry (sub "/**")
+perl -p -i -e 's|^/\*\*| *probestart|g' $i;
+sed -i -e '/^ \*/!d' $i;
+# rename all tapsets (remove .stp filename suffix), create templates
+echo $i > tempname ;
+sed -i -e 's/.stp//g' tempname ;
+mv $i `cat tempname` ; mv tempname $i ;
+done ;
+
+# create man page headers
+for i in `ls | grep -v .stp | grep -v tapsetdescription` ; do
+#echo ".\" -*- nroff -*-" >> $i.template ;
+echo ".TH STAPPROBES."$i" 5 @DATE@ "IBM"" >> $i.template ;
+echo ".SH NAME" >> $i.template ;
+echo "stapprobes."`cat $i.stp`" \- systemtap "`cat $i.stp`" probe points" >> $i.template ;
+echo " " >> $i.template ;
+echo ".SH DESCRIPTION" >> $i.template ;
+cat $i.stp.tapsetdescription >> $i.template ;
+echo " " >> $i.template ;
+echo ".SH PROBES" >> $i.template ;
+echo ".br" >> $i.template ;
+echo ".P" >> $i.template ;
+echo ".TP" >> $i.template ;
+done
+
+# MOST IMPORTANT: clean man page body!
+sed -i -e 's/\.stp$//g' ../manpageus ;
+for i in `cat ../manpageus` ;
+do mv $i $i.tmp ;
+perl -p -i -e 's| \* sfunction|.BR|g' $i.tmp ;
+perl -p -i -e 's| \* probe|.BR|g' $i.tmp ;
+perl -p -i -e 's| -|\ninitlinehere|g' $i.tmp ;
+perl -p -i -e 's|^initlinehere([^\n]*)\n|$1\n |g' $i.tmp ;
+perl -p -i -e 's| \* @([^:]*):|\n.I $1:\n|g' $i.tmp ;
+perl -p -i -e 's| \* ([^:]*):|\n.BR $1:\n|g' $i.tmp ;
+perl -p -i -e 's| \* ||g' $i.tmp
+perl -p -i -e 's|\*probestart|\n.P\n.TP|g' $i.tmp ;
+perl -p -i -e 's|\.I|\n.I|g' $i.tmp ;
+# remove empty lines
+sed -i -e '/^$/d' $i.tmp ;
+sed -i -e '/^$/d' $i.tmp ;
+sed -i -e 's/^[ \t]*//g' $i.tmp ;
+# process Description headers
+perl -p -i -e 's|^\*[^/]|\n.BR Description:\n|g' $i.tmp ;
+perl -p -i -e 'undef $/;s|\.BR Description:\n\.BR|.BR|g' $i.tmp ;
+perl -p -i -e 'undef $/;s|\.BR Description:\n\*\/||g' $i.tmp ;
+# process Argument headers
+perl -p -i -e 'undef $/;s|\n\n.I|\n.br\n.BR Arguments:\n.I|g' $i.tmp ;
+# clean up formatting of arguments
+perl -p -i -e 's|^.I([^:]*:)|\n.br\n.br\n.IR$1\n.br\n\t|g' $i.tmp ;
+done
+
+# make tags work
+for i in `cat ../manpageus` ; do
+perl -p -i -e 's|</[^>]*>([^.])|$1\n|g' $i.tmp ;
+perl -p -i -e 's|<[^>]*>|\n.B |g' $i.tmp ;
+# the previous two statements create excess empty lines, remove some of them
+sed -i -e '/^$/d' $i.tmp ;
+# increase whitespace between some headers
+perl -p -i -e 's|^\.BR ([^:]*:)|\n.br\n.BR $1\n.br\n|g' $i.tmp
+done
+
+# generate footer template
+echo ".SH SEE ALSO" >> footer
+echo ".IR stap (1)," >> footer
+echo ".IR stapprobes (5)," >> footer
+for i in `cat ../manpageus`; do echo ".IR stapprobes."$i" (5)," >> footer ; done
+
+# assemble parts
+for i in `cat ../manpageus`; do
+cat $i.template >> stapprobes.$i.5 ;
+cat $i.tmp >> stapprobes.$i.5 ;
+cat footer >> stapprobes.$i.5 ;
+# final polish
+sed -i -e 's/\*\/$//g' stapprobes.$i.5 ;
+done
+
+# cleanup
+for i in `ls | grep -v 'stapprobes.*.5'` ; do
+rm $i ;
+done
+
+rm ../manpageus ;
+cd ..
+mv workingdir man_pages
+echo " "
+echo "Finished! man pages generated in ./man_pages."
+echo " " \ No newline at end of file
diff --git a/doc/Tapset_Reference_Guide/publicanize.sh b/doc/Tapset_Reference_Guide/publicanize.sh
index d4da6e02..a97ae873 100755
--- a/doc/Tapset_Reference_Guide/publicanize.sh
+++ b/doc/Tapset_Reference_Guide/publicanize.sh
@@ -1,65 +1,112 @@
#!/bin/bash
+INFILE="../SystemTap_Tapset_Reference/tapsets.xml"
+OUTFILE="en-US/Tapset_Reference_Guide.xml"
+TMPFILE=`mktemp` || exit 1
+TMPFILE2=`mktemp` || exit 1
-#copy the automated tapsets.xml
-cp ../SystemTap_Tapset_Reference/tapsets.xml temp.xml ;
+do_help()
+{
+ echo "publicanize.sh: usage:
+ -?/--help this message
+ -i/--input=file input file name
+ -o/--output=file output file name
+" >&2
+}
+
+
+#process optional arguments -i -o
+while [ "$#" -ne 0 ]
+do
+ arg=`printf %s $1 | awk -F= '{print $1}'`
+ val=`printf %s $1 | awk -F= '{print $2}'`
+ shift
+ if test -z "$val"; then
+ local possibleval=$1
+ printf %s $1 "$possibleval" | grep ^- >/dev/null 2>&1
+ if test "$?" != "0"; then
+ val=$possibleval
+ if [ "$#" -ge 1 ]; then
+ shift
+ fi
+ fi
+ fi
+
+ case "$arg" in
+ -i|--input)
+ INFILE=$val
+ ;;
+ -o|--output)
+ OUTFILE=$val
+ ;;
+ -\?|--help)
+ do_help
+ exit 0
+ ;;
+ *)
+ echo "Unknown option \"$arg\". See opcontrol --help" >&2
+ exit 1
+ ;;
+ esac
+done
+
+
+#copy the generated tapsets.xml
+cp $INFILE $TMPFILE || exit 1
#remove all excess whitespace
-sed -i -e 's/^\s*//g' temp.xml ;
+sed -i -e 's/^\s*//g' $TMPFILE
-#remove marked Intro (starthere to endhere), then copy it to en-US
-sed '/starthere/,/endhere/d' temp.xml > Tapset_Reference_Guide.xml
-cp Tapset_Reference_Guide.xml en-US/Tapset_Reference_Guide.xml;
-rm Tapset_Reference_Guide.xml
+#remove marked Intro (starthere to endhere)
+sed -i -e '/starthere/,/endhere/d' $TMPFILE
#re-convert programlisting tags
-sed -i -e 's/&lt;programlisting&gt;/<programlisting>/g' en-US/Tapset_Reference_Guide.xml;
-sed -i -e 's/&lt;\/programlisting&gt;/<\/programlisting>/g' en-US/Tapset_Reference_Guide.xml;
+sed -i -e 's/&lt;programlisting&gt;/<programlisting>/g' $TMPFILE
+sed -i -e 's/&lt;\/programlisting&gt;/<\/programlisting>/g' $TMPFILE
#replace header
-cat en-US/Tapset_Reference_Guide.xml |
+cat $TMPFILE |
perl -p -e 'undef $/;s|<bookinfo>\n<title>SystemTap Tapset Reference Manual</title>|<xi:include href="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />\n<xi:include href="Preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />|msg' |
-perl -p -e 'undef $/;s|<authorgroup>\n<author>\n<firstname>William</firstname>\n<surname>Cohen</surname>\n<contrib></contrib>\n<affiliation>\n<address>\n<email>wcohen\@redhat.com</email>\n</address>\n</affiliation>\n</author>\n</authorgroup>||msg' |
-perl -p -e 'undef $/;s|<copyright>\n<year>2008, 2009</year>\n<holder>Red Hat, Inc.</holder>\n</copyright>||msg' |
-perl -p -e 'undef $/;s|<legalnotice>\n<para>\nThis documentation is free software\; you can redistribute\nit and/or modify it under the terms of the GNU General Public\nLicense version 2 as published by the Free Software Foundation.\n</para>||msg' |
-perl -p -e 'undef $/;s|<para>\nThis program is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied\nwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee the GNU General Public License for more details.\n</para>||msg' |
-perl -p -e 'undef $/;s|<para>\nYou should have received a copy of the GNU General Public\nLicense along with this program; if not, write to the Free\nSoftware Foundation, Inc., 59 Temple Place, Suite 330, Boston,\nMA 02111-1307 USA\n</para>||msg' |
-perl -p -e 'undef $/;s|<para>\nFor more details see the file COPYING in the source\ndistribution of Linux.\n</para>\n</legalnotice>\n</bookinfo>||msg' |
-perl -p -e 'undef $/;s|<toc></toc>||msg' |
+#perl -p -e 'undef $/;s|<authorgroup>\n<author>\n<othername>SystemTap</othername>\n<contrib>Hackers</contrib>\n</author>\n</authorgroup>||msg' |
+#perl -p -e 'undef $/;s|<copyright>\n<year>2008-2009</year>\n<holder>Red Hat, Inc. and others</holder>\n</copyright>||msg' |
+#perl -p -e 'undef $/;s|<legalnotice>\n<para>\nThis documentation is free software\; you can redistribute\nit and/or modify it under the terms of the GNU General Public\nLicense version 2 as published by the Free Software Foundation.\n</para>||msg' |
+#perl -p -e 'undef $/;s|<para>\nThis program is distributed in the hope that it will be\nuseful, but WITHOUT ANY WARRANTY; without even the implied\nwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nSee the GNU General Public License for more details.\n</para>||msg' |
+#perl -p -e 'undef $/;s|<para>\nYou should have received a copy of the GNU General Public\nLicense along with this program; if not, write to the Free\nSoftware Foundation, Inc., 59 Temple Place, Suite 330, Boston,\nMA 02111-1307 USA\n</para>||msg' |
+#perl -p -e 'undef $/;s|<para>\nFor more details see the file COPYING in the source\ndistribution of Linux.\n</para>\n</legalnotice>\n</bookinfo>||msg' |
+#perl -p -e 'undef $/;s|<toc></toc>||msg' |
perl -p -e 'undef $/;s|\n\n\n\n\n\n\n\n\n\n\n\n\n\n||msg' |
perl -p -e 'undef $/;s|\n\n\n\n\n\n\n\n\n\n\n||msg' |
perl -p -e 'undef $/;s|<programlisting>\n|<programlisting>\n<emphasis>function <\/emphasis>|msg' |
perl -p -e 'undef $/;s|<para>\n</para>||msg' |
perl -p -e 'undef $/;s|<para>\n\n</para>||msg' |
perl -p -e 'undef $/;s|<para>\n<programlisting>|<programlisting>|msg' |
-perl -p -e 'undef $/;s|</programlisting>\n</para>|</programlisting>|msg' > clean.xml
+perl -p -e 'undef $/;s|</programlisting>\n</para>|</programlisting>|msg' > $TMPFILE2
#replace Intro with my own
-perl -p -i -e 's|<!--markerforxi-->|<xi:include href="Introduction.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />\n<xi:include href="Tapset_Dev_Guide.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />|g' clean.xml
+perl -p -i -e 's|<!--markerforxi-->|<xi:include href="Introduction.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />\n<xi:include href="Tapset_Dev_Guide.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />|g' $TMPFILE2
#for tapset name format section
-#perl -p -i -e 'undef $/;s|<screen>\nname:return \(parameters\)\ndefinition\n</screen>|<screen>\n<replaceable>function/probe</replaceable> tapset_name:return \(parameters\)\n</screen>|msg' clean.xml
-#perl -p -i -e 's|<para>In this guide, tapset definitions appear in the following format:</para>|<para>In this guide, the synopsis of each tapset appears in the following format:</para>|g' clean.xml
-#perl -p -i -e 's|<!-- markerforxi pls dont remove -->|<xi:include href="tapsetnameformat-lastpara.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />\n<xi:include href="refentry-example.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />|g' clean.xml
+#perl -p -i -e 'undef $/;s|<screen>\nname:return \(parameters\)\ndefinition\n</screen>|<screen>\n<replaceable>function/probe</replaceable> tapset_name:return \(parameters\)\n</screen>|msg' $TMPFILE2
+#perl -p -i -e 's|<para>In this guide, tapset definitions appear in the following format:</para>|<para>In this guide, the synopsis of each tapset appears in the following format:</para>|g' $TMPFILE2
+#perl -p -i -e 's|<!-- markerforxi pls dont remove -->|<xi:include href="tapsetnameformat-lastpara.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />\n<xi:include href="refentry-example.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />|g' $TMPFILE2
-cp clean.xml en-US/Tapset_Reference_Guide.xml
-rm clean.xml
-
# statements change synopsis tags, as they are still currently unfixed in publican-redhat
-sed -i -e 's/refsynopsisdiv>/refsect1>/g' en-US/Tapset_Reference_Guide.xml;
-sed -i -e 's/refsect1>/refsection>/g' en-US/Tapset_Reference_Guide.xml;
-sed -i -e 's/synopsis>/programlisting>\n/g' en-US/Tapset_Reference_Guide.xml;
+sed -i -e 's/refsynopsisdiv>/refsect1>/g' $TMPFILE2
+sed -i -e 's/refsect1>/refsection>/g' $TMPFILE2
+sed -i -e 's/synopsis>/programlisting>\n/g' $TMPFILE2
# re-convert tags
-sed -i -e 's/&lt;emphasis&gt;/<emphasis>/g' en-US/Tapset_Reference_Guide.xml;
-sed -i -e 's/&lt;\/emphasis&gt;/<\/emphasis>/g' en-US/Tapset_Reference_Guide.xml;
+sed -i -e 's/&lt;emphasis&gt;/<emphasis>/g' $TMPFILE2
+sed -i -e 's/&lt;\/emphasis&gt;/<\/emphasis>/g' $TMPFILE2
-sed -i -e 's/&lt;remark&gt;/<remark>/g' en-US/Tapset_Reference_Guide.xml;
-sed -i -e 's/&lt;\/remark&gt;/<\/remark>/g' en-US/Tapset_Reference_Guide.xml;
+sed -i -e 's/&lt;remark&gt;/<remark>/g' $TMPFILE2
+sed -i -e 's/&lt;\/remark&gt;/<\/remark>/g' $TMPFILE2
-sed -i -e 's/&lt;command&gt;/<command>/g' en-US/Tapset_Reference_Guide.xml;
-sed -i -e 's/&lt;\/command&gt;/<\/command>/g' en-US/Tapset_Reference_Guide.xml;
+sed -i -e 's/&lt;command&gt;/<command>/g' $TMPFILE2
+sed -i -e 's/&lt;\/command&gt;/<\/command>/g' $TMPFILE2
#useful marker script; moves content between starthere and endhere to file target
-#sed -n '/starthere/,/endhere/ s/.*/&/w target' Tapset_Reference_Guide.xml \ No newline at end of file
+#sed -n '/starthere/,/endhere/ s/.*/&/w target' $TMPFILE2
+
+mv $TMPFILE2 $OUTFILE
diff --git a/dtrace b/dtrace
index 7966e1f2..a2b495b2 100755
--- a/dtrace
+++ b/dtrace
@@ -17,12 +17,11 @@ from subprocess import call
from tempfile import mkstemp
class provider:
- arglist = dict()
def open(self, provider, header):
have_provider = False
self.f = open(provider)
self.h = open(header,mode='w')
- self.h.write("// Generated by the Systemtap dtrace wrapper\n")
+ self.h.write("/* Generated by the Systemtap dtrace wrapper */\n")
self.h.write("\n#include <sys/sdt.h>\n\n")
in_comment = False
while (True):
@@ -49,7 +48,6 @@ class provider:
new_args = ""
i = 0
c = 0
- self.arglist[this_probe] = ""
while (i < len(args)):
if (args[i:i+1] == ","):
new_args = ('%s%s' % (new_args, args[i]))
@@ -57,45 +55,27 @@ class provider:
else:
new_args = new_args + args[i]
i += 1
- if (len(new_args) > 0):
- self.arglist[this_probe] = ('%s arg%d' % (new_args, c))
if (len(new_args) == 0):
- self.h.write ('#define %s() STAP_PROBE(provider,%s)\n' % (this_probe_canon, this_probe))
- elif (c == 0):
- self.h.write ('#define %s(arg1) STAP_PROBE%d(provider,%s,arg1)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 1):
- self.h.write ('#define %s(arg1,arg2) STAP_PROBE%d(provider,%s,arg1,arg2)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 2):
- self.h.write ('#define %s(arg1,arg2,arg3) STAP_PROBE%d(provider,%s,arg1,arg2,arg3)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 3):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 4):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 5):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 6):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 7):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 8):
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\n' % (this_probe_canon, c+1, this_probe))
- elif (c == 9):
- self.h.write('// X %d %s\n' % (c+1,this_probe_canon))
- self.h.write ('#define %s(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) STAP_PROBE%d(provider,%s,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)\n' % (this_probe_canon, c+1, this_probe))
+ c = 0
+ stap_str = "STAP_PROBE(provider,%s" % (this_probe)
+ else:
+ c += 1
+ stap_str = "STAP_PROBE%d(provider,%s" % (c,this_probe)
+ define_str = "#define %s(" % (this_probe_canon)
+ i = 1
+ while (i <= c):
+ if (i != 1):
+ define_str += ","
+ define_str = define_str + "arg%s" % (i);
+ stap_str = stap_str + ",arg%s" % (i);
+ i += 1
+ self.h.write ('/* %s (%s) */\n' % (this_probe_canon,new_args))
self.h.write ('#define %s_ENABLED() 1\n' % this_probe_canon)
-
- def get(self, arg):
- print arg
- if (arg in self.arglist):
- return self.arglist[arg]
- else:
- return ""
-########################################################################
-# main
-########################################################################
+ self.h.write (define_str + ") \\\n")
+ self.h.write (stap_str + ")\n\n")
def usage ():
- print "Usage " + sys.argv[0] + "[-h | -G] -s File.d -o File {Files}"
+ print "Usage " + sys.argv[0] + " [-h | -G] -s File.d -o File {Files}"
sys.exit(1)
def open_file (arg):
@@ -108,6 +88,11 @@ def open_file (arg):
sys.exit(1)
return file
+
+########################################################################
+# main
+########################################################################
+
if (len (sys.argv) < 2):
usage()
diff --git a/elaborate.cxx b/elaborate.cxx
index 34e6ab16..7c4a5fca 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -630,7 +630,18 @@ derive_probes (systemtap_session& s,
// and set a flag on the copy permanently.
bool old_loc_opt = loc->optional;
loc->optional = loc->optional || optional;
- s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation!
+ try
+ {
+ s.pattern_root->find_and_build (s, p, loc, 0, dps); // <-- actual derivation!
+ }
+ catch (const semantic_error& e)
+ {
+ if (!loc->optional)
+ throw semantic_error(e);
+ else /* tolerate failure for optional probe */
+ continue;
+ }
+
loc->optional = old_loc_opt;
unsigned num_atend = dps.size();
@@ -1441,6 +1452,7 @@ systemtap_session::systemtap_session ():
user_file (0),
be_derived_probes(0),
dwarf_derived_probes(0),
+ kprobe_derived_probes(0),
uprobe_derived_probes(0),
utrace_derived_probes(0),
itrace_derived_probes(0),
@@ -2433,7 +2445,8 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p)
p->body = duv.require(p->body, true);
if (p->body == 0)
{
- if (! s.suppress_warnings)
+ if (! s.suppress_warnings
+ && ! s.timing) // PR10070
s.print_warning ("side-effect-free probe '" + p->name + "'", p->tok);
p->body = new null_statement();
@@ -3392,6 +3405,9 @@ typeresolution_info::visit_symbol (symbol* e)
void
typeresolution_info::visit_target_symbol (target_symbol* e)
{
+ if (!e->probe_context_var.empty())
+ return;
+
// This occurs only if a target symbol was not resolved over in
// tapset.cxx land, that error was properly suppressed, and the
// later unused-expression-elimination pass didn't get rid of it
@@ -3432,7 +3448,7 @@ typeresolution_info::visit_cast_op (cast_op* e)
if (e->saved_conversion_error)
throw (* (e->saved_conversion_error));
else
- throw semantic_error("unresolved cast expression", e->tok);
+ throw semantic_error("type definition '" + e->type + "' not found", e->tok);
}
diff --git a/elaborate.h b/elaborate.h
index 0ad5b4b2..d927177b 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -129,6 +129,11 @@ struct derived_probe: public probe
void printsig_nested (std::ostream &o) const;
virtual void collect_derivation_chain (std::vector<probe*> &probes_list);
+ virtual void print_dupe_stamp(std::ostream&) {}
+ // To aid duplication elimination, print a stamp which uniquely identifies
+ // the code that will be added to the probe body. (Doesn't need to be the
+ // actual code...)
+
virtual void emit_probe_context_vars (translator_output*) {}
// From within unparser::emit_common_header, add any extra variables
// to this probe's context locals.
diff --git a/git_version.sh b/git_version.sh
index d39d96c9..c9d3dff7 100755
--- a/git_version.sh
+++ b/git_version.sh
@@ -180,7 +180,7 @@ fi
# 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
+for git_tool in git-symbolic-ref git-rev-parse git-diff-files git-diff-index git git-describe
do
if [ x`which $git_tool 2>/dev/null` = "x" ]; then
git_found="'$git_tool' not found"
@@ -207,7 +207,7 @@ if [ "x$git_repo_dir" != "x" ] && [ "x${abs_repo_dir}" = "x${abs_srcdir}/.git" ]
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'`
+ git_shaid=`git-describe --long 2>/dev/null || git-describe 2>/dev/null || git-rev-parse HEAD`
if [ "x$git_shaid" = "x" ]; then
git_errors="${git_errors+${git_errors}; }error running 'git-rev-parse HEAD'"
fi
diff --git a/grapher/.gitignore b/grapher/.gitignore
new file mode 100644
index 00000000..2ce2a624
--- /dev/null
+++ b/grapher/.gitignore
@@ -0,0 +1 @@
+grapher
diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx
new file mode 100644
index 00000000..86498a4f
--- /dev/null
+++ b/grapher/CairoWidget.cxx
@@ -0,0 +1,42 @@
+#include "CairoWidget.hxx"
+
+#include <math.h>
+
+namespace systemtap
+{
+ void CairoPlayButton::draw(Cairo::RefPtr<Cairo::Context> cr)
+ {
+ if (!_visible)
+ return;
+ cr->save();
+ cr->set_line_width(1.0);
+ // square with rounded corners
+ cr->move_to(_x0, _y0 + _radius);
+ cr->arc(_x0 + _radius, _y0 + _radius, _radius, M_PI, -M_PI_2);
+ cr->line_to(_x0 + _size - _radius, _y0);
+ cr->arc(_x0 + _size - _radius, _y0 + _radius, _radius, -M_PI_2, 0.0);
+ cr->line_to(_x0 + _size, _y0 + _size - _radius);
+ cr->arc(_x0 + _size - _radius, _y0 + _size - _radius, _radius, 0.0, M_PI_2);
+ cr->line_to(_x0 + _radius, _y0 + _size);
+ cr->arc(_x0 + _radius, _y0 + _size - _radius, _radius, M_PI_2, M_PI);
+ cr->close_path();
+ //cr->rectangle(_x0, _y0, 50.0, 50.0);
+ cr->set_source_rgba(1.0, 1.0, 1.0, .8);
+ cr->stroke();
+ // play equalateral triangle
+ cr->move_to(_x0 + .25 * _size, _y0 + (.5 - 1.0 / (sqrt(3.0) * 2.0)) * _size);
+ cr->line_to(_x0 + .75 * _size, _y0 + .5 * _size);
+ cr->line_to(_x0 + .25 * _size, _y0 + (.5 + 1.0 / (sqrt(3.0) * 2.0)) * _size);
+ cr->close_path();
+ cr->fill();
+ cr->restore();
+ }
+
+ bool CairoPlayButton::containsPoint(double x, double y)
+ {
+ if (x >= _x0 && (x < (_x0 + 50.0)) && (y >= _y0) && (y < (_y0 + 50)))
+ return true;
+ else
+ return false;
+ }
+}
diff --git a/grapher/CairoWidget.hxx b/grapher/CairoWidget.hxx
new file mode 100644
index 00000000..077a4c7a
--- /dev/null
+++ b/grapher/CairoWidget.hxx
@@ -0,0 +1,42 @@
+#ifndef SYSTEMTAP_CAIROWIDGET_H
+#define SYSTEMTAP_CAIROWIDGET_H 1
+
+#include <cairomm/context.h>
+namespace systemtap
+{
+ class CairoWidget
+ {
+ public:
+ CairoWidget(bool visible = false)
+ : _visible(visible), _size(50.0), _radius(5)
+ {}
+ bool isVisible() const { return _visible; }
+ void setVisible(bool visible) { _visible = visible; }
+ void getOrigin(double &x, double &y) const
+ {
+ x = _x0;
+ y = _y0;
+ }
+ void setOrigin(double x, double y)
+ {
+ _x0 = x;
+ _y0 = y;
+ }
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr) = 0;
+ virtual bool containsPoint(double x, double y) { return false; }
+ protected:
+ bool _visible;
+ double _x0;
+ double _y0;
+ double _size;
+ double _radius;
+ };
+
+ class CairoPlayButton : public CairoWidget
+ {
+ public:
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr);
+ virtual bool containsPoint(double x, double y);
+ };
+}
+#endif
diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx
new file mode 100644
index 00000000..0f3b0b31
--- /dev/null
+++ b/grapher/GraphData.hxx
@@ -0,0 +1,44 @@
+#ifndef SYSTEMTAP_GRAPHDATA_HXX
+#define SYSTEMTAP_GRAPHDATA_HXX 1
+
+#include <utility>
+#include <vector>
+
+namespace systemtap
+{
+ struct GraphData
+ {
+ public:
+ enum Style
+ { BAR,
+ DOT
+ };
+ GraphData() : scale(1.0), style(BAR)
+ {
+ color[0] = 0.0; color[1] = 1.0; color[2] = 0.0;
+ }
+ typedef std::pair<double, double> Datum;
+ typedef std::vector<Datum> List;
+ // size of grid square at "normal" viewing
+ double scale;
+ double color[3];
+ Style style;
+ List data;
+ struct Compare
+ {
+ bool operator() (const Datum& lhs, const Datum& rhs) const
+ {
+ return lhs.first < rhs.first;
+ }
+ bool operator() (double lhs, const Datum& rhs) const
+ {
+ return lhs < rhs.first;
+ }
+ bool operator() (const Datum& lhs, double rhs) const
+ {
+ return lhs.first < rhs;
+ }
+ };
+ };
+}
+#endif
diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx
new file mode 100644
index 00000000..38f8078d
--- /dev/null
+++ b/grapher/GraphWidget.cxx
@@ -0,0 +1,323 @@
+#include <algorithm>
+#include <ctime>
+#include <math.h>
+#include <sstream>
+#include <iomanip>
+#include <cairomm/context.h>
+#include "GraphWidget.hxx"
+#include "CairoWidget.hxx"
+
+namespace systemtap
+{
+ GraphWidget::GraphWidget()
+ : _left(0.0), _right(1.0), _top(1.0), _bottom(0.0), _lineWidth(10),
+ _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0),
+ _trackingDrag(false), _playButton(new CairoPlayButton)
+ {
+ add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK
+ | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK);
+ Glib::signal_timeout()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_timeout), 1000);
+ signal_expose_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_expose_event), false);
+ signal_button_press_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_button_press_event),
+ false);
+ signal_button_release_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_button_release_event),
+ false);
+ signal_motion_notify_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_motion_notify_event),
+ false);
+ signal_scroll_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_scroll_event), false);
+ }
+
+ void GraphWidget::getExtents(double& left, double& right, double& top,
+ double& bottom) const
+ {
+ left = _left;
+ right = _right;
+ top = _top;
+ bottom = _bottom;
+ }
+
+ void GraphWidget::setExtents(double left, double right, double top,
+ double bottom)
+ {
+ _left = left;
+ _right = right;
+ _top = top;
+ _bottom = bottom;
+
+ }
+ GraphWidget::~GraphWidget()
+ {
+ }
+
+ void GraphWidget::addGraphData(std::tr1::shared_ptr<GraphData> data)
+ {
+ _datasets.push_back(data);
+ }
+
+ bool GraphWidget::on_expose_event(GdkEventExpose* event)
+ {
+ // This is where we draw on the window
+ Glib::RefPtr<Gdk::Window> window = get_window();
+ if(!window)
+ return true;
+
+ Gtk::Allocation allocation = get_allocation();
+
+ const int graphWidth = allocation.get_width();
+ const int graphHeight = allocation.get_height();
+ const int width = graphWidth - 20;
+ const int height = graphHeight - 20;
+
+ Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
+ if(event && !_autoScaling)
+ {
+ // clip to the area indicated by the expose event so that we only
+ // redraw the portion of the window that needs to be redrawn
+ cr->rectangle(event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cr->clip();
+ }
+ if (_autoScaling)
+ {
+ // line separation
+ int linesPossible = width / ((int)_lineWidth + 2);
+ // Find latest time.
+ double latestTime = 0;
+ for (DatasetList::iterator ditr = _datasets.begin(),
+ de = _datasets.end();
+ ditr != de;
+ ++ditr)
+ {
+ if (!(*ditr)->data.empty())
+ {
+ double lastDataTime = (*ditr)->data.back().first;
+ if (lastDataTime > latestTime)
+ latestTime = lastDataTime;
+ }
+ }
+ double minDiff = 0.0;
+ double maxTotal = 0.0;
+ for (DatasetList::iterator ditr = _datasets.begin(),
+ de = _datasets.end();
+ ditr != de;
+ ++ditr)
+ {
+ GraphData::List& gdata = (*ditr)->data;
+ if (gdata.size() <= 1)
+ continue;
+ double totalDiff = 0.0;
+ for (GraphData::List::reverse_iterator ritr = gdata.rbegin(),
+ re = gdata.rend();
+ ritr + 1 != gdata.rend();
+ ritr++)
+ {
+ double timeDiff = ritr->first - (ritr + 1)->first;
+ if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0))
+ minDiff = timeDiff;
+ if (minDiff != 0
+ && (totalDiff + timeDiff) / minDiff > linesPossible)
+ break;
+ totalDiff += timeDiff;
+ }
+ if (totalDiff > maxTotal)
+ maxTotal = totalDiff;
+ }
+ // Now we have a global scale.
+ _right = latestTime;
+ if (maxTotal != 0)
+ _left = latestTime - maxTotal;
+ else
+ _left = _right - 1.0;
+ }
+ cr->save();
+ double horizScale = _zoomFactor * width / ( _right - _left);
+ cr->translate(20.0, 0.0);
+ cr->set_line_width(_lineWidth);
+ cr->save();
+ cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
+ cr->paint();
+ cr->restore();
+
+ for (DatasetList::iterator itr = _datasets.begin(), e = _datasets.end();
+ itr != e;
+ ++itr)
+ {
+ cr->save();
+ cr->translate(0.0, height);
+ cr->scale(1.0, -1.0);
+ GraphData::List::iterator lower
+ = std::lower_bound((*itr)->data.begin(), (*itr)->data.end(), _left,
+ GraphData::Compare());
+ GraphData::List::iterator upper
+ = std::upper_bound((*itr)->data.begin(), (*itr)->data.end(), _right,
+ GraphData::Compare());
+ for (GraphData::List::iterator ditr = lower, de = upper;
+ ditr != de;
+ ++ditr)
+ {
+ cr->set_source_rgba((*itr)->color[0], (*itr)->color[1],
+ (*itr)->color[2], 1.0);
+ if ((*itr)->style == GraphData::BAR)
+ {
+ cr->move_to((ditr->first - _left) * horizScale, 0);
+ cr->line_to((ditr->first - _left) * horizScale,
+ ditr->second * height / (*itr)->scale);
+ cr->stroke();
+ }
+ else
+ {
+ cr->arc((ditr->first - _left) * horizScale,
+ ditr->second * height / (*itr)->scale,
+ _lineWidth / 2.0, 0.0, M_PI * 2.0);
+ cr->fill();
+ }
+ }
+ cr->restore();
+ }
+ cr->restore();
+ cr->save();
+ cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
+ Cairo::FONT_WEIGHT_BOLD);
+ cr->set_font_size(14.0);
+ cr->set_source_rgba(1.0, 1.0, 1.0, .8);
+
+ if (!_title.empty())
+ {
+ cr->move_to(20.0, 20.0);
+ cr->show_text(_title);
+ }
+ if (!_xAxisText.empty())
+ {
+ cr->move_to(10.0, graphHeight - 5);
+ cr->show_text(_xAxisText);
+ }
+ if (!_yAxisText.empty())
+ {
+ cr->save();
+ cr->translate(10.0, height - 10.0);
+ cr->rotate(-M_PI / 2.0);
+ cr->move_to(10.0, 0.0);
+ cr->show_text(_yAxisText);
+ cr->restore();
+ }
+ cr->restore();
+ // Draw axes
+ double diff = _right - _left;
+ double majorUnit = pow(10.0, floor(log(diff) / log(10.0)));
+ double startTime = floor(_left / majorUnit) * majorUnit;
+ cr->save();
+ cr->set_source_rgba(1.0, 1.0, 1.0, .9);
+ cr->set_line_cap(Cairo::LINE_CAP_BUTT);
+ cr->set_line_width(_lineWidth);
+ cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
+ Cairo::FONT_WEIGHT_NORMAL);
+ cr->set_font_size(10.0);
+ cr->move_to(20.0, 0.0);
+ cr->line_to(20.0, height);
+ cr->move_to(20.0, height);
+ cr->line_to(graphWidth, height);
+ cr->stroke();
+ std::valarray<double> dash(1);
+ dash[0] = height / 10;
+ cr->set_dash(dash, 0.0);
+ for (double tickVal = startTime; tickVal < _right; tickVal += majorUnit)
+ {
+ cr->move_to((tickVal - _left) * horizScale + 20.0, graphHeight - 5);
+ std::ostringstream stream;
+ stream << std::fixed << std::setprecision(0) << tickVal;
+ cr->show_text(stream.str());
+ cr->move_to((tickVal - _left) * horizScale + 20.0, 0.0);
+ cr->line_to((tickVal - _left) * horizScale + 20.0, height);
+ cr->stroke();
+ }
+ cr->stroke();
+ cr->restore();
+
+ if (!_autoScrolling)
+ {
+ _playButton->setVisible(true);
+ _playButton->setOrigin(width / 2 - 25, .875 * height - 50);
+ _playButton->draw(cr);
+ }
+
+ return true;
+ }
+
+ bool GraphWidget::on_button_press_event(GdkEventButton* event)
+ {
+ if (!_autoScrolling && _playButton->containsPoint(event->x, event->y))
+ {
+ _autoScaling = true;
+ _autoScrolling = true;
+ queue_draw();
+ }
+ else
+ {
+ _trackingDrag = true;
+ _autoScaling = false;
+ _autoScrolling = false;
+ _dragOriginX = event->x;
+ _dragOriginY = event->y;
+ _dragOrigLeft = _left;
+ _dragOrigRight = _right;
+ }
+ return true;
+ }
+
+ bool GraphWidget::on_button_release_event(GdkEventButton* event)
+ {
+ _trackingDrag = false;
+ return true;
+ }
+
+ bool GraphWidget::on_motion_notify_event(GdkEventMotion* event)
+ {
+ Glib::RefPtr<Gdk::Window> win = get_window();
+ if(!win)
+ return true;
+ double x = 0.0;
+ double y = 0.0;
+ // XXX Hint
+ if (event->is_hint)
+ {
+ }
+ else
+ {
+ x = event->x;
+ y = event->y;
+ }
+ if (_trackingDrag)
+ {
+ Gtk::Allocation allocation = get_allocation();
+ const int width = allocation.get_width();
+ double motion = (x - _dragOriginX) / (double) width;
+ double increment = motion * (_dragOrigLeft - _dragOrigRight);
+ _left = _dragOrigLeft + increment;
+ _right = _dragOrigRight + increment;
+ queue_draw();
+ }
+ return true;
+ }
+
+ bool GraphWidget::on_scroll_event(GdkEventScroll* event)
+ {
+ if (event->direction == GDK_SCROLL_UP)
+ _zoomFactor += .1;
+ else if (event->direction == GDK_SCROLL_DOWN)
+ _zoomFactor -= .1;
+ queue_draw();
+ return true;
+ }
+
+ bool GraphWidget::on_timeout()
+ {
+ queue_draw();
+ return true;
+ }
+}
diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx
new file mode 100644
index 00000000..46075b78
--- /dev/null
+++ b/grapher/GraphWidget.hxx
@@ -0,0 +1,62 @@
+#ifndef SYSTEMTAP_GRAPHWIDGET_H
+#define SYSTEMTAP_GRAPHWIDGET_H
+
+#include <string>
+#include <vector>
+#include <tr1/memory>
+
+#include <gtkmm/drawingarea.h>
+#include "GraphData.hxx"
+
+namespace systemtap
+{
+ class CairoPlayButton;
+
+ class GraphWidget : public Gtk::DrawingArea
+ {
+ public:
+ GraphWidget();
+ virtual ~GraphWidget();
+ void addGraphData(std::tr1::shared_ptr<GraphData> data);
+ void getExtents(double& left, double& right, double& top, double& bottom) const;
+ void setExtents(double left, double right, double top, double bottom);
+ double getLineWidth() { return _lineWidth; }
+ void setLineWidth(double lineWidth) { _lineWidth = lineWidth; }
+ bool getAutoScaling() const { return _autoScaling; }
+ void setAutoScaling(bool val) { _autoScaling = val; }
+ std::string getTitle() const { return _title; }
+ void setTitle(const std::string& title) { _title = title; }
+ std::string getXAxisText() const { return _xAxisText; }
+ void setXAxisText(const std::string& text) { _xAxisText = text; }
+ std::string getYAxisText() const { return _yAxisText; }
+ void setYAxisText(const std::string& text) { _yAxisText = text; }
+ protected:
+ //Override default signal handler:
+ virtual bool on_expose_event(GdkEventExpose* event);
+ virtual bool on_motion_notify_event(GdkEventMotion* event);
+ virtual bool on_button_press_event(GdkEventButton* event);
+ virtual bool on_button_release_event(GdkEventButton* event);
+ virtual bool on_scroll_event(GdkEventScroll* event);
+ bool on_timeout();
+ typedef std::vector<std::tr1::shared_ptr<GraphData> > DatasetList;
+ DatasetList _datasets;
+ double _left;
+ double _right;
+ double _top;
+ double _bottom;
+ double _lineWidth;
+ bool _autoScaling;
+ bool _autoScrolling;
+ double _zoomFactor;
+ bool _trackingDrag;
+ double _dragOriginX;
+ double _dragOriginY;
+ double _dragOrigLeft;
+ double _dragOrigRight;
+ std::string _title;
+ std::string _xAxisText;
+ std::string _yAxisText;
+ std::tr1::shared_ptr<CairoPlayButton> _playButton;
+ };
+}
+#endif // SYSTEMTAP_GRAPHWIDGET_H
diff --git a/grapher/Makefile.am b/grapher/Makefile.am
new file mode 100644
index 00000000..fdb52ef7
--- /dev/null
+++ b/grapher/Makefile.am
@@ -0,0 +1,7 @@
+if BUILD_GRAPHER
+bin_PROGRAMS = grapher
+
+grapher_CXXFLAGS = $(GRAPHER_CFLAGS)
+grapher_SOURCES = grapher.cxx GraphWidget.cxx CairoWidget.cxx
+grapher_LDADD = $(GRAPHER_LIBS)
+endif \ No newline at end of file
diff --git a/grapher/Makefile.in b/grapher/Makefile.in
new file mode 100644
index 00000000..2373b6f4
--- /dev/null
+++ b/grapher/Makefile.in
@@ -0,0 +1,490 @@
+# Makefile.in generated by automake 1.10 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+@BUILD_GRAPHER_TRUE@bin_PROGRAMS = grapher$(EXEEXT)
+subdir = grapher
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__grapher_SOURCES_DIST = grapher.cxx GraphWidget.cxx CairoWidget.cxx
+@BUILD_GRAPHER_TRUE@am_grapher_OBJECTS = grapher-grapher.$(OBJEXT) \
+@BUILD_GRAPHER_TRUE@ grapher-GraphWidget.$(OBJEXT) \
+@BUILD_GRAPHER_TRUE@ grapher-CairoWidget.$(OBJEXT)
+grapher_OBJECTS = $(am_grapher_OBJECTS)
+am__DEPENDENCIES_1 =
+@BUILD_GRAPHER_TRUE@grapher_DEPENDENCIES = $(am__DEPENDENCIES_1)
+grapher_LINK = $(CXXLD) $(grapher_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+SOURCES = $(grapher_SOURCES)
+DIST_SOURCES = $(am__grapher_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATE = @DATE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GRAPHER_CFLAGS = @GRAPHER_CFLAGS@
+GRAPHER_LIBS = @GRAPHER_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PIECFLAGS = @PIECFLAGS@
+PIECXXFLAGS = @PIECXXFLAGS@
+PIELDFLAGS = @PIELDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PROCFLAGS = @PROCFLAGS@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+elfutils_abs_srcdir = @elfutils_abs_srcdir@
+exec_prefix = @exec_prefix@
+have_certutil = @have_certutil@
+have_dvips = @have_dvips@
+have_latex = @have_latex@
+have_latex2html = @have_latex2html@
+have_ps2pdf = @have_ps2pdf@
+have_xmlto = @have_xmlto@
+host_alias = @host_alias@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nspr_CFLAGS = @nspr_CFLAGS@
+nss_CFLAGS = @nss_CFLAGS@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sqlite3_LIBS = @sqlite3_LIBS@
+srcdir = @srcdir@
+stap_LIBS = @stap_LIBS@
+staplog_CPPFLAGS = @staplog_CPPFLAGS@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@BUILD_GRAPHER_TRUE@grapher_CXXFLAGS = $(GRAPHER_CFLAGS)
+@BUILD_GRAPHER_TRUE@grapher_SOURCES = grapher.cxx GraphWidget.cxx CairoWidget.cxx
+@BUILD_GRAPHER_TRUE@grapher_LDADD = $(GRAPHER_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cxx .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu grapher/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu grapher/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+grapher$(EXEEXT): $(grapher_OBJECTS) $(grapher_DEPENDENCIES)
+ @rm -f grapher$(EXEEXT)
+ $(grapher_LINK) $(grapher_OBJECTS) $(grapher_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-CairoWidget.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-GraphWidget.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grapher-grapher.Po@am__quote@
+
+.cxx.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cxx.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+grapher-grapher.o: grapher.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-grapher.o -MD -MP -MF $(DEPDIR)/grapher-grapher.Tpo -c -o grapher-grapher.o `test -f 'grapher.cxx' || echo '$(srcdir)/'`grapher.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='grapher.cxx' object='grapher-grapher.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-grapher.o `test -f 'grapher.cxx' || echo '$(srcdir)/'`grapher.cxx
+
+grapher-grapher.obj: grapher.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-grapher.obj -MD -MP -MF $(DEPDIR)/grapher-grapher.Tpo -c -o grapher-grapher.obj `if test -f 'grapher.cxx'; then $(CYGPATH_W) 'grapher.cxx'; else $(CYGPATH_W) '$(srcdir)/grapher.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-grapher.Tpo $(DEPDIR)/grapher-grapher.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='grapher.cxx' object='grapher-grapher.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-grapher.obj `if test -f 'grapher.cxx'; then $(CYGPATH_W) 'grapher.cxx'; else $(CYGPATH_W) '$(srcdir)/grapher.cxx'; fi`
+
+grapher-GraphWidget.o: GraphWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-GraphWidget.o -MD -MP -MF $(DEPDIR)/grapher-GraphWidget.Tpo -c -o grapher-GraphWidget.o `test -f 'GraphWidget.cxx' || echo '$(srcdir)/'`GraphWidget.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='GraphWidget.cxx' object='grapher-GraphWidget.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-GraphWidget.o `test -f 'GraphWidget.cxx' || echo '$(srcdir)/'`GraphWidget.cxx
+
+grapher-GraphWidget.obj: GraphWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-GraphWidget.obj -MD -MP -MF $(DEPDIR)/grapher-GraphWidget.Tpo -c -o grapher-GraphWidget.obj `if test -f 'GraphWidget.cxx'; then $(CYGPATH_W) 'GraphWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/GraphWidget.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-GraphWidget.Tpo $(DEPDIR)/grapher-GraphWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='GraphWidget.cxx' object='grapher-GraphWidget.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-GraphWidget.obj `if test -f 'GraphWidget.cxx'; then $(CYGPATH_W) 'GraphWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/GraphWidget.cxx'; fi`
+
+grapher-CairoWidget.o: CairoWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-CairoWidget.o -MD -MP -MF $(DEPDIR)/grapher-CairoWidget.Tpo -c -o grapher-CairoWidget.o `test -f 'CairoWidget.cxx' || echo '$(srcdir)/'`CairoWidget.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='CairoWidget.cxx' object='grapher-CairoWidget.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-CairoWidget.o `test -f 'CairoWidget.cxx' || echo '$(srcdir)/'`CairoWidget.cxx
+
+grapher-CairoWidget.obj: CairoWidget.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -MT grapher-CairoWidget.obj -MD -MP -MF $(DEPDIR)/grapher-CairoWidget.Tpo -c -o grapher-CairoWidget.obj `if test -f 'CairoWidget.cxx'; then $(CYGPATH_W) 'CairoWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/CairoWidget.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/grapher-CairoWidget.Tpo $(DEPDIR)/grapher-CairoWidget.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='CairoWidget.cxx' object='grapher-CairoWidget.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(grapher_CXXFLAGS) $(CXXFLAGS) -c -o grapher-CairoWidget.obj `if test -f 'CairoWidget.cxx'; then $(CYGPATH_W) 'CairoWidget.cxx'; else $(CYGPATH_W) '$(srcdir)/CairoWidget.cxx'; fi`
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx
new file mode 100644
index 00000000..46182178
--- /dev/null
+++ b/grapher/grapher.cxx
@@ -0,0 +1,127 @@
+#include "GraphWidget.hxx"
+
+#include <cmath>
+#include <sstream>
+#include <string>
+#include <map>
+
+#include <gtkmm/main.h>
+#include <gtkmm/window.h>
+#include <unistd.h>
+#include <poll.h>
+
+using namespace systemtap;
+
+class StapParser
+{
+ Glib::ustring _buffer;
+ typedef std::map<std::string, std::tr1::shared_ptr<GraphData> > DataMap;
+ DataMap _dataSets;
+ Gtk::Window& _win;
+ GraphWidget& _widget;
+public:
+ StapParser(Gtk::Window& win,
+ GraphWidget& widget) : _win(win), _widget(widget) {}
+
+ bool ioCallback(Glib::IOCondition ioCondition)
+ {
+ if ((ioCondition & Glib::IO_IN) == 0)
+ return true;
+ char buf[256];
+ ssize_t bytes_read = 0;
+ bytes_read = read(0, buf, sizeof(buf) - 1);
+ if (bytes_read <= 0)
+ {
+ _win.hide();
+ return true;
+ }
+ buf[bytes_read] = '\0';
+ _buffer += buf;
+ Glib::ustring::size_type ret = Glib::ustring::npos;
+ while ((ret = _buffer.find('\n')) != Glib::ustring::npos)
+ {
+ Glib::ustring dataString(_buffer, 0, ret);
+ if (dataString[0] == '%')
+ {
+ size_t found;
+ if ((found = dataString.find("%Title:") == 0))
+ {
+ std::string title = dataString.substr(7);
+ _widget.setTitle(title);
+ }
+ else if ((found = dataString.find("%XAxisTitle:") == 0))
+ {
+ _widget.setXAxisText(dataString.substr(12));
+ }
+ else if ((found = dataString.find("%YAxisTitle:") == 0))
+ {
+ _widget.setYAxisText(dataString.substr(12));
+ }
+ else if ((found = dataString.find("%YMax:") == 0))
+ {
+ double ymax;
+ std::istringstream stream(dataString.substr(6));
+ stream >> ymax;
+ // _gdata->scale = ymax;
+ }
+ else if ((found = dataString.find("%DataSet:") == 0))
+ {
+ std::tr1::shared_ptr<GraphData> dataSet(new GraphData);
+ std::string setName;
+ int hexColor;
+ std::string style;
+ std::istringstream stream(dataString.substr(9));
+ stream >> setName >> dataSet->scale >> std::hex >> hexColor
+ >> style;
+ dataSet->color[0] = (hexColor >> 16) / 255.0;
+ dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0;
+ dataSet->color[2] = (hexColor & 0xff) / 255.0;
+ if (style == "dot")
+ dataSet->style = GraphData::DOT;
+ _dataSets.insert(std::make_pair(setName, dataSet));
+ _widget.addGraphData(dataSet);
+ }
+ }
+ else
+ {
+ std::string dataSet;
+ double time;
+ double data;
+ std::istringstream stream(dataString);
+ stream >> dataSet >> time >> data;
+ DataMap::iterator itr = _dataSets.find(dataSet);
+ if (itr != _dataSets.end())
+ itr->second->data.push_back(std::make_pair(time, data));
+ }
+ _buffer.erase(0, ret + 1);
+ }
+ return true;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ Gtk::Main app(argc, argv);
+
+ Gtk::Window win;
+
+ win.set_title("Grapher");
+ win.set_default_size(600, 200);
+
+ GraphWidget w;
+
+ w.setExtents(0.0, 1.0, 5.0, 0.0);
+ w.setLineWidth(2);
+
+ StapParser stapParser(win, w);
+ Glib::signal_io().connect(sigc::mem_fun(stapParser,
+ &StapParser::ioCallback),
+ 0,
+ Glib::IO_IN);
+ win.add(w);
+ w.show();
+
+ Gtk::Main::run(win);
+
+ return 0;
+}
diff --git a/hash.cxx b/hash.cxx
index 61caa356..45ae05eb 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -48,6 +48,20 @@ hash::add(const unsigned char *buffer, size_t size)
void
+hash::add_file(const std::string& filename)
+{
+ struct stat st;
+
+ if (stat(filename.c_str(), &st) == 0)
+ {
+ add(filename);
+ add(st.st_size);
+ add(st.st_mtime);
+ }
+}
+
+
+void
hash::result(string& r)
{
ostringstream rstream;
@@ -68,37 +82,40 @@ hash::result(string& r)
static void
get_base_hash (systemtap_session& s, hash& h)
{
- struct stat st;
-
// Hash kernel release and arch.
h.add(s.kernel_release);
h.add(s.kernel_build_tree);
h.add(s.architecture);
+ // Hash a few kernel version/build-id files too
+ // (useful for kernel developers reusing a single source tree)
+ h.add_file(s.kernel_build_tree + "/.config");
+ h.add_file(s.kernel_build_tree + "/.version");
+ h.add_file(s.kernel_build_tree + "/include/linux/compile.h");
+ h.add_file(s.kernel_build_tree + "/include/linux/version.h");
+ h.add_file(s.kernel_build_tree + "/include/linux/utsrelease.h");
+
+ // If the kernel is a git working directory, then add the git HEAD
+ // revision to our hash as well.
+ // XXX avoiding this for now, because it's potentially expensive and has
+ // uncertain gain. The only corner case that this may help is if a developer
+ // is switching the source tree without rebuilding the kernel...
+ ///h.add(git_revision(s.kernel_build_tree));
+
// Hash runtime path (that gets added in as "-R path").
h.add(s.runtime_path);
// Hash compiler path, size, and mtime. We're just going to assume
// we'll be using gcc. XXX: getting kbuild to spit out out would be
// better.
- string gcc_path = find_executable ("gcc");
- if (stat(gcc_path.c_str(), &st) == 0)
- {
- h.add(gcc_path);
- h.add(st.st_size);
- h.add(st.st_mtime);
- }
+ h.add_file(find_executable("gcc"));
// Hash the systemtap size and mtime. We could use VERSION/DATE,
// but when developing systemtap that doesn't work well (since you
// can compile systemtap multiple times in 1 day). Since we don't
// know exactly where we're getting run from, we'll use
// /proc/self/exe.
- if (stat("/proc/self/exe", &st) == 0)
- {
- h.add(st.st_size);
- h.add(st.st_mtime);
- }
+ h.add_file("/proc/self/exe");
}
@@ -157,6 +174,7 @@ find_script_hash (systemtap_session& s, const string& script, const hash &base)
h.add(s.ignore_vmlinux); // --ignore-vmlinux
h.add(s.ignore_dwarf); // --ignore-dwarf
h.add(s.consult_symtab); // --kelf, --kmap
+ h.add(s.skip_badvars); // --skip-badvars
if (!s.kernel_symtab_path.empty()) // --kmap
{
h.add(s.kernel_symtab_path);
@@ -237,4 +255,42 @@ find_hash (systemtap_session& s, const string& script)
find_script_hash(s, script, base);
}
+
+void
+find_tracequery_hash (systemtap_session& s)
+{
+ hash h;
+ get_base_hash(s, h);
+
+ // The basic hash should be good enough for the tracepoint query module
+
+ // Get the directory path to store our cached module
+ string result, hashdir;
+ h.result(result);
+ if (!create_hashdir(s, result, hashdir))
+ return;
+
+ s.tracequery_path = hashdir + "/tracequery_" + result + ".ko";
+}
+
+
+void
+find_typequery_hash (systemtap_session& s, const string& name, string& module)
+{
+ hash h;
+ get_base_hash(s, h);
+
+ // Add the typequery name to distinguish the hash
+ h.add(name);
+
+ // Get the directory path to store our cached module
+ string result, hashdir;
+ h.result(result);
+ if (!create_hashdir(s, result, hashdir))
+ return;
+
+ module = hashdir + "/typequery_" + result
+ + (name[0] == 'k' ? ".ko" : ".so");
+}
+
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/hash.h b/hash.h
index d386ad03..7e432216 100644
--- a/hash.h
+++ b/hash.h
@@ -30,10 +30,14 @@ public:
void add(const char *s) { add((const unsigned char *)s, strlen(s)); }
void add(const std::string& s) { add((const unsigned char *)s.c_str(),
s.length()); }
+ void add_file(const std::string& filename);
void result(std::string& r);
};
void find_hash (systemtap_session& s, const std::string& script);
+void find_tracequery_hash (systemtap_session& s);
+void find_typequery_hash (systemtap_session& s, const std::string& name,
+ std::string& module);
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h
index d6c90192..5899549c 100644
--- a/includes/sys/sdt.h
+++ b/includes/sys/sdt.h
@@ -13,34 +13,29 @@
#include <string.h>
#include <sys/types.h>
-#if _LP64
-#define STAP_PROBE_STRUCT_ARG(arg) \
- __uint64_t arg
+#ifdef __LP64__
+#define STAP_PROBE_ADDR "\t.quad "
#else
-#define STAP_PROBE_STRUCT_ARG(arg) \
- long arg __attribute__ ((aligned(8)))
+#define STAP_PROBE_ADDR "\t.long "
#endif
-#define STAP_SENTINEL 0x31425250
-
-#define STAP_PROBE_STRUCT(probe,argc) \
-struct _probe_ ## probe \
-{ \
- int probe_type; \
- STAP_PROBE_STRUCT_ARG (probe_name); \
- STAP_PROBE_STRUCT_ARG (probe_arg); \
-}; \
-static char probe ## _ ## probe_name [] \
- __attribute__ ((section (".probes"))) \
- = #probe; \
-__extension__ static volatile struct _probe_ ## probe _probe_ ## probe __attribute__ ((section (".probes"))) = {STAP_SENTINEL,(size_t)& probe ## _ ## probe_name[0],argc};
-
-/* The goto _probe_ prevents the label from "drifting" */
-#define STAP_LABEL_REF(probe, label) \
- if (__builtin_expect(_probe_ ## probe.probe_type < 0, 0)) \
- goto label;
-
-/* These baroque macros are used to create a unique label */
+/* An allocated section .probes that holds the probe names and addrs. */
+#define STAP_PROBE_DATA_(probe) \
+ __asm__ volatile (".section .probes, \"a\"\n" \
+ "\t.align 8\n" \
+ "1:\n\t.asciz " #probe "\n" \
+ "\t.align 4\n" \
+ "\t.int 0x31425250\n" \
+ "\t.align 8\n" \
+ STAP_PROBE_ADDR "1b\n" \
+ "\t.align 8\n" \
+ STAP_PROBE_ADDR "2f\n" \
+ "\t.previous\n")
+
+#define STAP_PROBE_DATA(probe) \
+ STAP_PROBE_DATA_(#probe)
+
+/* These baroque macros are used to create a unique label. */
#define STAP_CONCAT(a,b) a ## b
#define STAP_LABEL_PREFIX(p) _stapprobe1_ ## p
/* __COUNTER__ is not present in gcc 4.1 */
@@ -51,151 +46,189 @@ __extension__ static volatile struct _probe_ ## probe _probe_ ## probe __attribu
#endif
#define STAP_LABEL(a,b) STAP_CONCAT(a,b)
-#define STAP_PROBE_(probe,label) \
+/* Taking the address of a local label and/or referencing alloca prevents the
+ containing function from being inlined, which keeps the parameters visible. */
+
+#if __GNUC__ == 4 && __GNUC_MINOR__ <= 1
+#include <alloca.h>
+#define STAP_UNINLINE alloca((size_t)0)
+#else
+#define STAP_UNINLINE
+#endif
+
+#define STAP_UNINLINE_LABEL(label) \
+ __extension__ static volatile long labelval __attribute__ ((unused)) = (long) &&label
+
+#if defined(__x86_64__) || defined(__i386__)
+#define STAP_NOP "\tnop "
+#else
+#define STAP_NOP "\tnop 0 "
+#endif
+
+#define STAP_PROBE_(probe) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- STAP_LABEL_REF(probe,label); \
-label: \
- __asm__ volatile ("nop"); \
+ STAP_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP); \
} while (0)
#define STAP_PROBE1_(probe,label,parm1) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
-label: \
- __asm__ volatile ("nop /* %0 */" :: "X"( arg1)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 */" :: "g"(arg1)); \
} while (0)
#define STAP_PROBE2_(probe,label,parm1,parm2) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
-label: \
- __asm__ volatile ("nop /* %0 %1 */" :: "X"(arg1), "X"(arg2)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 */" :: "g"(arg1), "g"(arg2)); \
} while (0)
#define STAP_PROBE3_(probe,label,parm1,parm2,parm3) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
-label: \
- __asm__ volatile ("nop /* %0 %1 %2 */" :: "X"(arg1), "X"(arg2), "X"(arg3)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 */" :: "g"(arg1), "g"(arg2), "g"(arg3)); \
} while (0)
#define STAP_PROBE4_(probe,label,parm1,parm2,parm3,parm4) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
-label: \
- __asm__ volatile ("nop /* %0 %1 %2 %3 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4)); \
} while (0)
#define STAP_PROBE5_(probe,label,parm1,parm2,parm3,parm4,parm5) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
- volatile __typeof__((parm5)) arg5 __attribute__ ((unused)) = parm5; \
-label: \
- __asm__ volatile ("nop /* %0 %1 %2 %3 %4 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ volatile __typeof__((parm5)) arg5 = parm5; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 %4 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5)); \
} while (0)
#define STAP_PROBE6_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
- volatile __typeof__((parm5)) arg5 __attribute__ ((unused)) = parm5; \
- volatile __typeof__((parm6)) arg6 __attribute__ ((unused)) = parm6; \
-label: \
- __asm__ volatile ("nop" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ volatile __typeof__((parm5)) arg5 = parm5; \
+ volatile __typeof__((parm6)) arg6 = parm6; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 %4 %5 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5), "g"(arg6)); \
} while (0)
#define STAP_PROBE7_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
- volatile __typeof__((parm5)) arg5 __attribute__ ((unused)) = parm5; \
- volatile __typeof__((parm6)) arg6 __attribute__ ((unused)) = parm6; \
- volatile __typeof__((parm7)) arg7 __attribute__ ((unused)) = parm7; \
-label: \
- __asm__ volatile ("nop" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ volatile __typeof__((parm5)) arg5 = parm5; \
+ volatile __typeof__((parm6)) arg6 = parm6; \
+ volatile __typeof__((parm7)) arg7 = parm7; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 %4 %5 %6 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5), "g"(arg6), "g"(arg7)); \
} while (0)
#define STAP_PROBE8_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
- volatile __typeof__((parm5)) arg5 __attribute__ ((unused)) = parm5; \
- volatile __typeof__((parm6)) arg6 __attribute__ ((unused)) = parm6; \
- volatile __typeof__((parm7)) arg7 __attribute__ ((unused)) = parm7; \
- volatile __typeof__((parm8)) arg8 __attribute__ ((unused)) = parm8; \
-label: \
- __asm__ volatile ("nop" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7), "X"(arg8)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ volatile __typeof__((parm5)) arg5 = parm5; \
+ volatile __typeof__((parm6)) arg6 = parm6; \
+ volatile __typeof__((parm7)) arg7 = parm7; \
+ volatile __typeof__((parm8)) arg8 = parm8; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 %4 %5 %6 %7 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5), "g"(arg6), "g"(arg7), "g"(arg8)); \
} while (0)
#define STAP_PROBE9_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
- volatile __typeof__((parm5)) arg5 __attribute__ ((unused)) = parm5; \
- volatile __typeof__((parm6)) arg6 __attribute__ ((unused)) = parm6; \
- volatile __typeof__((parm7)) arg7 __attribute__ ((unused)) = parm7; \
- volatile __typeof__((parm8)) arg8 __attribute__ ((unused)) = parm8; \
- volatile __typeof__((parm9)) arg9 __attribute__ ((unused)) = parm9; \
-label: \
- __asm__ volatile ("nop" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7), "X"(arg8), "X"(arg9)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ volatile __typeof__((parm5)) arg5 = parm5; \
+ volatile __typeof__((parm6)) arg6 = parm6; \
+ volatile __typeof__((parm7)) arg7 = parm7; \
+ volatile __typeof__((parm8)) arg8 = parm8; \
+ volatile __typeof__((parm9)) arg9 = parm9; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 %4 %5 %6 %7 %8 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5), "g"(arg6), "g"(arg7), "g"(arg8), "g"(arg9)); \
} while (0)
#define STAP_PROBE10_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \
do { \
- STAP_PROBE_STRUCT(probe,(size_t)&& label) \
- volatile __typeof__((parm1)) arg1 __attribute__ ((unused)) = parm1; \
- volatile __typeof__((parm2)) arg2 __attribute__ ((unused)) = parm2; \
- volatile __typeof__((parm3)) arg3 __attribute__ ((unused)) = parm3; \
- volatile __typeof__((parm4)) arg4 __attribute__ ((unused)) = parm4; \
- volatile __typeof__((parm5)) arg5 __attribute__ ((unused)) = parm5; \
- volatile __typeof__((parm6)) arg6 __attribute__ ((unused)) = parm6; \
- volatile __typeof__((parm7)) arg7 __attribute__ ((unused)) = parm7; \
- volatile __typeof__((parm8)) arg8 __attribute__ ((unused)) = parm8; \
- volatile __typeof__((parm9)) arg9 __attribute__ ((unused)) = parm9; \
- volatile __typeof__((parm10)) arg10 __attribute__ ((unused)) = parm10; \
-label: \
- __asm__ volatile ("nop" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7), "X"(arg8), "X"(arg9), "X"(arg10)); \
- STAP_LABEL_REF(probe,label); \
+ STAP_UNINLINE_LABEL(label); \
+ volatile __typeof__((parm1)) arg1 = parm1; \
+ volatile __typeof__((parm2)) arg2 = parm2; \
+ volatile __typeof__((parm3)) arg3 = parm3; \
+ volatile __typeof__((parm4)) arg4 = parm4; \
+ volatile __typeof__((parm5)) arg5 = parm5; \
+ volatile __typeof__((parm6)) arg6 = parm6; \
+ volatile __typeof__((parm7)) arg7 = parm7; \
+ volatile __typeof__((parm8)) arg8 = parm8; \
+ volatile __typeof__((parm9)) arg9 = parm9; \
+ volatile __typeof__((parm10)) arg10 = parm10; \
+ STAP_UNINLINE; \
+ STAP_PROBE_DATA(probe); \
+ label: \
+ __asm__ volatile ("2:\n" \
+ STAP_NOP "/* %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 */" :: "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), "g"(arg5), "g"(arg6), "g"(arg7), "g"(arg8), "g"(arg9), "g"(arg10)); \
} while (0)
#define STAP_PROBE(provider,probe) \
- STAP_PROBE_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER))
+ STAP_PROBE_(probe)
#define STAP_PROBE1(provider,probe,parm1) \
STAP_PROBE1_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1))
#define STAP_PROBE2(provider,probe,parm1,parm2) \
diff --git a/initscript/.gitignore b/initscript/.gitignore
new file mode 100644
index 00000000..ec0530ab
--- /dev/null
+++ b/initscript/.gitignore
@@ -0,0 +1 @@
+systemtap
diff --git a/initscript/README.initscript b/initscript/README.initscript
index f566cf71..ee11f3be 100644
--- a/initscript/README.initscript
+++ b/initscript/README.initscript
@@ -1,5 +1,5 @@
Systemtap initscript
-Version 0.2
+Version 0.2.1
Author: Masami Hiramatsu <mhiramat@redhat.com>
INDEX
diff --git a/initscript/systemtap.in b/initscript/systemtap.in
index eaa1d969..918455d6 100644
--- a/initscript/systemtap.in
+++ b/initscript/systemtap.in
@@ -287,7 +287,7 @@ stap_getopt () { # opts
# TODO: support quoted options
getopt -s bash -u \
-l 'kelf,kmap::,ignore-vmlinux,ignore-dwarf,vp:' \
- -o 'hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:F' -- $@
+ -o 'hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:FS:' -- $@
ret=$?
[ $ret -ne 0 ] && slog "Failed to parse parameters. ($@)"
return $ret
@@ -301,9 +301,9 @@ get_compile_opts () { # opts
for o in $opts; do
if [ $skip -ne 0 ]; then skip=0; continue; fi
case $o in
- -p|-m|-r|-c|-x|-e|-s|-o)
+ -p|-m|-r|-c|-x|-e|-s|-o|-S)
skip=1 ;;
- -h|-V|-k)
+ -h|-V|-k|-F)
;;
*)
echo -n $o" " ;;
@@ -312,14 +312,16 @@ get_compile_opts () { # opts
}
get_run_opts () { # normalized_opts
- local opts o show
+ local opts o show mode
opts=`stap_getopt $*`
[ $? -ne 0 ] && return 1
+ mode='-L'
show=0
for o in $opts; do
case $o in
- -c|-x|-s|-o)
+ -c|-x|-s|-o|-S)
[ $o == '-s' ] && o='-b'
+ [ $o == '-o' ] && mode='-D'
echo -n $o" "
show=1
;;
@@ -331,6 +333,7 @@ get_run_opts () { # normalized_opts
;;
esac
done
+ echo -n $mode
}
prepare_cache_dir () {
@@ -461,11 +464,12 @@ start_script () { # script
return 1
fi
pushd "$tmpdir" &> /dev/null
- logex $STAPRUN -L $opts "$CACHE_PATH/$s.ko"
+ eval log \"Exec: $STAPRUN $opts $CACHE_PATH/$s.ko\"
+ $STAPRUN $opts "$CACHE_PATH/$s.ko" 2>> "$LOG_FILE" > ./pid
ret=$?
+ [ x`cat ./pid` = x ] && echo 0 > ./pid
if [ $ret -eq 0 ]; then
- # TODO: store daemon pid after supporting on-file flight recorder
- echo 0 > "$STAT_PATH/$s"
+ logex cp -f ./pid "$STAT_PATH/$s"
fi
popd &> /dev/null
rm -rf "$tmpdir"
@@ -524,7 +528,7 @@ stop_script () { # script
p=`get_daemon_pid $1`
if [ $p -ne 0 ]; then
- logex killall -TERM $p
+ logex kill -TERM $p
else
logex $STAPRUN -d "$1"
fi
diff --git a/main.cxx b/main.cxx
index 890f65bc..1ac5dd5a 100644
--- a/main.cxx
+++ b/main.cxx
@@ -108,10 +108,13 @@ usage (systemtap_session& s, int exitcode)
<< " " << s.kernel_build_tree << endl
<< " -m MODULE set probe module name, instead of " << endl
<< " " << s.module_name << endl
- << " -o FILE send script output to file, instead of stdout" << endl
+ << " -o FILE send script output to file, instead of stdout. This supports" << endl
+ << " strftime(3) formats for FILE" << endl
<< " -c CMD start the probes, run CMD, and exit when it finishes" << endl
<< " -x PID sets target() to PID" << endl
- << " -F load module and start probes, then detach" << endl
+ << " -F run as on-file flight recorder with -o." << endl
+ << " run as on-memory flight recorder without -o." << endl
+ << " -S size[,n] set maximum of the size and the number of files." << endl
<< " -d OBJECT add unwind/symbol data for OBJECT file";
if (s.unwindsym_modules.size() == 0)
clog << endl;
@@ -287,14 +290,9 @@ int pending_interrupts;
extern "C"
void handle_interrupt (int sig)
{
- if (pending_interrupts == 0)
- kill (0, sig); // Forward signals to child processes if any.
-
+ kill_stap_spawn(sig);
pending_interrupts ++;
- // NB: the "2" below is intended to skip the effect of the self-induced
- // deferred signal coming from the kill() above.
-
- if (pending_interrupts > 2) // XXX: should be configurable? time-based?
+ if (pending_interrupts > 1) // XXX: should be configurable? time-based?
{
char msg[] = "Too many interrupts received, exiting.\n";
int rc = write (2, msg, sizeof(msg)-1);
@@ -318,7 +316,7 @@ setup_signals (sighandler_t handler)
sigaddset (&sa.sa_mask, SIGINT);
sigaddset (&sa.sa_mask, SIGTERM);
}
- sa.sa_flags = 0;
+ sa.sa_flags = SA_RESTART;
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGPIPE, &sa, NULL);
@@ -326,6 +324,34 @@ setup_signals (sighandler_t handler)
sigaction (SIGTERM, &sa, NULL);
}
+void
+setup_kernel_release (systemtap_session &s, const char* kstr) {
+ if (kstr[0] == '/') // fully specified path
+ {
+ s.kernel_build_tree = kstr;
+ string version_file_name = s.kernel_build_tree + "/include/config/kernel.release";
+ // The file include/config/kernel.release within the
+ // build tree is used to pull out the version information
+ ifstream version_file (version_file_name.c_str());
+ if (version_file.fail ())
+ {
+ cerr << "Missing " << version_file_name << endl;
+ exit(1);
+ }
+ else
+ {
+ char c;
+ s.kernel_release = "";
+ while (version_file.get(c) && c != '\n')
+ s.kernel_release.push_back(c);
+ }
+ }
+ else
+ {
+ s.kernel_release = string (kstr);
+ s.kernel_build_tree = "/lib/modules/" + s.kernel_release + "/build";
+ }
+}
int
main (int argc, char * const argv [])
@@ -375,6 +401,15 @@ main (int argc, char * const argv [])
s.ignore_vmlinux = false;
s.ignore_dwarf = false;
s.load_only = false;
+ s.skip_badvars = false;
+
+ // Location of our signing certificate.
+ // If we're root, use the database in SYSCONFDIR, otherwise
+ // use the one in our $HOME directory. */
+ if (geteuid() == 0)
+ s.cert_db_path = SYSCONFDIR "/systemtap/ssl/server";
+ else
+ s.cert_db_path = getenv("HOME") + string ("/.systemtap/ssl/server");
const char* s_p = getenv ("SYSTEMTAP_TAPSET");
if (s_p != NULL)
@@ -425,6 +460,12 @@ main (int argc, char * const argv [])
if (s_tc != NULL)
s.tapset_compile_coverage = true;
+ const char* s_kr = getenv ("SYSTEMTAP_RELEASE");
+ if (s_kr != NULL) {
+ setup_kernel_release(s, s_kr);
+ }
+
+
while (true)
{
int long_opt;
@@ -444,7 +485,7 @@ main (int argc, char * const argv [])
{ "vp", 1, &long_opt, LONG_OPT_VERBOSE_PASS },
{ NULL, 0, NULL, 0 }
};
- int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:F",
+ int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:FS:",
long_options, NULL);
if (grc < 0)
break;
@@ -559,31 +600,7 @@ main (int argc, char * const argv [])
break;
case 'r':
- if (optarg[0] == '/') // fully specified path
- {
- s.kernel_build_tree = optarg;
- string version_file_name = s.kernel_build_tree + "/include/config/kernel.release";
- // The file include/config/kernel.release within the
- // build tree is used to pull out the version information
- ifstream version_file (version_file_name.c_str());
- if (version_file.fail ())
- {
- cerr << "Missing " << version_file_name << endl;
- usage (s, 1);
- }
- else
- {
- char c;
- s.kernel_release = "";
- while (version_file.get(c) && c != '\n')
- s.kernel_release.push_back(c);
- }
- }
- else
- {
- s.kernel_release = string (optarg);
- s.kernel_build_tree = "/lib/modules/" + s.kernel_release + "/build";
- }
+ setup_kernel_release(s, optarg);
break;
case 'k':
@@ -628,6 +645,10 @@ main (int argc, char * const argv [])
s.macros.push_back (string (optarg));
break;
+ case 'S':
+ s.size_option = string (optarg);
+ break;
+
case 'q':
s.tapset_compile_coverage = true;
break;
@@ -1121,6 +1142,20 @@ main (int argc, char * const argv [])
if (copy_file(module_src_path.c_str(), module_dest_path.c_str()) != 0)
cerr << "Copy failed (\"" << module_src_path << "\" to \""
<< module_dest_path << "\"): " << strerror(errno) << endl;
+
+#if HAVE_NSS
+ // Save the signature as well.
+ assert (! s.cert_db_path.empty());
+ module_src_path += ".sgn";
+ module_dest_path += ".sgn";
+
+ if (s.verbose > 1)
+ clog << "Copying " << module_src_path << " to "
+ << module_dest_path << endl;
+ if (copy_file(module_src_path.c_str(), module_dest_path.c_str()) != 0)
+ cerr << "Copy failed (\"" << module_src_path << "\" to \""
+ << module_dest_path << "\"): " << strerror(errno) << endl;
+#endif
}
}
@@ -1178,7 +1213,7 @@ pass_5:
string cleanupcmd = "rm -rf ";
cleanupcmd += s.tmpdir;
if (s.verbose>1) clog << "Running " << cleanupcmd << endl;
- int status = system (cleanupcmd.c_str());
+ int status = stap_system (cleanupcmd.c_str());
if (status != 0 && s.verbose>1)
clog << "Cleanup command failed, status: " << status << endl;
}
diff --git a/man/stapprobes.iosched.5.in b/man/stapprobes.iosched.3stap.in
index f638b2ff..873251ac 100644
--- a/man/stapprobes.iosched.5.in
+++ b/man/stapprobes.iosched.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.IOSCHED 5 @DATE@ "IBM"
+.TH STAPPROBES.IOSCHED 3stap @DATE@ "IBM"
.SH NAME
stapprobes.iosched \- systemtap IO scheduler probe points
@@ -96,5 +96,5 @@ Fires when a request is completed
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.process.5.in b/man/stapprobes.kprocess.3stap.in
index b725a907..4f5e7903 100644
--- a/man/stapprobes.process.5.in
+++ b/man/stapprobes.kprocess.3stap.in
@@ -1,7 +1,7 @@
.\" -*- nroff -*-
-.TH STAPPROBES.PROCESS 5 @DATE@ "Intel, IBM"
+.TH STAPPROBES.KPROCESS 3stap @DATE@ "Intel, IBM"
.SH NAME
-stapprobes.process \- systemtap process probe points
+stapprobes.kprocess \- systemtap kernel process probe points
.\" macros
.de SAMPLE
@@ -18,12 +18,12 @@ stapprobes.process \- systemtap process probe points
.SH DESCRIPTION
-This family of probe points is used to probe the process activities.
+This family of probe points is used to probe the kernel's process activities.
It contains the following probe points:
.P
.TP
-.B process.create
+.B kprocess.create
Fires whenever a new process is successfully created, either as a
result of one of the fork syscall variants, or a new kernel thread.
@@ -38,7 +38,7 @@ result of one of the fork syscall variants, or a new kernel thread.
.P
.TP
-.B process.start
+.B kprocess.start
Fires immediately before a new process begins execution.
@@ -48,7 +48,7 @@ Fires immediately before a new process begins execution.
.P
.TP
-.B process.exec
+.B kprocess.exec
Fires whenever a process attempts to exec to a new program
@@ -59,7 +59,7 @@ Fires whenever a process attempts to exec to a new program
.P
.TP
-.B process.exec_complete
+.B kprocess.exec_complete
Fires at the completion of an exec call
@@ -73,10 +73,10 @@ Fires at the completion of an exec call
.P
.TP
-.B process.exit
+.B kprocess.exit
Fires when a process terminates. This will always be followed by a
-process.release, though the latter may be delayed if the process
+kprocess.release, though the latter may be delayed if the process
waits in a zombie state.
.B Arguments:
@@ -86,10 +86,10 @@ waits in a zombie state.
.P
.TP
-.B process.release
+.B kprocess.release
Fires when a process is released from the kernel. This always
-follows a process.exit, though it may be delayed somewhat if the
+follows a kprocess.exit, though it may be delayed somewhat if the
process waits in a zombie state.
.B Arguments:
@@ -102,5 +102,5 @@ process waits in a zombie state.
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.netdev.5.in b/man/stapprobes.netdev.3stap.in
index 0510b07b..9b2e57ed 100644
--- a/man/stapprobes.netdev.5.in
+++ b/man/stapprobes.netdev.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.NETDEV 5 @DATE@ "IBM"
+.TH STAPPROBES.NETDEV 3stap @DATE@ "IBM"
.SH NAME
stapprobes.netdev \- systemtap network device probe points
@@ -74,4 +74,4 @@ Fires when the network device wants to transmit a buffer
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.nfs.5.in b/man/stapprobes.nfs.3stap.in
index bf575ae4..14404b96 100644
--- a/man/stapprobes.nfs.5.in
+++ b/man/stapprobes.nfs.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.NFS 5 @DATE@ "IBM"
+.TH STAPPROBES.NFS 3stap @DATE@ "IBM"
.SH NAME
stapprobes.nfs \- systemtap NFS client side probe points
@@ -551,7 +551,7 @@ Fires when a previous async read operation failed
.TP
.B nfs.aop.readpages
-Fies when in readahead way,read several pages once
+Fires when in readahead way, read several pages once
.B Arguments:
@@ -577,7 +577,7 @@ Fies when in readahead way,read several pages once
.TP
.B nfs.aop.readpages.return
-Fies whenever a nfs read pages operation is done
+Fires whenever a nfs read pages operation is done
.B Arguments:
@@ -588,7 +588,7 @@ Fies whenever a nfs read pages operation is done
.TP
.B nfs.aop.set_page_dirty
-Fies whenever set page dirty on nfs client side
+Fires whenever set page dirty on nfs client side
.B Arguments:
@@ -602,7 +602,7 @@ Fies whenever set page dirty on nfs client side
.TP
.B nfs.aop.writepage
-Fies whenever writing an mapped page to the server from nfs client side
+Fires whenever writing an mapped page to the server from nfs client side
.B Arguments:
@@ -644,7 +644,7 @@ Fies whenever writing an mapped page to the server from nfs client side
.TP
.B nfs.aop.writepages
-Fies whenever writing several dirty pages to the server from nfs client sides
+Fires whenever writing several dirty pages to the server from nfs client sides
.B Arguments:
@@ -674,7 +674,7 @@ Fies whenever writing several dirty pages to the server from nfs client sides
.TP
.B nfs.aop.prepare_write
-Fies whenever prepare a page for writting on nfs client sides
+Fires whenever prepare a page for writing on nfs client sides
.B Arguments:
@@ -703,7 +703,7 @@ Fies whenever prepare a page for writting on nfs client sides
.TP
.B nfs.aop.commit_write
-Fies often after prepare write operation
+Fires often after prepare write operation
.B Arguments:
@@ -771,7 +771,7 @@ Fies often after prepare write operation
nfs version
.I filename
- the name of file which client opens/searchs on server
+ the name of file which client opens/searches on server
.I name_len
the length of file name
@@ -851,7 +851,7 @@ Fires when client synchronously writes file to server
.TP
.B nfs.proc.write.return
-Fires when synchronously writting file from server is done
+Fires when synchronously writing file from server is done
.B Arguments:
@@ -862,7 +862,7 @@ Fires when synchronously writting file from server is done
.TP
.B nfs.proc.commit
-Fires when client writes the buffered data to disk,the buffered
+Fires when client writes the buffered data to disk, the buffered
data is asynchronously written by client before(not exist in NFSV2)
.B Arguments:
@@ -902,7 +902,7 @@ Fires when committing operation is done
.B nfs.proc.read_setup
Fires when client asynchronously reads file from server,
-this function is used to setup a read rpc task,not do
+this function is used to setup a read rpc task, not do
a real read operation.
.B Arguments:
@@ -947,7 +947,7 @@ Fires when a read reply is received or some read error occur
number of bytes read
.I timestamp
- time stamp ,which is used for lease renewal (only
+ time stamp, which is used for lease renewal (only
in nfs.proc4.read_done)
.P
@@ -955,7 +955,7 @@ Fires when a read reply is received or some read error occur
.B nfs.proc.write_setup
Fires when client asynchronously write data to server,
-this function is used to setup a write rpc task,not do
+this function is used to setup a write rpc task, not do
a write read operation.
.B Arguments:
@@ -976,7 +976,7 @@ a write read operation.
the file offset
.I how
- used to set args.stable,The possible value could be:
+ used to set args.stable, The possible value could be:
NFS_UNSTABLE,
NFS_DATA_SYNC,
NFS_FILE_SYNC
@@ -1008,13 +1008,13 @@ Fires when a write reply is received or some write error occur
result of last async write operation
.I valid
- fattr\->valid ,indicates which fields are valid
+ fattr\->valid, indicates which fields are valid
.I count
number of bytes written
.I timestamp
- time stamp ,which is used for lease renewal (only
+ time stamp, which is used for lease renewal (only
in nfs.proc4.read_done)
.P
@@ -1022,7 +1022,7 @@ Fires when a write reply is received or some write error occur
.B nfs.proc.commit_setup
Fires when client asynchronously do a commit operation,
-this function is used to setup a commit rpc task,not do
+this function is used to setup a commit rpc task, not do
a commit read operation.
.B Arguments:
@@ -1068,13 +1068,13 @@ Fires when a commit reply is received or some commit error occur
result of last async write operation
.I valid
- fattr\->valid ,indicates which fields are valid
+ fattr\->valid, indicates which fields are valid
.I count
number of bytes written
.I timestamp
- time stamp ,which is used for lease renewal (only
+ time stamp, which is used for lease renewal (only
in nfs.proc4.read_done)
.P
@@ -1232,5 +1232,5 @@ Fires whenever nfs client renames a file on server
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.nfsd.5.in b/man/stapprobes.nfsd.3stap.in
index 8d30b38b..ea2ac2df 100644
--- a/man/stapprobes.nfsd.5.in
+++ b/man/stapprobes.nfsd.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.NFSD 5 @DATE@ "IBM"
+.TH STAPPROBES.NFSD 3stap @DATE@ "IBM"
.SH NAME
stapprobes.nfsd \- systemtap NFS server side probe points
@@ -29,7 +29,7 @@ It contains the following probe points:
.TP
.B nfsd.proc.lookup
-Fires whenever client opens/searchs file on server
+Fires whenever client opens/searches file on server
.B Arguments:
@@ -78,7 +78,7 @@ Fires whenever client reads file on server
the offset of file
.I vec
- struct kvec ,includes buf address in kernel address
+ struct kvec, includes buf address in kernel address
and the length of each buffer
.I vlen
@@ -111,7 +111,7 @@ Fires whenever client writes data to file on server
the offset of file
.I vec
- struct kvec ,includes buf address in kernel address
+ struct kvec, includes buf address in kernel address
and the length of each buffer
.I vlen
@@ -294,7 +294,7 @@ Fires whenever server reads file
the offset of file
.I vec
- struct kvec ,includes buf address in kernel address
+ struct kvec, includes buf address in kernel address
and the length of each buffer
.I vlen
@@ -321,7 +321,7 @@ Fires whenever server writes file
the offset of file
.I vec
- struct kvec ,includes buf address in kernel address
+ struct kvec, includes buf address in kernel address
and the length of each buffer
.I vlen
@@ -348,7 +348,7 @@ Fires when server commits all pending writes to stable storage
.TP
.B nfsd.lookup
-Fires whenever client opens/searchs file on server
+Fires whenever client opens/searches file on server
.B Arguments:
@@ -394,7 +394,7 @@ Fires whenever client opens/searchs file on server
.B nfsd.createv3
Fires when client creates a regular file or set file attributes
-on server side,only called by nfsd3_proc_create and nfsd4_open
+on server side, only called by nfsd3_proc_create and nfsd4_open
(op_claim_type is NFS4_OPEN_CLAIM_NULL)
.B Arguments:
@@ -415,14 +415,14 @@ on server side,only called by nfsd3_proc_create and nfsd4_open
file access mode
.I createmode
- create mode .The possible values could be:
+ create mode. The possible values could be:
NFS3_CREATE_EXCLUSIVE,NFS3_CREATE_UNCHECKED,NFS3_CREATE_GUARDED
.I truncp
- trunp arguments, indicates if the file shouldbe truncate
+ trunp arguments, indicates if the file should be truncated
.I verfier
- file attributes (atime,mtime,mode).It's used to reset file
+ file attributes (atime,mtime,mode). It's used to reset file
attributes for CREATE_EXCLUSIVE
.P
@@ -485,7 +485,7 @@ Fires whenever server closes file
.TP
.B nfsd.dispatch
-Fires whenever server receives NFS operation from client
+Fires whenever server receives NFS operation from client
.B Arguments:
@@ -509,5 +509,5 @@ Fires whenever server receives NFS operation from client
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.pagefault.5.in b/man/stapprobes.pagefault.3stap.in
index ea93f325..7d4f266e 100644
--- a/man/stapprobes.pagefault.5.in
+++ b/man/stapprobes.pagefault.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.PAGEFAULT 5 @DATE@ "IBM"
+.TH STAPPROBES.PAGEFAULT 3stap @DATE@ "IBM"
.SH NAME
stapprobes.pagefault \- systemtap pagefault probe points
@@ -36,5 +36,5 @@ Fires when there is a pagefault
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.rpc.5.in b/man/stapprobes.rpc.3stap.in
index 7f411de6..02b37a8b 100644
--- a/man/stapprobes.rpc.5.in
+++ b/man/stapprobes.rpc.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.RPC 5 @DATE@ "IBM"
+.TH STAPPROBES.RPC 3stap @DATE@ "IBM"
.SH NAME
stapprobes.rpc \- systemtap SunRPC probe points
@@ -375,7 +375,7 @@ Fires when an RPC client is to be processed
The procedure number in the request
.I rq_prot
- The IP protocol of the reqeust
+ The IP protocol of the request
.P
.TP
@@ -403,7 +403,7 @@ Fires when an RPC client is to be authorised
The procedure number in the request
.I rq_prot
- The IP protocol of the reqeust
+ The IP protocol of the request
.P
.TP
@@ -450,7 +450,7 @@ Fires when want to return reply to client
The procedure number in the request
.I rq_prot
- The IP protocol of the reqeust
+ The IP protocol of the request
.P
.TP
@@ -478,7 +478,7 @@ Fires when a request is to be dropped
The procedure number in the request
.I rq_prot
- The IP protocol of the reqeust
+ The IP protocol of the request
.P
.TP
@@ -579,5 +579,5 @@ Fires when a task is to be delayed
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.scsi.5.in b/man/stapprobes.scsi.3stap.in
index bbebcc81..afe16541 100644
--- a/man/stapprobes.scsi.5.in
+++ b/man/stapprobes.scsi.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.SCSI 5 @DATE@ "IBM"
+.TH STAPPROBES.SCSI 3stap @DATE@ "IBM"
.SH NAME
stapprobes.scsi \- systemtap scsi probe points
@@ -147,5 +147,5 @@ block device I/O requests
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.signal.5.in b/man/stapprobes.signal.3stap.in
index dc669b0c..cdaa51b9 100644
--- a/man/stapprobes.signal.5.in
+++ b/man/stapprobes.signal.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.SIGNAL 5 @DATE@ "IBM"
+.TH STAPPROBES.SIGNAL 3stap @DATE@ "IBM"
.SH NAME
stapprobes.signal \- systemtap signal probe points
@@ -74,7 +74,7 @@ Fires when return from sending a signal
.RS
.RS
-- return 0 if the signal is sucessfully sent to a process,
+- return 0 if the signal is successfully sent to a process,
which means the following:
<1> the signal is ignored by receiving process
@@ -90,7 +90,7 @@ by user using something other than kill()
Return values for "send_group_sigqueue"
.RS
-- return 0 if the signal is either sucessfully added into the
+- return 0 if the signal is either successfully added into the
sigqueue of receiving process or a SI_TIMER entry is already
queued so just increment the overrun count
@@ -100,7 +100,7 @@ queued so just increment the overrun count
Return values for "send_sigqueue"
.RS
-- return 0 if the signal is either sucessfully added into the
+- return 0 if the signal is either successfully added into the
sigqueue of receiving process or a SI_TIMER entry is already
queued so just increment the overrun count
@@ -186,8 +186,8 @@ Fires when wake up the process for new active signals
indicate whether to wake up a task in STOPPED or TRACED state
.I state_mask
- a string representation indicate the mask of task states
-that can be woken. Possible values are
+ a string representation indicate the mask of task states
+that can be woken. Possible values are
(TASK_INTERRUPTIBLE|TASK_STOPPED|TASK_TRACED) and
TASK_INTERRUPTIBLE.
@@ -505,5 +505,5 @@ Fires when flush all pending signals for a task
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.socket.5.in b/man/stapprobes.socket.3stap.in
index 6c939fd2..fa6f1c0a 100644
--- a/man/stapprobes.socket.5.in
+++ b/man/stapprobes.socket.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.SOCKET 5 @DATE@ "IBM"
+.TH STAPPROBES.SOCKET 3stap @DATE@ "IBM"
.SH NAME
stapprobes.socket \- systemtap socket probe points
@@ -52,7 +52,7 @@ The message sender.
to convert to a string.
Common values include:
- 0 - IP (Internet Procotol, local interprocess communications)
+ 0 - IP (Internet Protocol, local interprocess communications)
6 - TCP (Transmission Control Protocol)
17 - UDP (User Datagram Protocol)
132 - SCTP (Stream Control Transmission Protocol)
@@ -481,5 +481,5 @@ The socket closer.
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
-.IR stapfuncs (5)
+.IR stapprobes (3stap),
+.IR stapfuncs (3stap)
diff --git a/man/stapprobes.tcp.5.in b/man/stapprobes.tcp.3stap.in
index c5194261..88603f58 100644
--- a/man/stapprobes.tcp.5.in
+++ b/man/stapprobes.tcp.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.TCP 5 @DATE@ "IBM, Intel"
+.TH STAPPROBES.TCP 3stap @DATE@ "IBM, Intel"
.SH NAME
stapprobes.tcp \- systemtap tcp probe points
@@ -98,5 +98,5 @@ Fires when returning from tcp.disconnect
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/man/stapprobes.udp.5.in b/man/stapprobes.udp.3stap.in
index 6e89adf0..dae11578 100644
--- a/man/stapprobes.udp.5.in
+++ b/man/stapprobes.udp.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES.UDP 5 @DATE@ "Intel"
+.TH STAPPROBES.UDP 3stap @DATE@ "Intel"
.SH NAME
stapprobes.udp \- systemtap udp probe points
@@ -98,5 +98,5 @@ Fires when returning from udp.disconnect
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
+.IR stapprobes (3stap)
diff --git a/modsign.cxx b/modsign.cxx
new file mode 100644
index 00000000..8f29dab1
--- /dev/null
+++ b/modsign.cxx
@@ -0,0 +1,555 @@
+/*
+ This program signs the given file using the named certificate and private
+ key in the given certificate database and places the signature in the named
+ output file.
+
+ Copyright (C) 2009 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 as published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "session.h"
+#include "util.h"
+#include <iostream>
+#include <string>
+
+extern "C" {
+#include "nsscommon.h"
+
+#include <nspr.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <cryptohi.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+}
+
+using namespace std;
+
+/* Function: int check_cert_db_permissions (const string &cert_db_path);
+ *
+ * Check that the given certificate directory and its contents have
+ * the correct permissions.
+ *
+ * Returns 0 if there is an error, 1 otherwise.
+ */
+static int
+check_cert_file_permissions (
+ const string &cert_file,
+ uid_t euid,
+ const struct passwd *pw
+) {
+ struct stat info;
+ int rc;
+
+ rc = stat (cert_file.c_str (), & info);
+ if (rc)
+ {
+ cerr << "Could not obtain information on certificate file " << cert_file << "." << endl;
+ perror ("");
+ return 0;
+ }
+
+ rc = 1; // ok
+
+ // We must be the owner of the file.
+ if (info.st_uid != euid)
+ {
+ cerr << "Certificate file " << cert_file << " must be owned by "
+ << pw->pw_name << endl;
+ rc = 0;
+ }
+
+ // Check the access permissions of the file
+ if ((info.st_mode & S_IRUSR) == 0)
+ cerr << "Certificate file " << cert_file << " should be readable by the owner" << "." << endl;
+ if ((info.st_mode & S_IWUSR) == 0)
+ cerr << "Certificate file " << cert_file << " should be writeable by the owner" << "." << endl;
+ if ((info.st_mode & S_IXUSR) != 0)
+ {
+ cerr << "Certificate file " << cert_file << " must not be executable by the owner" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IRGRP) == 0)
+ cerr << "Certificate file " << cert_file << " should be readable by the group" << "." << endl;
+ if ((info.st_mode & S_IWGRP) != 0)
+ {
+ cerr << "Certificate file " << cert_file << " must not be writable by the group" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXGRP) != 0)
+ {
+ cerr << "Certificate file " << cert_file << " must not be executable by the group" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IROTH) == 0)
+ cerr << "Certificate file " << cert_file << " should be readable by others" << "." << endl;
+ if ((info.st_mode & S_IWOTH) != 0)
+ {
+ cerr << "Certificate file " << cert_file << " must not be writable by others" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXOTH) != 0)
+ {
+ cerr << "Certificate file " << cert_file << " must not be executable by others" << "." << endl;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/* Function: int check_cert_db_permissions (const string &cert_db_path);
+ *
+ * Check that the given certificate directory and its contents have
+ * the correct permissions.
+ *
+ * Returns 0 if there is an error, 1 otherwise.
+ */
+static int
+check_db_file_permissions (
+ const string &cert_db_file,
+ uid_t euid,
+ const struct passwd *pw
+) {
+ struct stat info;
+ int rc;
+
+ rc = stat (cert_db_file.c_str (), & info);
+ if (rc)
+ {
+ cerr << "Could not obtain information on certificate database file " << cert_db_file << "." << endl;
+ perror ("");
+ return 0;
+ }
+
+ rc = 1; // ok
+
+ // We must be the owner of the file.
+ if (info.st_uid != euid)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must be owned by "
+ << pw->pw_name << endl;
+ rc = 0;
+ }
+
+ // Check the access permissions of the file
+ if ((info.st_mode & S_IRUSR) == 0)
+ cerr << "Certificate database file " << cert_db_file << " should be readable by the owner" << "." << endl;
+ if ((info.st_mode & S_IWUSR) == 0)
+ cerr << "Certificate database file " << cert_db_file << " should be writeable by the owner" << "." << endl;
+ if ((info.st_mode & S_IXUSR) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be executable by the owner" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IRGRP) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be readable by the group" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IWGRP) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be writable by the group" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXGRP) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be executable by the group" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IROTH) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be readable by others" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IWOTH) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be writable by others" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXOTH) != 0)
+ {
+ cerr << "Certificate database file " << cert_db_file << " must not be executable by others" << "." << endl;
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/* Function: int check_cert_db_permissions (const string &cert_db_path);
+ *
+ * Check that the given certificate directory and its contents have
+ * the correct permissions.
+ *
+ * Returns 0 if there is an error, 1 otherwise.
+ */
+static int
+check_cert_db_permissions (const string &cert_db_path) {
+ struct stat info;
+ const struct passwd *pw;
+ uid_t euid;
+ int rc;
+
+ rc = stat (cert_db_path.c_str (), & info);
+ if (rc)
+ {
+ cerr << "Could not obtain information on certificate database directory " << cert_db_path << "." << endl;
+ perror ("");
+ return 0;
+ }
+
+ rc = 1; // ok
+
+ // We must be the owner of the database.
+ euid = geteuid ();
+ pw = getpwuid (euid);
+ if (! pw)
+ {
+ cerr << "Unable to obtain current user information which checking certificate database "
+ << cert_db_path << endl;
+ perror ("");
+ return 0;
+ }
+ if (info.st_uid != euid)
+ {
+ cerr << "Certificate database " << cert_db_path << " must be owned by "
+ << pw->pw_name << endl;
+ rc = 0;
+ }
+
+ // Check the database directory access permissions
+ if ((info.st_mode & S_IRUSR) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be readable by the owner" << "." << endl;
+ if ((info.st_mode & S_IWUSR) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be writeable by the owner" << "." << endl;
+ if ((info.st_mode & S_IXUSR) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be searchable by the owner" << "." << endl;
+ if ((info.st_mode & S_IRGRP) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be readable by the group" << "." << endl;
+ if ((info.st_mode & S_IWGRP) != 0)
+ {
+ cerr << "Certificate database " << cert_db_path << " must not be writable by the group" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXGRP) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be searchable by the group" << "." << endl;
+ if ((info.st_mode & S_IROTH) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be readable by others" << "." << endl;
+ if ((info.st_mode & S_IWOTH) != 0)
+ {
+ cerr << "Certificate database " << cert_db_path << " must not be writable by others" << "." << endl;
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXOTH) == 0)
+ cerr << "Certificate database " << cert_db_path << " should be searchable by others" << "." << endl;
+
+ // Now check the permissions of the critical files.
+ rc &= check_db_file_permissions (cert_db_path + "/cert8.db", euid, pw);
+ rc &= check_db_file_permissions (cert_db_path + "/key3.db", euid, pw);
+ rc &= check_db_file_permissions (cert_db_path + "/secmod.db", euid, pw);
+ rc &= check_db_file_permissions (cert_db_path + "/pw", euid, pw);
+ rc &= check_cert_file_permissions (cert_db_path + "/stap.cert", euid, pw);
+
+ if (rc == 0)
+ cerr << "Unable to use certificate database " << cert_db_path << " due to errors" << "." << endl;
+
+ return rc;
+}
+
+/* Function: int init_cert_db_path (const string &cert_db_path);
+ *
+ * Initialize a certificate database at the given path.
+ */
+static int
+init_cert_db_path (const string &cert_db_path) {
+ int rc;
+
+ // Generate the certificate and database.
+ string cmd = BINDIR "/stap-gen-cert " + cert_db_path;
+ rc = stap_system (cmd.c_str()) == 0;
+
+ // If we are root, authorize the new certificate as a trusted
+ // signer. It is not an error if this fails.
+ if (geteuid () == 0)
+ {
+ cmd = BINDIR "/stap-authorize-signing-cert " + cert_db_path + "/stap.cert";
+ stap_system (cmd.c_str());
+ }
+
+ return rc;
+}
+
+/* Function: int check_cert_db_path (const string &cert_db_path);
+ *
+ * Check that the given certificate directory exists and is initialized.
+ * Create and/or initialize it otherwise.
+ */
+static int
+check_cert_db_path (const string &cert_db_path) {
+ // Does the path exist?
+ PRFileInfo fileInfo;
+ PRStatus prStatus = PR_GetFileInfo (cert_db_path.c_str(), &fileInfo);
+ if (prStatus != PR_SUCCESS || fileInfo.type != PR_FILE_DIRECTORY)
+ return init_cert_db_path (cert_db_path);
+
+ // Update the user's cert file if it is old.
+ string fname = cert_db_path + "/stap-server.cert";
+ prStatus = PR_GetFileInfo (fname.c_str (), &fileInfo);
+ if (prStatus == PR_SUCCESS && fileInfo.type == PR_FILE_FILE && fileInfo.size > 0)
+ {
+ string fname1 = cert_db_path + "/stap.cert";
+ prStatus = PR_GetFileInfo (fname1.c_str (), &fileInfo);
+ if (prStatus != PR_SUCCESS)
+ PR_Rename (fname.c_str (), fname1.c_str ());
+ else
+ PR_Delete (fname.c_str ());
+ }
+
+ return check_cert_db_permissions (cert_db_path);
+}
+
+/* Function: char * password_callback()
+ *
+ * Purpose: This function is our custom password handler that is called by
+ * NSS when retrieving private certs and keys from the database. Returns a
+ * pointer to a string that with a password for the database. Password pointer
+ * should point to dynamically allocated memory that will be freed later.
+ */
+static char *
+password_callback (PK11SlotInfo *info, PRBool retry, void *arg)
+{
+ char *passwd = NULL;
+
+ if (! retry && arg)
+ passwd = PORT_Strdup((char *)arg);
+
+ return passwd;
+}
+
+/* Obtain the certificate and key database password from the given file. */
+static char *
+get_password (const string &fileName)
+{
+ PRFileDesc *local_file_fd;
+ PRFileInfo fileInfo;
+ PRInt32 numBytesRead;
+ PRStatus prStatus;
+ PRInt32 i;
+ char *password;
+
+ prStatus = PR_GetFileInfo (fileName.c_str(), &fileInfo);
+ if (prStatus != PR_SUCCESS || fileInfo.type != PR_FILE_FILE || fileInfo.size < 0)
+ {
+ cerr << "Could not obtain information on password file " << fileName << "." << endl;
+ nssError ();
+ return NULL;
+ }
+
+ local_file_fd = PR_Open (fileName.c_str(), PR_RDONLY, 0);
+ if (local_file_fd == NULL)
+ {
+ cerr << "Could not open password file " << fileName << "." << endl;
+ nssError ();
+ return NULL;
+ }
+
+ password = (char*)PORT_Alloc (fileInfo.size + 1);
+ if (! password)
+ {
+ cerr << "Unable to allocate " << (fileInfo.size + 1) << " bytes." << endl;
+ nssError ();
+ return NULL;
+ }
+
+ numBytesRead = PR_Read (local_file_fd, password, fileInfo.size);
+ if (numBytesRead <= 0)
+ {
+ cerr << "Error reading password file " << fileName << "." << endl;
+ nssError ();
+ return 0;
+ }
+
+ PR_Close (local_file_fd);
+
+ /* Keep only the first line of data. */
+ for (i = 0; i < numBytesRead; ++i)
+ {
+ if (password[i] == '\n' || password[i] == '\r' || password[i] == '\0')
+ break;
+ }
+ password[i] = '\0';
+
+ return password;
+}
+
+static void
+sign_it (const string &inputName, const string &outputName, SECKEYPrivateKey *privKey)
+{
+ unsigned char buffer[4096];
+ PRFileDesc *local_file_fd;
+ PRUint32 numBytes;
+ SECStatus secStatus;
+ SGNContext *sgn;
+ SECItem signedData;
+
+ /* Set up the signing context. */
+ sgn = SGN_NewContext (SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, privKey);
+ if (! sgn)
+ {
+ cerr << "Could not create signing context." << endl;
+ nssError ();
+ return;
+ }
+ secStatus = SGN_Begin (sgn);
+ if (secStatus != SECSuccess)
+ {
+ cerr << "Could not initialize signing context." << endl;
+ nssError ();
+ return;
+ }
+
+ /* Now read the data and add it to the signature. */
+ local_file_fd = PR_Open (inputName.c_str(), PR_RDONLY, 0);
+ if (local_file_fd == NULL)
+ {
+ cerr << "Could not open module file " << inputName << "." << endl;
+ nssError ();
+ return;
+ }
+
+ for (;;)
+ {
+ numBytes = PR_Read (local_file_fd, buffer, sizeof (buffer));
+ if (numBytes == 0)
+ break; /* EOF */
+
+ if (numBytes < 0)
+ {
+ cerr << "Error reading module file " << inputName << "." << endl;
+ nssError ();
+ return;
+ }
+
+ /* Add the data to the signature. */
+ secStatus = SGN_Update (sgn, buffer, numBytes);
+ if (secStatus != SECSuccess)
+ {
+ cerr << "Error while signing module file " << inputName << "." << endl;
+ nssError ();
+ return;
+ }
+ }
+
+ PR_Close (local_file_fd);
+
+ /* Complete the signature. */
+ secStatus = SGN_End (sgn, & signedData);
+ if (secStatus != SECSuccess)
+ {
+ cerr << "Could not complete signature of module file " << inputName << "." << endl;
+ nssError ();
+ return;
+ }
+
+ SGN_DestroyContext (sgn, PR_TRUE);
+
+ /* Now write the signed data to the output file. */
+ local_file_fd = PR_Open (outputName.c_str(), PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
+ PR_IRUSR | PR_IWUSR | PR_IRGRP | PR_IWGRP | PR_IROTH);
+ if (local_file_fd == NULL)
+ {
+ cerr << "Could not open signature file " << outputName << "." << endl;
+ nssError ();
+ return;
+ }
+
+ numBytes = PR_Write (local_file_fd, signedData.data, signedData.len);
+ if (numBytes < 0 || numBytes != signedData.len)
+ {
+ cerr << "Error writing to signature file " << outputName << "." << endl;
+ nssError ();
+ return;
+ }
+
+ PR_Close (local_file_fd);
+}
+
+void
+sign_module (systemtap_session& s)
+{
+ const char *nickName = "stap-server";
+ char *password;
+ CERTCertificate *cert;
+ SECKEYPrivateKey *privKey;
+ SECStatus secStatus;
+
+ if (! check_cert_db_path (s.cert_db_path))
+ return;
+
+ password = get_password (s.cert_db_path + "/pw");
+ if (! password)
+ {
+ cerr << "Unable to obtain certificate database password." << endl;
+ return;
+ }
+
+ /* Call the NSPR initialization routines. */
+ PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+
+ /* Set the cert database password callback. */
+ PK11_SetPasswordFunc (password_callback);
+
+ /* Initialize NSS. */
+ secStatus = NSS_Init (s.cert_db_path.c_str());
+ if (secStatus != SECSuccess)
+ {
+ cerr << "Unable to initialize nss library." << endl;
+ nssError ();
+ return;
+ }
+
+ /* Get own certificate and private key. */
+ cert = PK11_FindCertFromNickname (nickName, password);
+ if (cert == NULL)
+ {
+ cerr << "Unable to find certificate with nickname " << nickName
+ << " in " << s.cert_db_path << "." << endl;
+ nssError ();
+ return;
+ }
+
+ privKey = PK11_FindKeyByAnyCert (cert, password);
+ if (privKey == NULL)
+ {
+ cerr << "Unable to obtain private key from the certificate with nickname " << nickName
+ << " in " << s.cert_db_path << "." << endl;
+ nssError ();
+ return;
+ }
+
+ /* Sign the file. */
+ sign_it (s.tmpdir + "/" + s.module_name + ".ko", s.tmpdir + "/" + s.module_name + ".ko.sgn", privKey);
+
+ /* Shutdown NSS and exit NSPR gracefully. */
+ nssCleanup ();
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/modsign.h b/modsign.h
new file mode 100644
index 00000000..2d39899a
--- /dev/null
+++ b/modsign.h
@@ -0,0 +1,3 @@
+void sign_module (systemtap_session& s);
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/nsscommon.c b/nsscommon.c
new file mode 100644
index 00000000..2e9c748b
--- /dev/null
+++ b/nsscommon.c
@@ -0,0 +1,85 @@
+/*
+ Common functions used by the NSS-aware code in systemtap.
+
+ Copyright (C) 2009 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 as published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+
+#include <nss.h>
+#include <nspr.h>
+#include <prerror.h>
+#include <secerr.h>
+#include <sslerr.h>
+
+void
+nssError (void)
+{
+ PRErrorCode errorNumber;
+ PRInt32 errorTextLength;
+ PRInt32 rc;
+ char *errorText;
+
+ /* See if PR_GetErrorText can tell us what the error is. */
+ errorNumber = PR_GetError ();
+ if (errorNumber >= PR_NSPR_ERROR_BASE && errorNumber <= PR_MAX_ERROR)
+ {
+ errorTextLength = PR_GetErrorTextLength ();
+ if (errorTextLength != 0) {
+ errorText = PORT_Alloc (errorTextLength);
+ rc = PR_GetErrorText (errorText);
+ if (rc != 0)
+ fprintf (stderr, "%s\n", errorText);
+ PR_Free (errorText);
+ if (rc != 0)
+ return;
+ }
+ }
+
+ /* Otherwise handle common errors ourselves. */
+ switch (errorNumber)
+ {
+ case PR_CONNECT_RESET_ERROR:
+ fputs ("Connection reset by peer.\n", stderr);
+ break;
+ case SEC_ERROR_BAD_DATABASE:
+ fputs ("The specified certificate database does not exist or is not valid.\n", stderr);
+ break;
+ case SEC_ERROR_BAD_SIGNATURE:
+ fputs ("Certificate does not match the signature.\n", stderr);
+ break;
+ case SEC_ERROR_CA_CERT_INVALID:
+ fputs ("The issuer's certificate is invalid.\n", stderr);
+ break;
+ case SSL_ERROR_BAD_CERT_DOMAIN:
+ fputs ("The requested domain name does not match the server's certificate.\n", stderr);
+ break;
+ default:
+ fprintf (stderr, "Unknown NSS error: %d.\n", errorNumber);
+ break;
+ }
+}
+
+void
+nssCleanup (void)
+{
+ /* Shutdown NSS and exit NSPR gracefully. */
+ NSS_Shutdown ();
+ PR_Cleanup ();
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/nsscommon.h b/nsscommon.h
new file mode 100644
index 00000000..c6ab8aa7
--- /dev/null
+++ b/nsscommon.h
@@ -0,0 +1,4 @@
+void nssError (void);
+void nssCleanup (void);
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/parse.cxx b/parse.cxx
index ac7e652c..a26d594c 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -2341,6 +2341,12 @@ parser::parse_symbol ()
cop->operand = parse_expression ();
expect_op(",");
expect_unknown(tok_string, cop->type);
+ // types never start with "struct<space>" or "union<space>",
+ // so gobble it up.
+ if (cop->type.compare(0, 7, "struct ") == 0)
+ cop->type = cop->type.substr(7);
+ if (cop->type.compare(0, 6, "union ") == 0)
+ cop->type = cop->type.substr(6);
if (peek_op (","))
{
next();
diff --git a/run-stap.in b/run-stap.in
index dfb53ab2..8b150ece 100644
--- a/run-stap.in
+++ b/run-stap.in
@@ -19,11 +19,8 @@ esac
# Set all the variables to find the source and build trees.
SYSTEMTAP_TAPSET="${srcdir}/tapset"
SYSTEMTAP_RUNTIME="${srcdir}/runtime"
-SYSTEMTAP_STAPIO="${builddir}/stapio"
-SYSTEMTAP_STAPRUN="sudo 'SYSTEMTAP_STAPIO=$SYSTEMTAP_STAPIO' \
- 'SYSTEMTAP_STAPRUN=${builddir}/staprun' \
- ${builddir}/staprun"
-export SYSTEMTAP_TAPSET SYSTEMTAP_RUNTIME SYSTEMTAP_STAPRUN SYSTEMTAP_STAPIO
+SYSTEMTAP_STAPRUN="${builddir}/run-staprun"
+export SYSTEMTAP_TAPSET SYSTEMTAP_RUNTIME SYSTEMTAP_STAPRUN
# If there were private elfutils libs built, use them.
if [ -d "$rundir/lib-elfutils" ]; then
diff --git a/run-staprun.in b/run-staprun.in
new file mode 100644
index 00000000..e0615556
--- /dev/null
+++ b/run-staprun.in
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+srcdir='@abs_top_srcdir@'
+builddir='@abs_top_builddir@'
+
+rundir="${0%/*}"
+[ "$rundir" == "$0" ] || builddir="$rundir"
+
+# Absolutify the paths.
+case "$srcdir" in
+/*) ;;
+*) srcdir=`cd "$srcdir" && pwd` || exit ;;
+esac
+case "$builddir" in
+/*) ;;
+*) builddir=`cd "$builddir" && pwd` || exit ;;
+esac
+
+exec sudo -P "SYSTEMTAP_STAPIO=${builddir}/stapio" \
+ "SYSTEMTAP_STAPRUN=${builddir}/run-staprun" \
+ "SYSTEMTAP_RUNTIME=${srcdir}/runtime" \
+ "SYSTEMTAP_REAL_UID=`id -ru`" \
+ "SYSTEMTAP_REAL_GID=`id -rg`" \
+ ${builddir}/staprun ${1+"$@"}
diff --git a/runtime/autoconf-asm-syscall.c b/runtime/autoconf-asm-syscall.c
new file mode 100644
index 00000000..bf7a273f
--- /dev/null
+++ b/runtime/autoconf-asm-syscall.c
@@ -0,0 +1,2 @@
+#include <asm/syscall.h>
+
diff --git a/runtime/autoconf-find-task-pid.c b/runtime/autoconf-find-task-pid.c
new file mode 100644
index 00000000..549d5ac3
--- /dev/null
+++ b/runtime/autoconf-find-task-pid.c
@@ -0,0 +1,6 @@
+#include <linux/sched.h>
+
+void foo (pid_t k) {
+ struct task_struct *tsk = find_task_by_pid (k);
+ (void) tsk;
+}
diff --git a/runtime/autoconf-x86-gs.c b/runtime/autoconf-x86-gs.c
new file mode 100644
index 00000000..f4dda795
--- /dev/null
+++ b/runtime/autoconf-x86-gs.c
@@ -0,0 +1,5 @@
+#include <asm/ptrace.h>
+
+#if defined (__i386__)
+struct pt_regs regs = {.gs = 0x0};
+#endif
diff --git a/runtime/itrace.c b/runtime/itrace.c
index ed32b0bc..68f85301 100644
--- a/runtime/itrace.c
+++ b/runtime/itrace.c
@@ -1,6 +1,7 @@
/*
* user space instruction tracing
* Copyright (C) 2005, 2006, 2007, 2008, 2009 IBM Corp.
+ * Copyright (C) 2009 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
@@ -17,8 +18,16 @@
#include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/utrace.h>
+#include "ptrace_compatibility.h"
+
+/* PR9974: Adapt to struct renaming. */
+#ifdef UTRACE_API_VERSION
+#define utrace_attached_engine utrace_engine
+#endif
+
#include <asm/string.h>
#include "uprobes/uprobes.h"
+#include "utrace_compatibility.h"
#ifndef put_task_struct
#define put_task_struct(t) \
@@ -55,7 +64,7 @@ struct itrace_info {
struct list_head link;
};
-static u32 debug = 1;
+static u32 debug = 0 /* 1 */;
static LIST_HEAD(usr_itrace_info);
static spinlock_t itrace_lock;
@@ -118,10 +127,15 @@ static int __access_process_vm(struct task_struct *tsk, unsigned long addr, void
return buf - old_buf;
}
+#ifdef UTRACE_ORIG_VERSION
+static u32 usr_itrace_report_quiesce(struct utrace_attached_engine *engine,
+ struct task_struct *tsk)
+#else
static u32 usr_itrace_report_quiesce(enum utrace_resume_action action,
struct utrace_attached_engine *engine,
struct task_struct *tsk,
unsigned long event)
+#endif
{
int status;
struct itrace_info *ui;
@@ -129,10 +143,23 @@ static u32 usr_itrace_report_quiesce(enum utrace_resume_action action,
ui = rcu_dereference(engine->data);
WARN_ON(!ui);
+#ifdef UTRACE_ORIG_VERSION
+ return (ui->step_flag | UTRACE_ACTION_NEWSTATE);
+#else
return (event == 0 ? ui->step_flag : UTRACE_RESUME);
+#endif
}
+#ifdef UTRACE_ORIG_VERSION
+static u32 usr_itrace_report_signal(
+ struct utrace_attached_engine *engine,
+ struct task_struct *tsk,
+ struct pt_regs *regs,
+ u32 action, siginfo_t *info,
+ const struct k_sigaction *orig_ka,
+ struct k_sigaction *return_ka)
+#else
static u32 usr_itrace_report_signal(u32 action,
struct utrace_attached_engine *engine,
struct task_struct *tsk,
@@ -140,6 +167,7 @@ static u32 usr_itrace_report_signal(u32 action,
siginfo_t *info,
const struct k_sigaction *orig_ka,
struct k_sigaction *return_ka)
+#endif
{
struct itrace_info *ui;
u32 return_flags;
@@ -174,16 +202,31 @@ static u32 usr_itrace_report_signal(u32 action,
return return_flags;
}
+
+
+#ifdef UTRACE_ORIG_VERSION
+static u32 usr_itrace_report_clone(
+ struct utrace_attached_engine *engine,
+ struct task_struct *parent,
+ unsigned long clone_flags,
+ struct task_struct *child)
+#else
static u32 usr_itrace_report_clone(enum utrace_resume_action action,
struct utrace_attached_engine *engine,
struct task_struct *parent, unsigned long clone_flags,
struct task_struct *child)
+#endif
{
return UTRACE_RESUME;
}
+#ifdef UTRACE_ORIG_VERSION
+static u32 usr_itrace_report_death(struct utrace_attached_engine *e,
+ struct task_struct *tsk)
+#else
static u32 usr_itrace_report_death(struct utrace_attached_engine *e,
struct task_struct *tsk, bool group_dead, int signal)
+#endif
{
struct itrace_info *ui = rcu_dereference(e->data);
WARN_ON(!ui);
@@ -275,8 +318,13 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe
struct itrace_info *ui;
struct task_struct *tsk;
+ spin_lock_init(&itrace_lock);
rcu_read_lock();
+#ifdef STAPCONF_FIND_TASK_PID
+ tsk = find_task_by_pid(tid);
+#else
tsk = find_task_by_vpid(tid);
+#endif
if (!tsk) {
printk(KERN_ERR "usr_itrace_init: Cannot find process %d\n", tid);
rcu_read_unlock();
@@ -293,12 +341,8 @@ static int usr_itrace_init(int single_step, pid_t tid, struct stap_itrace_probe
put_task_struct(tsk);
rcu_read_unlock();
- spin_lock_init(&itrace_lock);
-
- /* set initial state */
- spin_lock(&itrace_lock);
- spin_unlock(&itrace_lock);
- printk(KERN_INFO "usr_itrace_init: completed for tid = %d\n", tid);
+ if (debug)
+ printk(KERN_INFO "usr_itrace_init: completed for tid = %d\n", tid);
return 0;
}
@@ -314,7 +358,6 @@ void static remove_usr_itrace_info(struct itrace_info *ui)
if (debug)
printk(KERN_INFO "remove_usr_itrace_info: tid=%d\n", ui->tid);
- spin_lock(&itrace_lock);
if (ui->tsk && ui->engine) {
status = utrace_control(ui->tsk, ui->engine, UTRACE_DETACH);
if (status < 0 && status != -ESRCH && status != -EALREADY)
@@ -322,6 +365,7 @@ void static remove_usr_itrace_info(struct itrace_info *ui)
"utrace_control(UTRACE_DETACH) returns %d\n",
status);
}
+ spin_lock(&itrace_lock);
list_del(&ui->link);
spin_unlock(&itrace_lock);
kfree(ui);
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
index 0af19edc..620e1615 100644
--- a/runtime/loc2c-runtime.h
+++ b/runtime/loc2c-runtime.h
@@ -29,11 +29,12 @@
& (((__typeof (base)) 1 << (nbits)) - 1))
#define store_bitfield(target, base, higherbits, nbits) \
- target = (target \
- &~ ((((__typeof (base)) 1 << (nbits)) - 1) \
- << (sizeof (base) * 8 - (higherbits) - (nbits))) \
- | ((__typeof (base)) (base) \
- << (sizeof (base) * 8 - (higherbits) - (nbits))))
+ target = ((target \
+ &~ ((((__typeof (target)) 1 << (nbits)) - 1) \
+ << (sizeof (target) * 8 - (higherbits) - (nbits)))) \
+ | ((((__typeof (target)) (base)) \
+ & (((__typeof (target)) 1 << (nbits)) - 1)) \
+ << (sizeof (target) * 8 - (higherbits) - (nbits))))
/* Given a DWARF register number, fetch its intptr_t (long) value from the
@@ -62,6 +63,10 @@
must work right for kernel addresses, and can use whatever existing
machine-specific kernel macros are convenient. */
+#if STP_SKIP_BADVARS
+#define DEREF_FAULT(addr) ({0; })
+#define STORE_DEREF_FAULT(addr) ({0; })
+#else
#define DEREF_FAULT(addr) ({ \
snprintf(c->error_buffer, sizeof(c->error_buffer), \
"kernel read fault at 0x%p (%s)", (void *)(intptr_t)(addr), #addr); \
@@ -75,7 +80,7 @@
c->last_error = c->error_buffer; \
goto deref_fault; \
})
-
+#endif
#if defined (STAPCONF_X86_UNIREGS) && defined (__i386__)
@@ -186,37 +191,34 @@
*/
#define kread(ptr) ({ \
- typeof(*(ptr)) _v; \
- if (probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \
- DEREF_FAULT(ptr); \
+ typeof(*(ptr)) _v = 0; \
+ if (lookup_bad_addr((unsigned long)(ptr)) || \
+ probe_kernel_read((void *)&_v, (void *)(ptr), sizeof(*(ptr)))) \
+ DEREF_FAULT(ptr); \
_v; \
})
#define kwrite(ptr, value) ({ \
typeof(*(ptr)) _v; \
_v = (typeof(*(ptr)))(value); \
- if (probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \
- STORE_DEREF_FAULT(ptr); \
+ if (lookup_bad_addr((unsigned long)addr) || \
+ probe_kernel_write((void *)(ptr), (void *)&_v, sizeof(*(ptr)))) \
+ STORE_DEREF_FAULT(ptr); \
})
#define deref(size, addr) ({ \
- intptr_t _i; \
- if (lookup_bad_addr((unsigned long)addr)) \
- __deref_bad(); \
+ intptr_t _i = 0; \
switch (size) { \
case 1: _i = kread((u8 *)(addr)); break; \
case 2: _i = kread((u16 *)(addr)); break; \
case 4: _i = kread((u32 *)(addr)); break; \
case 8: _i = kread((u64 *)(addr)); break; \
default: __deref_bad(); \
- /* uninitialized _i should also be caught by -Werror */ \
} \
_i; \
})
#define store_deref(size, addr, value) ({ \
- if (lookup_bad_addr((unsigned long)addr)) \
- __store_deref_bad(); \
switch (size) { \
case 1: kwrite((u8 *)(addr), (value)); break; \
case 2: kwrite((u16 *)(addr), (value)); break; \
@@ -237,7 +239,7 @@ extern void __store_deref_bad(void);
({ \
int _bad = 0; \
u8 _b; u16 _w; u32 _l; \
- intptr_t _v; \
+ intptr_t _v = 0; \
if (lookup_bad_addr((unsigned long)addr)) \
_bad = 1; \
else \
@@ -277,7 +279,7 @@ extern void __store_deref_bad(void);
({ \
int _bad = 0; \
u8 _b; u16 _w; u32 _l; u64 _q; \
- intptr_t _v; \
+ intptr_t _v = 0; \
if (lookup_bad_addr((unsigned long)addr)) \
_bad = 1; \
else \
@@ -394,7 +396,7 @@ extern void __store_deref_bad(void);
#define deref(size, addr) \
({ \
int _bad = 0; \
- intptr_t _v; \
+ intptr_t _v = 0; \
if (lookup_bad_addr((unsigned long)addr)) \
_bad = 1; \
else \
diff --git a/runtime/map-gen.c b/runtime/map-gen.c
index c4bdf2c7..fdb75089 100644
--- a/runtime/map-gen.c
+++ b/runtime/map-gen.c
@@ -26,6 +26,14 @@
#define JOIN5x(a,b,c,d,e,f) a##_##b##c##d##e##f
#define JOIN6(a,b,c,d,e,f,g) JOIN6x(a,b,c,d,e,f,g)
#define JOIN6x(a,b,c,d,e,f,g) a##_##b##c##d##e##f##g
+#define JOIN7(a,b,c,d,e,f,g,h) JOIN7x(a,b,c,d,e,f,g,h)
+#define JOIN7x(a,b,c,d,e,f,g,h) a##_##b##c##d##e##f##g##h
+#define JOIN8(a,b,c,d,e,f,g,h,i) JOIN8x(a,b,c,d,e,f,g,h,i)
+#define JOIN8x(a,b,c,d,e,f,g,h,i) a##_##b##c##d##e##f##g##h##i
+#define JOIN9(a,b,c,d,e,f,g,h,i,j) JOIN9x(a,b,c,d,e,f,g,h,i,j)
+#define JOIN9x(a,b,c,d,e,f,g,h,i,j) a##_##b##c##d##e##f##g##h##i##j
+#define JOIN10(a,b,c,d,e,f,g,h,i,j,k) JOIN10x(a,b,c,d,e,f,g,h,i,j,k)
+#define JOIN10x(a,b,c,d,e,f,g,h,i,j,k) a##_##b##c##d##e##f##g##h##i##j##k
#include "map.h"
@@ -162,6 +170,113 @@
#define KEY5_HASH JOIN(KEY5NAME,hash)
#endif /* defined(KEY5_TYPE) */
+#if defined (KEY6_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 6
+#if KEY6_TYPE == STRING
+#define KEY6TYPE char*
+#define KEY6NAME str
+#define KEY6N s
+#define KEY6STOR char key6[MAP_STRING_LENGTH]
+#define KEY6CPY(m) str_copy(m->key6, key6)
+#else
+#define KEY6TYPE int64_t
+#define KEY6NAME int64
+#define KEY6N i
+#define KEY6STOR int64_t key6
+#define KEY6CPY(m) m->key6=key6
+#endif
+#define KEY6_EQ_P JOIN(KEY6NAME,eq_p)
+#define KEY6_HASH JOIN(KEY6NAME,hash)
+#endif /* defined(KEY6_TYPE) */
+
+#if defined (KEY7_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 7
+#if KEY7_TYPE == STRING
+#define KEY7TYPE char*
+#define KEY7NAME str
+#define KEY7N s
+#define KEY7STOR char key7[MAP_STRING_LENGTH]
+#define KEY7CPY(m) str_copy(m->key7, key7)
+#else
+#define KEY7TYPE int64_t
+#define KEY7NAME int64
+#define KEY7N i
+#define KEY7STOR int64_t key7
+#define KEY7CPY(m) m->key7=key7
+#endif
+#define KEY7_EQ_P JOIN(KEY7NAME,eq_p)
+#define KEY7_HASH JOIN(KEY7NAME,hash)
+#endif /* defined(KEY7_TYPE) */
+
+#if defined (KEY7_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 7
+#if KEY7_TYPE == STRING
+#define KEY7TYPE char*
+#define KEY7NAME str
+#define KEY7N s
+#define KEY7STOR char key7[MAP_STRING_LENGTH]
+#define KEY7CPY(m) str_copy(m->key7, key7)
+#else
+#define KEY7TYPE int64_t
+#define KEY7NAME int64
+#define KEY7N i
+#define KEY7STOR int64_t key7
+#define KEY7CPY(m) m->key7=key7
+#endif
+#define KEY7_EQ_P JOIN(KEY7NAME,eq_p)
+#define KEY7_HASH JOIN(KEY7NAME,hash)
+#endif /* defined(KEY7_TYPE) */
+
+#if defined (KEY8_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 8
+#if KEY8_TYPE == STRING
+#define KEY8TYPE char*
+#define KEY8NAME str
+#define KEY8N s
+#define KEY8STOR char key8[MAP_STRING_LENGTH]
+#define KEY8CPY(m) str_copy(m->key8, key8)
+#else
+#define KEY8TYPE int64_t
+#define KEY8NAME int64
+#define KEY8N i
+#define KEY8STOR int64_t key8
+#define KEY8CPY(m) m->key8=key8
+#endif
+#define KEY8_EQ_P JOIN(KEY8NAME,eq_p)
+#define KEY8_HASH JOIN(KEY8NAME,hash)
+#endif /* defined(KEY8_TYPE) */
+
+#if defined (KEY9_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 9
+#if KEY9_TYPE == STRING
+#define KEY9TYPE char*
+#define KEY9NAME str
+#define KEY9N s
+#define KEY9STOR char key9[MAP_STRING_LENGTH]
+#define KEY9CPY(m) str_copy(m->key9, key9)
+#else
+#define KEY9TYPE int64_t
+#define KEY9NAME int64
+#define KEY9N i
+#define KEY9STOR int64_t key9
+#define KEY9CPY(m) m->key9=key9
+#endif
+#define KEY9_EQ_P JOIN(KEY9NAME,eq_p)
+#define KEY9_HASH JOIN(KEY9NAME,hash)
+#endif /* defined(KEY9_TYPE) */
+
+/* Not so many, cowboy! */
+#if defined (KEY10_TYPE)
+#error "excessive key arity == too many array indexes"
+#endif
+
+
+
#if KEY_ARITY == 1
#define KEYSYM(x) JOIN2(x,KEY1N,VALN)
#define ALLKEYS(x) x##1
@@ -187,6 +302,26 @@
#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5
#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5
#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);}
+#elif KEY_ARITY == 6
+#define KEYSYM(x) JOIN7(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);}
+#elif KEY_ARITY == 7
+#define KEYSYM(x) JOIN8(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,KEY7N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6, x##7
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6, KEY7TYPE x##7
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);KEY7CPY(m);}
+#elif KEY_ARITY == 8
+#define KEYSYM(x) JOIN9(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,KEY7N,KEY8N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6, KEY7TYPE x##7, KEY8TYPE x##8
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);KEY7CPY(m);KEY8CPY(m);}
+#elif KEY_ARITY == 9
+#define KEYSYM(x) JOIN10(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,KEY7N,KEY8N,KEY9N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8, x##9
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6, KEY7TYPE x##7, KEY8TYPE x##8, KEY9TYPE x##9
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);KEY7CPY(m);KEY8CPY(m);KEY9CPY(m);}
#endif
/* */
@@ -208,6 +343,18 @@ struct KEYSYM(map_node) {
KEY4STOR;
#if KEY_ARITY > 4
KEY5STOR;
+#if KEY_ARITY > 5
+ KEY6STOR;
+#if KEY_ARITY > 6
+ KEY7STOR;
+#if KEY_ARITY > 7
+ KEY8STOR;
+#if KEY_ARITY > 8
+ KEY9STOR;
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -266,6 +413,34 @@ static key_data KEYSYM(map_get_key) (struct map_node *mn, int n, int *type)
if (type)
*type = type_to_enum(KEY5TYPE);
break;
+#if KEY_ARITY > 5
+ case 6:
+ ptr = (key_data)m->key6;
+ if (type)
+ *type = type_to_enum(KEY6TYPE);
+ break;
+#if KEY_ARITY > 6
+ case 7:
+ ptr = (key_data)m->key7;
+ if (type)
+ *type = type_to_enum(KEY7TYPE);
+ break;
+#if KEY_ARITY > 7
+ case 8:
+ ptr = (key_data)m->key8;
+ if (type)
+ *type = type_to_enum(KEY8TYPE);
+ break;
+#if KEY_ARITY > 8
+ case 9:
+ ptr = (key_data)m->key9;
+ if (type)
+ *type = type_to_enum(KEY9TYPE);
+ break;
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -309,6 +484,34 @@ static unsigned int KEYSYM(keycheck) (ALLKEYSD(key))
if (key5 == NULL)
return 0;
#endif
+
+#if KEY_ARITY > 5
+#if KEY6_TYPE == STRING
+ if (key6 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 6
+#if KEY7_TYPE == STRING
+ if (key7 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 7
+#if KEY8_TYPE == STRING
+ if (key8 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 8
+#if KEY9_TYPE == STRING
+ if (key9 == NULL)
+ return 0;
+#endif
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -327,6 +530,18 @@ static unsigned int KEYSYM(hash) (ALLKEYSD(key))
hash ^= KEY4_HASH(key4);
#if KEY_ARITY > 4
hash ^= KEY5_HASH(key5);
+#if KEY_ARITY > 5
+ hash ^= KEY6_HASH(key6);
+#if KEY_ARITY > 6
+ hash ^= KEY7_HASH(key7);
+#if KEY_ARITY > 7
+ hash ^= KEY8_HASH(key8);
+#if KEY_ARITY > 8
+ hash ^= KEY9_HASH(key9);
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -411,6 +626,18 @@ static int KEYSYM(__stp_map_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add)
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -462,6 +689,18 @@ static VALTYPE KEYSYM(_stp_map_get) (MAP map, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -498,6 +737,18 @@ static int KEYSYM(_stp_map_del) (MAP map, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -535,6 +786,18 @@ static int KEYSYM(_stp_map_exists) (MAP map, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -582,6 +845,34 @@ static int KEYSYM(_stp_map_exists) (MAP map, ALLKEYSD(key))
#undef KEY5STOR
#undef KEY5CPY
+#undef KEY6NAME
+#undef KEY6N
+#undef KEY6TYPE
+#undef KEY6_TYPE
+#undef KEY6STOR
+#undef KEY6CPY
+
+#undef KEY7NAME
+#undef KEY7N
+#undef KEY7TYPE
+#undef KEY7_TYPE
+#undef KEY7STOR
+#undef KEY7CPY
+
+#undef KEY8NAME
+#undef KEY8N
+#undef KEY8TYPE
+#undef KEY8_TYPE
+#undef KEY8STOR
+#undef KEY8CPY
+
+#undef KEY9NAME
+#undef KEY9N
+#undef KEY9TYPE
+#undef KEY9_TYPE
+#undef KEY9STOR
+#undef KEY9CPY
+
#undef KEY_ARITY
#undef ALLKEYS
#undef ALLKEYSD
diff --git a/runtime/map.c b/runtime/map.c
index de25d6f3..74467f30 100644
--- a/runtime/map.c
+++ b/runtime/map.c
@@ -38,27 +38,16 @@ static int int64_eq_p (int64_t key1, int64_t key2)
static void str_copy(char *dest, char *src)
{
- int len = 0;
- if (src) {
- len = strlen(src);
- if (len > MAP_STRING_LENGTH - 1)
- len = MAP_STRING_LENGTH - 1;
- memcpy (dest, src, len);
- }
- dest[len] = 0;
+ if (src)
+ strlcpy(dest, src, MAP_STRING_LENGTH);
+ else
+ *dest = 0;
}
static void str_add(void *dest, char *val)
{
char *dst = (char *)dest;
- int len = strlen(val);
- int len1 = strlen(dst);
- int num = MAP_STRING_LENGTH - 1 - len1;
-
- if (len > num)
- len = num;
- memcpy (&dst[len1], val, len);
- dst[len + len1] = 0;
+ strlcat(dst, val, MAP_STRING_LENGTH);
}
static int str_eq_p (char *key1, char *key2)
@@ -730,7 +719,7 @@ static MAP _stp_pmap_agg (PMAP pmap)
{
int i, hash;
MAP m, agg;
- struct map_node *ptr, *aptr;
+ struct map_node *ptr, *aptr = NULL;
struct hlist_head *head, *ahead;
struct hlist_node *e, *f;
diff --git a/runtime/pmap-gen.c b/runtime/pmap-gen.c
index 86c3dc42..c95adc6b 100644
--- a/runtime/pmap-gen.c
+++ b/runtime/pmap-gen.c
@@ -26,6 +26,14 @@
#define JOIN5x(a,b,c,d,e,f) a##_##b##c##d##e##f
#define JOIN6(a,b,c,d,e,f,g) JOIN6x(a,b,c,d,e,f,g)
#define JOIN6x(a,b,c,d,e,f,g) a##_##b##c##d##e##f##g
+#define JOIN7(a,b,c,d,e,f,g,h) JOIN7x(a,b,c,d,e,f,g,h)
+#define JOIN7x(a,b,c,d,e,f,g,h) a##_##b##c##d##e##f##g##h
+#define JOIN8(a,b,c,d,e,f,g,h,i) JOIN8x(a,b,c,d,e,f,g,h,i)
+#define JOIN8x(a,b,c,d,e,f,g,h,i) a##_##b##c##d##e##f##g##h##i
+#define JOIN9(a,b,c,d,e,f,g,h,i,j) JOIN9x(a,b,c,d,e,f,g,h,i,j)
+#define JOIN9x(a,b,c,d,e,f,g,h,i,j) a##_##b##c##d##e##f##g##h##i##j
+#define JOIN10(a,b,c,d,e,f,g,h,i,j,k) JOIN10x(a,b,c,d,e,f,g,h,i,j,k)
+#define JOIN10x(a,b,c,d,e,f,g,h,i,j,k) a##_##b##c##d##e##f##g##h##i##j##k
#include "map.h"
@@ -162,6 +170,113 @@
#define KEY5_HASH JOIN(KEY5NAME,hash)
#endif /* defined(KEY5_TYPE) */
+#if defined (KEY6_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 6
+#if KEY6_TYPE == STRING
+#define KEY6TYPE char*
+#define KEY6NAME str
+#define KEY6N s
+#define KEY6STOR char key6[MAP_STRING_LENGTH]
+#define KEY6CPY(m) str_copy(m->key6, key6)
+#else
+#define KEY6TYPE int64_t
+#define KEY6NAME int64
+#define KEY6N i
+#define KEY6STOR int64_t key6
+#define KEY6CPY(m) m->key6=key6
+#endif
+#define KEY6_EQ_P JOIN(KEY6NAME,eq_p)
+#define KEY6_HASH JOIN(KEY6NAME,hash)
+#endif /* defined(KEY6_TYPE) */
+
+#if defined (KEY7_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 7
+#if KEY7_TYPE == STRING
+#define KEY7TYPE char*
+#define KEY7NAME str
+#define KEY7N s
+#define KEY7STOR char key7[MAP_STRING_LENGTH]
+#define KEY7CPY(m) str_copy(m->key7, key7)
+#else
+#define KEY7TYPE int64_t
+#define KEY7NAME int64
+#define KEY7N i
+#define KEY7STOR int64_t key7
+#define KEY7CPY(m) m->key7=key7
+#endif
+#define KEY7_EQ_P JOIN(KEY7NAME,eq_p)
+#define KEY7_HASH JOIN(KEY7NAME,hash)
+#endif /* defined(KEY7_TYPE) */
+
+#if defined (KEY7_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 7
+#if KEY7_TYPE == STRING
+#define KEY7TYPE char*
+#define KEY7NAME str
+#define KEY7N s
+#define KEY7STOR char key7[MAP_STRING_LENGTH]
+#define KEY7CPY(m) str_copy(m->key7, key7)
+#else
+#define KEY7TYPE int64_t
+#define KEY7NAME int64
+#define KEY7N i
+#define KEY7STOR int64_t key7
+#define KEY7CPY(m) m->key7=key7
+#endif
+#define KEY7_EQ_P JOIN(KEY7NAME,eq_p)
+#define KEY7_HASH JOIN(KEY7NAME,hash)
+#endif /* defined(KEY7_TYPE) */
+
+#if defined (KEY8_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 8
+#if KEY8_TYPE == STRING
+#define KEY8TYPE char*
+#define KEY8NAME str
+#define KEY8N s
+#define KEY8STOR char key8[MAP_STRING_LENGTH]
+#define KEY8CPY(m) str_copy(m->key8, key8)
+#else
+#define KEY8TYPE int64_t
+#define KEY8NAME int64
+#define KEY8N i
+#define KEY8STOR int64_t key8
+#define KEY8CPY(m) m->key8=key8
+#endif
+#define KEY8_EQ_P JOIN(KEY8NAME,eq_p)
+#define KEY8_HASH JOIN(KEY8NAME,hash)
+#endif /* defined(KEY8_TYPE) */
+
+#if defined (KEY9_TYPE)
+#undef KEY_ARITY
+#define KEY_ARITY 9
+#if KEY9_TYPE == STRING
+#define KEY9TYPE char*
+#define KEY9NAME str
+#define KEY9N s
+#define KEY9STOR char key9[MAP_STRING_LENGTH]
+#define KEY9CPY(m) str_copy(m->key9, key9)
+#else
+#define KEY9TYPE int64_t
+#define KEY9NAME int64
+#define KEY9N i
+#define KEY9STOR int64_t key9
+#define KEY9CPY(m) m->key9=key9
+#endif
+#define KEY9_EQ_P JOIN(KEY9NAME,eq_p)
+#define KEY9_HASH JOIN(KEY9NAME,hash)
+#endif /* defined(KEY9_TYPE) */
+
+/* Not so many, cowboy! */
+#if defined (KEY10_TYPE)
+#error "excessive key arity == too many array indexes"
+#endif
+
+
+
#if KEY_ARITY == 1
#define KEYSYM(x) JOIN2(x,KEY1N,VALN)
#define ALLKEYS(x) x##1
@@ -187,6 +302,26 @@
#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5
#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5
#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);}
+#elif KEY_ARITY == 6
+#define KEYSYM(x) JOIN7(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);}
+#elif KEY_ARITY == 7
+#define KEYSYM(x) JOIN8(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,KEY7N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6, x##7
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6, KEY7TYPE x##7
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);KEY7CPY(m);}
+#elif KEY_ARITY == 8
+#define KEYSYM(x) JOIN9(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,KEY7N,KEY8N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6, KEY7TYPE x##7, KEY8TYPE x##8
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);KEY7CPY(m);KEY8CPY(m);}
+#elif KEY_ARITY == 9
+#define KEYSYM(x) JOIN10(x,KEY1N,KEY2N,KEY3N,KEY4N,KEY5N,KEY6N,KEY7N,KEY8N,KEY9N,VALN)
+#define ALLKEYS(x) x##1, x##2, x##3, x##4, x##5, x##6, x##7, x##8, x##9
+#define ALLKEYSD(x) KEY1TYPE x##1, KEY2TYPE x##2, KEY3TYPE x##3, KEY4TYPE x##4, KEY5TYPE x##5, KEY6TYPE x##6, KEY7TYPE x##7, KEY8TYPE x##8, KEY9TYPE x##9
+#define KEYCPY(m) {KEY1CPY(m);KEY2CPY(m);KEY3CPY(m);KEY4CPY(m);KEY5CPY(m);KEY6CPY(m);KEY7CPY(m);KEY8CPY(m);KEY9CPY(m);}
#endif
/* */
@@ -208,6 +343,18 @@ struct KEYSYM(pmap_node) {
KEY4STOR;
#if KEY_ARITY > 4
KEY5STOR;
+#if KEY_ARITY > 5
+ KEY6STOR;
+#if KEY_ARITY > 6
+ KEY7STOR;
+#if KEY_ARITY > 7
+ KEY8STOR;
+#if KEY_ARITY > 8
+ KEY9STOR;
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -238,6 +385,18 @@ static int KEYSYM(pmap_key_cmp) (struct map_node *m1, struct map_node *m2)
&& KEY4_EQ_P(n1->key4, n2->key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n1->key5, n2->key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n1->key6, n2->key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n1->key7, n2->key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n1->key8, n2->key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n1->key9, n2->key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -282,6 +441,34 @@ static void KEYSYM(pmap_copy_keys) (struct map_node *m1, struct map_node *m2)
#else
dst->key5 = src->key5;
#endif
+#if KEY_ARITY > 5
+#if KEY6_TYPE == STRING
+ str_copy (dst->key6, src->key6);
+#else
+ dst->key6 = src->key6;
+#endif
+#if KEY_ARITY > 6
+#if KEY7_TYPE == STRING
+ str_copy (dst->key7, src->key7);
+#else
+ dst->key7 = src->key7;
+#endif
+#if KEY_ARITY > 7
+#if KEY8_TYPE == STRING
+ str_copy (dst->key8, src->key8);
+#else
+ dst->key8 = src->key8;
+#endif
+#if KEY_ARITY > 8
+#if KEY9_TYPE == STRING
+ str_copy (dst->key9, src->key9);
+#else
+ dst->key9 = src->key9;
+#endif
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -330,6 +517,34 @@ static key_data KEYSYM(pmap_get_key) (struct map_node *mn, int n, int *type)
if (type)
*type = type_to_enum(KEY5TYPE);
break;
+#if KEY_ARITY > 5
+ case 6:
+ ptr = (key_data)m->key6;
+ if (type)
+ *type = type_to_enum(KEY6TYPE);
+ break;
+#if KEY_ARITY > 6
+ case 7:
+ ptr = (key_data)m->key7;
+ if (type)
+ *type = type_to_enum(KEY7TYPE);
+ break;
+#if KEY_ARITY > 7
+ case 8:
+ ptr = (key_data)m->key8;
+ if (type)
+ *type = type_to_enum(KEY8TYPE);
+ break;
+#if KEY_ARITY > 8
+ case 9:
+ ptr = (key_data)m->key9;
+ if (type)
+ *type = type_to_enum(KEY9TYPE);
+ break;
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -373,6 +588,34 @@ static unsigned int KEYSYM(pkeycheck) (ALLKEYSD(key))
if (key5 == NULL)
return 0;
#endif
+
+#if KEY_ARITY > 5
+#if KEY6_TYPE == STRING
+ if (key6 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 6
+#if KEY7_TYPE == STRING
+ if (key7 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 7
+#if KEY8_TYPE == STRING
+ if (key8 == NULL)
+ return 0;
+#endif
+
+#if KEY_ARITY > 8
+#if KEY9_TYPE == STRING
+ if (key9 == NULL)
+ return 0;
+#endif
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -391,6 +634,18 @@ static unsigned int KEYSYM(phash) (ALLKEYSD(key))
hash ^= KEY4_HASH(key4);
#if KEY_ARITY > 4
hash ^= KEY5_HASH(key5);
+#if KEY_ARITY > 5
+ hash ^= KEY6_HASH(key6);
+#if KEY_ARITY > 6
+ hash ^= KEY7_HASH(key7);
+#if KEY_ARITY > 7
+ hash ^= KEY8_HASH(key8);
+#if KEY_ARITY > 8
+ hash ^= KEY9_HASH(key9);
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -504,6 +759,18 @@ static int KEYSYM(__stp_pmap_set) (MAP map, ALLKEYSD(key), VSTYPE val, int add)
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -587,6 +854,18 @@ static VALTYPE KEYSYM(_stp_pmap_get_cpu) (PMAP pmap, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -637,6 +916,18 @@ static VALTYPE KEYSYM(_stp_pmap_get) (PMAP pmap, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -669,6 +960,18 @@ static VALTYPE KEYSYM(_stp_pmap_get) (PMAP pmap, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -723,6 +1026,18 @@ static int KEYSYM(__stp_pmap_del) (MAP map, ALLKEYSD(key))
&& KEY4_EQ_P(n->key4, key4)
#if KEY_ARITY > 4
&& KEY5_EQ_P(n->key5, key5)
+#if KEY_ARITY > 5
+ && KEY6_EQ_P(n->key6, key6)
+#if KEY_ARITY > 6
+ && KEY7_EQ_P(n->key7, key7)
+#if KEY_ARITY > 7
+ && KEY8_EQ_P(n->key8, key8)
+#if KEY_ARITY > 8
+ && KEY9_EQ_P(n->key9, key9)
+#endif
+#endif
+#endif
+#endif
#endif
#endif
#endif
@@ -788,6 +1103,34 @@ static int KEYSYM(_stp_pmap_del) (PMAP pmap, ALLKEYSD(key))
#undef KEY5STOR
#undef KEY5CPY
+#undef KEY6NAME
+#undef KEY6N
+#undef KEY6TYPE
+#undef KEY6_TYPE
+#undef KEY6STOR
+#undef KEY6CPY
+
+#undef KEY7NAME
+#undef KEY7N
+#undef KEY7TYPE
+#undef KEY7_TYPE
+#undef KEY7STOR
+#undef KEY7CPY
+
+#undef KEY8NAME
+#undef KEY8N
+#undef KEY8TYPE
+#undef KEY8_TYPE
+#undef KEY8STOR
+#undef KEY8CPY
+
+#undef KEY9NAME
+#undef KEY9N
+#undef KEY9TYPE
+#undef KEY9_TYPE
+#undef KEY9STOR
+#undef KEY9CPY
+
#undef KEY_ARITY
#undef ALLKEYS
#undef ALLKEYSD
diff --git a/runtime/print.c b/runtime/print.c
index c1fff306..d51c8108 100644
--- a/runtime/print.c
+++ b/runtime/print.c
@@ -16,6 +16,7 @@
#include "vsprintf.c"
#include "print.h"
#include "transport/transport.c"
+#include "vsprintf.c"
/** @file print.c
* Printing Functions.
@@ -168,34 +169,10 @@ static void _stp_print_binary (int num, ...)
*/
static void _stp_printf (const char *fmt, ...)
{
- int num;
va_list args;
- _stp_pbuf *pb = per_cpu_ptr(Stp_pbuf, smp_processor_id());
- char *buf = pb->buf + pb->len;
- int size = STP_BUFFER_SIZE - pb->len;
-
va_start(args, fmt);
- num = _stp_vsnprintf(buf, size, fmt, args);
+ _stp_vsnprintf(NULL, 0, fmt, args);
va_end(args);
- if (unlikely(num >= size)) {
- /* overflowed the buffer */
- if (pb->len == 0) {
- /* A single print request exceeded the buffer size. */
- /* Should not be possible with Systemtap-generated code. */
- pb->len = STP_BUFFER_SIZE;
- _stp_print_flush();
- num = 0;
- } else {
- /* Need more space. Flush the previous contents */
- _stp_print_flush();
-
- /* try again */
- va_start(args, fmt);
- num = _stp_vsnprintf(pb->buf, STP_BUFFER_SIZE, fmt, args);
- va_end(args);
- }
- }
- pb->len += num;
}
/** Write a string into the print buffer.
diff --git a/runtime/ptrace_compatibility.h b/runtime/ptrace_compatibility.h
new file mode 100644
index 00000000..939c3b56
--- /dev/null
+++ b/runtime/ptrace_compatibility.h
@@ -0,0 +1,50 @@
+#ifndef _PTRACE_COMPATIBILITY_H_
+#define _PTRACE_COMPATIBILITY_H_
+
+#include <linux/ptrace.h>
+
+/* Older kernel's linux/ptrace.h don't define
+ * arch_has_single_step()/arch_has_block_step(). */
+
+#ifndef arch_has_single_step
+
+#include <linux/tracehook.h>
+
+/**
+ * arch_has_single_step - does this CPU support user-mode single-step?
+ *
+ * If this is defined, then there must be function declarations or
+ * inlines for user_enable_single_step() and user_disable_single_step().
+ * arch_has_single_step() should evaluate to nonzero iff the machine
+ * supports instruction single-step for user mode.
+ * It can be a constant or it can test a CPU feature bit.
+ */
+
+#ifdef ARCH_HAS_SINGLE_STEP
+#define arch_has_single_step() (ARCH_HAS_SINGLE_STEP)
+#else
+#define arch_has_single_step() (0)
+#endif /* ARCH_HAS_SINGLE_STEP */
+
+#endif /* arch_has_single_step */
+
+#ifndef arch_has_block_step
+/**
+ * arch_has_block_step - does this CPU support user-mode block-step?
+ *
+ * If this is defined, then there must be a function declaration or inline
+ * for user_enable_block_step(), and arch_has_single_step() must be defined
+ * too. arch_has_block_step() should evaluate to nonzero iff the machine
+ * supports step-until-branch for user mode. It can be a constant or it
+ * can test a CPU feature bit.
+ */
+
+#ifdef ARCH_HAS_BLOCK_STEP
+#define arch_has_block_step() (ARCH_HAS_BLOCK_STEP)
+#else
+#define arch_has_block_step() (0)
+#endif /* ARCH_HAS_BLOCK_STEP */
+
+#endif /* arch_has_block_step */
+
+#endif /* _PTRACE_COMPATIBILITY_H_ */
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 78c27a84..7418d13b 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -74,6 +74,13 @@ static struct
#define MAXTRACE 20
#endif
+/* dwarf unwinder only tested so far on i386 and x86_64. */
+#if (defined(__i386__) || defined(__x86_64__))
+#ifndef STP_USE_DWARF_UNWINDER
+#define STP_USE_DWARF_UNWINDER
+#endif
+#endif
+
#ifdef CONFIG_FRAME_POINTER
/* Just because frame pointers are available does not mean we can trust them. */
#ifndef STP_USE_DWARF_UNWINDER
@@ -81,19 +88,17 @@ static struct
#endif
#endif
-/* dwarf unwinder only tested so far on i386 and x86_64,
- but globally disabled for now */
-#if 0
-// !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 "regs.c"
+#include "regs-ia64.c"
+
+#include "task_finder.c"
+
#include "sym.c"
#ifdef STP_PERFMON
#include "perf.c"
diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c
index 9b0b772d..fcff0a3b 100644
--- a/runtime/stack-arm.c
+++ b/runtime/stack-arm.c
@@ -31,7 +31,8 @@ static int __init find_str_pc_offset(void)
}
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
#ifdef STP_USE_FRAME_POINTER
int pc_offset = find_str_pc_offset();
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c
index 5a18c9d8..69623765 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -23,14 +23,15 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
/* cannot access stack. give up. */
return;
}
- if (_stp_func_print(addr, verbose, 0))
+ if (_stp_func_print(addr, verbose, 0, NULL))
levels--;
stack++;
}
}
#endif
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long context = (unsigned long)&REG_SP(regs) & ~(THREAD_SIZE - 1);
@@ -43,7 +44,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
/* cannot access stack. give up. */
return;
}
- _stp_func_print(addr, verbose, 1);
+ _stp_func_print(addr, verbose, 1, NULL);
if (unlikely(_stp_read_address(next_fp, (unsigned long *)fp, KERNEL_DS))) {
/* cannot access stack. give up. */
return;
@@ -60,19 +61,23 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
- while (levels && !arch_unw_user_mode(&info)) {
- int ret = unwind(&info);
+ while (levels && (tsk || !arch_unw_user_mode(&info))) {
+ int ret = unwind(&info, tsk);
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);
+ _stp_func_print(UNW_PC(&info), verbose, 1, tsk);
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))
+ /* If an error happened or we hit a kretprobe trampoline,
+ * use fallback backtrace, unless user task backtrace.
+ * FIXME: is there a way to unwind across kretprobe
+ * trampolines? */
+ if ((ret < 0
+ || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ && ! (tsk || arch_unw_user_mode(&info)))
_stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
- break;
+ return;
}
#else /* ! STP_USE_DWARF_UNWINDER */
_stp_stack_print_fallback((unsigned long)&REG_SP(regs), verbose, levels);
diff --git a/runtime/stack-ia64.c b/runtime/stack-ia64.c
index ca9d25a6..a04355fa 100644
--- a/runtime/stack-ia64.c
+++ b/runtime/stack-ia64.c
@@ -48,7 +48,8 @@ static void __stp_show_stack_addr(struct unw_frame_info *info, void *arg)
} while (unw_unwind(info) >= 0);
}
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long *stack = (unsigned long *)&REG_SP(regs);
struct dump_para para;
diff --git a/runtime/stack-ppc64.c b/runtime/stack-ppc64.c
index 3dc38526..3267194e 100644
--- a/runtime/stack-ppc64.c
+++ b/runtime/stack-ppc64.c
@@ -7,7 +7,8 @@
* later version.
*/
-static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long ip, newsp, lr = 0;
int count = 0;
diff --git a/runtime/stack-s390.c b/runtime/stack-s390.c
index c9654102..14e9b7d8 100644
--- a/runtime/stack-s390.c
+++ b/runtime/stack-s390.c
@@ -66,7 +66,8 @@ __stp_show_stack (unsigned long sp, unsigned long low,
}
static void __stp_stack_print (struct pt_regs *regs,
- int verbose, int levels)
+ int verbose, int levels,
+ struct task_struct *tsk)
{
unsigned long *_sp = (unsigned long *)&REG_SP(regs);
unsigned long sp = (unsigned long)_sp;
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c
index 03d88ef0..9afdf38a 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -19,7 +19,7 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
/* cannot access stack. give up. */
return;
}
- if (_stp_func_print(addr, verbose, 0))
+ if (_stp_func_print(addr, verbose, 0, NULL))
levels--;
stack++;
}
@@ -27,26 +27,31 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
#endif
-static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels)
+static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels,
+ struct task_struct *tsk)
{
#ifdef STP_USE_DWARF_UNWINDER
// FIXME: large stack allocation
struct unwind_frame_info info;
arch_unw_init_frame_info(&info, regs);
- while (levels && !arch_unw_user_mode(&info)) {
- int ret = unwind(&info);
+ while (levels && (tsk || !arch_unw_user_mode(&info))) {
+ int ret = unwind(&info, tsk);
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);
+ _stp_func_print(UNW_PC(&info), verbose, 1, tsk);
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))
+ /* If an error happened or we hit a kretprobe trampoline,
+ * use fallback backtrace, unless user task backtrace.
+ * FIXME: is there a way to unwind across kretprobe
+ * trampolines? */
+ if ((ret < 0
+ || (ret > 0 && UNW_PC(&info) == _stp_kretprobe_trampoline))
+ && ! (tsk || arch_unw_user_mode(&info)))
_stp_stack_print_fallback(UNW_SP(&info), verbose, levels);
- break;
+ return;
}
#else /* ! STP_USE_DWARF_UNWINDER */
_stp_stack_print_fallback(REG_SP(regs), verbose, levels);
diff --git a/runtime/stack.c b/runtime/stack.c
index f6b1cd08..042f44c7 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
* Stack tracing functions
- * Copyright (C) 2005-2008 Red Hat Inc.
+ * Copyright (C) 2005-2009 Red Hat Inc.
* Copyright (C) 2005 Intel Corporation.
*
* This file is part of systemtap, and is free software. You can
@@ -77,7 +77,7 @@ static void print_stack_address(void *data, unsigned long addr, int reliable)
{
struct print_stack_data *sdata = data;
if (sdata->level++ < sdata->max_level)
- _stp_func_print(addr,sdata->verbose, 0);
+ _stp_func_print(addr, sdata->verbose, 0, NULL);
}
static const struct stacktrace_ops print_stack_ops = {
@@ -97,11 +97,17 @@ static void _stp_stack_print_fallback(unsigned long stack, int verbose, int leve
&print_data);
}
#endif
+
+// Without KPROBES very little works atm.
+// But this file is unconditionally imported, while these two functions are only
+// used through context-unwind.stp.
+#if defined (CONFIG_KPROBES)
+
/** Prints the stack backtrace
* @param regs A pointer to the struct pt_regs.
*/
-static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
+static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
{
if (verbose) {
/* print the current address */
@@ -112,7 +118,10 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
} else {
_stp_print_char(' ');
- _stp_symbol_print(REG_IP(regs));
+ if (tsk)
+ _stp_usymbol_print(REG_IP(regs), tsk);
+ else
+ _stp_symbol_print(REG_IP(regs));
}
_stp_print_char('\n');
} else if (pi)
@@ -120,7 +129,7 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
else
_stp_printf("%p ", (int64_t) REG_IP(regs));
- __stp_stack_print(regs, verbose, levels);
+ __stp_stack_print(regs, verbose, levels, tsk);
}
/** Writes stack backtrace to a string
@@ -129,34 +138,19 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
* @param regs A pointer to the struct pt_regs.
* @returns void
*/
-static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels)
+static void _stp_stack_snprint(char *str, int size, struct pt_regs *regs, int verbose, struct kretprobe_instance *pi, int levels, struct task_struct *tsk)
{
/* 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, levels);
+ _stp_stack_print(regs, verbose, pi, levels, tsk);
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
-static 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));
- if (REG_SP(nregs))
- _stp_printf("%p : [user]\n", (int64_t) (*(unsigned long *)REG_SP(nregs)));
-}
-#endif /* 0 */
-
-/** @} */
+#endif /* CONFIG_KPROBES */
void _stp_stack_print_tsk(struct task_struct *tsk, int verbose, int levels)
{
diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c
index fd16b4b8..c67ce340 100644
--- a/runtime/staprun/common.c
+++ b/runtime/staprun/common.c
@@ -27,6 +27,9 @@ int attach_mod;
int delete_mod;
int load_only;
int need_uprobes;
+int daemon_mode;
+off_t fsize_max;
+int fnum_max;
/* module variables */
char *modname = NULL;
@@ -35,9 +38,38 @@ char *modoptions[MAXMODOPTIONS];
int control_channel = -1; /* NB: fd==0 possible */
+static char path_buf[PATH_MAX];
+static char *get_abspath(char *path)
+{
+ int len;
+ if (path[0] == '/')
+ return path;
+
+ len = strlen(getcwd(path_buf, PATH_MAX));
+ if (len + 2 + strlen(path) >= PATH_MAX)
+ return NULL;
+ path_buf[len] = '/';
+ strcpy(&path_buf[len + 1], path);
+ return path_buf;
+}
+
+int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t)
+{
+ struct tm tm;
+ size_t ret;
+ if (buf == NULL || fmt == NULL || max <= 1)
+ return -EINVAL;
+ localtime_r(&t, &tm);
+ ret = strftime(buf, max, fmt, &tm);
+ if (ret == 0)
+ return -EINVAL;
+ return (int)ret;
+}
+
void parse_args(int argc, char **argv)
{
int c;
+ char *s;
/* Initialize option variables. */
verbose = 0;
@@ -49,8 +81,11 @@ void parse_args(int argc, char **argv)
delete_mod = 0;
load_only = 0;
need_uprobes = 0;
+ daemon_mode = 0;
+ fsize_max = 0;
+ fnum_max = 0;
- while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:")) != EOF) {
+ while ((c = getopt(argc, argv, "ALuvb:t:dc:o:x:S:D")) != EOF) {
switch (c) {
case 'u':
need_uprobes = 1;
@@ -85,11 +120,38 @@ void parse_args(int argc, char **argv)
case 'L':
load_only = 1;
break;
+ case 'D':
+ daemon_mode = 1;
+ break;
+ case 'S':
+ fsize_max = strtoul(optarg, &s, 10);
+ fsize_max <<= 20;
+ if (s[0] == ',')
+ fnum_max = (int)strtoul(&s[1], &s, 10);
+ if (s[0] != '\0') {
+ err("Invalid file size option '%s'.\n", optarg);
+ usage(argv[0]);
+ }
+ break;
default:
usage(argv[0]);
}
}
-
+ if (outfile_name) {
+ char tmp[PATH_MAX];
+ int ret;
+ outfile_name = get_abspath(outfile_name);
+ if (outfile_name == NULL) {
+ err("File name is too long.\n");
+ usage(argv[0]);
+ }
+ ret = stap_strfloctime(tmp, PATH_MAX - 18, /* = _cpuNNN.SSSSSSSSSS */
+ outfile_name, time(NULL));
+ if (ret < 0) {
+ err("Filename format is invalid or too long.\n");
+ usage(argv[0]);
+ }
+ }
if (attach_mod && load_only) {
err("You can't specify the '-A' and '-L' options together.\n");
usage(argv[0]);
@@ -118,18 +180,40 @@ void parse_args(int argc, char **argv)
err("You can't specify the '-c' and '-x' options together.\n");
usage(argv[0]);
}
+
+ if (daemon_mode && load_only) {
+ err("You can't specify the '-D' and '-L' options together.\n");
+ usage(argv[0]);
+ }
+ if (daemon_mode && delete_mod) {
+ err("You can't specify the '-D' and '-d' options together.\n");
+ usage(argv[0]);
+ }
+ if (daemon_mode && target_cmd) {
+ err("You can't specify the '-D' and '-c' options together.\n");
+ usage(argv[0]);
+ }
+ if (daemon_mode && outfile_name == NULL) {
+ err("You have to specify output FILE with '-D' option.\n");
+ usage(argv[0]);
+ }
+ if (outfile_name == NULL && fsize_max != 0) {
+ err("You have to specify output FILE with '-S' option.\n");
+ usage(argv[0]);
+ }
}
void usage(char *prog)
{
- err("\n%s [-v] [-c cmd ] [-x pid] [-u user]\n"
- "\t[-A|-L] [-b bufsize] [-o FILE] MODULE [module-options]\n", prog);
+ err("\n%s [-v] [-c cmd ] [-x pid] [-u user] [-A|-L|-d]\n"
+ "\t[-b bufsize] [-o FILE [-D] [-S size[,N]]] MODULE [module-options]\n", prog);
err("-v Increase verbosity.\n");
err("-c cmd Command \'cmd\' will be run and staprun will\n");
err(" exit when it does. The '_stp_target' variable\n");
err(" will contain the pid for the command.\n");
err("-x pid Sets the '_stp_target' variable to pid.\n");
- err("-o FILE Send output to FILE.\n");
+ err("-o FILE Send output to FILE. This supports strftime(3)\n");
+ err(" formats for 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 4095 \n");
@@ -140,6 +224,14 @@ void usage(char *prog)
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("-D Run in background. This requires '-o' option.\n");
+ err("-S size[,N] Switches output file to next file when the size\n");
+ err(" of file reaches the specified size. The value\n");
+ err(" should be an integer greater than 1 which is\n");
+ err(" assumed to be the maximum file size in MB.\n");
+ err(" When the number of output files reaches N, it\n");
+ err(" switches to the first output file. You can omit\n");
+ err(" the second argument.\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");
@@ -344,3 +436,24 @@ int send_request(int type, void *data, int len)
if (rc < 0) return rc;
return (rc != len+4);
}
+
+#include <stdarg.h>
+
+static int use_syslog = 0;
+
+void eprintf(const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ if (use_syslog)
+ vsyslog(LOG_ERR, fmt, va);
+ else
+ vfprintf(stderr, fmt, va);
+ va_end(va);
+}
+
+void switch_syslog(const char *name)
+{
+ openlog(name, LOG_PID, LOG_DAEMON);
+ use_syslog = 1;
+}
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index 0745f611..7125a7bb 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -7,7 +7,7 @@
* Public License (GPL); either version 2, or (at your option) any
* later version.
*
- * Copyright (C) 2005-2008 Red Hat Inc.
+ * Copyright (C) 2005-2009 Red Hat Inc.
*/
#include "staprun.h"
@@ -318,6 +318,41 @@ int init_stapio(void)
if (target_cmd)
start_cmd();
+ /* Run in background */
+ if (daemon_mode) {
+ pid_t pid;
+ int ret;
+ dbug(2, "daemonizing stapio\n");
+
+ /* daemonize */
+ ret = daemon(0, 1); /* don't close stdout at this time. */
+ if (ret) {
+ err("Failed to daemonize stapio\n");
+ return -1;
+ }
+
+ /* change error messages to syslog. */
+ switch_syslog("stapio");
+
+ /* show new pid */
+ pid = getpid();
+ fprintf(stdout, "%d\n", pid);
+ fflush(stdout);
+
+ /* redirect all outputs to /dev/null */
+ ret = open("/dev/null", O_RDWR);
+ if (ret < 0) {
+ err("Failed to open /dev/null\n");
+ return -1;
+ }
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ dup2(ret, STDOUT_FILENO);
+ dup2(ret, STDERR_FILENO);
+ close(ret);
+ }
+
return 0;
}
@@ -360,10 +395,10 @@ void cleanup_and_exit(int detach)
#define BUG9788_WORKAROUND
#ifndef BUG9788_WORKAROUND
dbug(2, "removing %s\n", modname);
- if (execlp(staprun, basename (staprun), "-d", modname, NULL) < 0) {
+ if (execlp(staprun, basename (staprun), "-d", modpath, NULL) < 0) {
if (errno == ENOEXEC) {
char *cmd;
- if (asprintf(&cmd, "%s -d '%s'", staprun, modname) > 0)
+ if (asprintf(&cmd, "%s -d '%s'", staprun, modpath) > 0)
execl("/bin/sh", "sh", "-c", cmd, NULL);
free(cmd);
}
@@ -392,10 +427,10 @@ void cleanup_and_exit(int detach)
if (pid == 0) { /* child process */
/* Run the command. */
- if (execlp(staprun, basename (staprun), "-d", modname, NULL) < 0) {
+ if (execlp(staprun, basename (staprun), "-d", modpath, NULL) < 0) {
if (errno == ENOEXEC) {
char *cmd;
- if (asprintf(&cmd, "%s -d '%s'", staprun, modname) > 0)
+ if (asprintf(&cmd, "%s -d '%s'", staprun, modpath) > 0)
execl("/bin/sh", "sh", "-c", cmd, NULL);
free(cmd);
}
@@ -454,21 +489,14 @@ int stp_main_loop(void)
switch (type) {
#if STP_TRANSPORT_VERSION == 1
case STP_REALTIME_DATA:
- {
- 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 (write_realtime_data(data, nb)) {
+ _perr("write error (nb=%ld)", (long)nb);
+ cleanup_and_exit(0);
}
+ break;
#endif
case STP_OOB_DATA:
- fputs((char *)data, stderr);
+ eprintf("%s", (char *)data);
break;
case STP_EXIT:
{
@@ -477,6 +505,14 @@ int stp_main_loop(void)
cleanup_and_exit(0);
break;
}
+ case STP_REQUEST_EXIT:
+ {
+ /* module asks us to start exiting, so send STP_EXIT */
+ dbug(2, "got STP_REQUEST_EXIT\n");
+ int32_t rc, btype = STP_EXIT;
+ rc = write(control_channel, &btype, sizeof(btype));
+ break;
+ }
case STP_START:
{
struct _stp_msg_start *t = (struct _stp_msg_start *)data;
diff --git a/runtime/staprun/modverify.c b/runtime/staprun/modverify.c
new file mode 100644
index 00000000..b50a69f4
--- /dev/null
+++ b/runtime/staprun/modverify.c
@@ -0,0 +1,391 @@
+/*
+ This program verifies the given file using the given signature, the named
+ certificate and public key in the given certificate database.
+
+ Copyright (C) 2009 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 as published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+
+#include <nspr.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <cryptohi.h>
+#include <cert.h>
+#include <certt.h>
+
+#include "nsscommon.h"
+#include "modverify.h"
+
+#include <sys/stat.h>
+
+/* Function: int check_cert_db_permissions (const char *cert_db_path);
+ *
+ * Check that the given certificate directory and its contents have
+ * the correct permissions.
+ *
+ * Returns 0 if there is an error, 1 otherwise.
+ */
+static int
+check_db_file_permissions (const char *cert_db_file) {
+ struct stat info;
+ int rc;
+
+ rc = stat (cert_db_file, & info);
+ if (rc)
+ {
+ fprintf (stderr, "Could not obtain information on certificate database file %s.\n",
+ cert_db_file);
+ perror ("");
+ return 0;
+ }
+
+ rc = 1; /* ok */
+
+ /* The owner of the file must be root. */
+ if (info.st_uid != 0)
+ {
+ fprintf (stderr, "Certificate database file %s must be owned by root.\n",
+ cert_db_file);
+ rc = 0;
+ }
+
+ /* Check the access permissions of the file. */
+ if ((info.st_mode & S_IRUSR) == 0)
+ fprintf (stderr, "Certificate database file %s should be readable by the owner.\n", cert_db_file);
+ if ((info.st_mode & S_IWUSR) == 0)
+ fprintf (stderr, "Certificate database file %s should be writeable by the owner.\n", cert_db_file);
+ if ((info.st_mode & S_IXUSR) != 0)
+ {
+ fprintf (stderr, "Certificate database file %s must not be executable by the owner.\n", cert_db_file);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IRGRP) == 0)
+ {
+ fprintf (stderr, "Certificate database file %s should be readable by the group.\n", cert_db_file);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IWGRP) != 0)
+ {
+ fprintf (stderr, "Certificate database file %s must not be writable by the group.\n", cert_db_file);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXGRP) != 0)
+ {
+ fprintf (stderr, "Certificate database file %s must not be executable by the group.\n", cert_db_file);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IROTH) == 0)
+ {
+ fprintf (stderr, "Certificate database file %s should be readable by others.\n", cert_db_file);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IWOTH) != 0)
+ {
+ fprintf (stderr, "Certificate database file %s must not be writable by others.\n", cert_db_file);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXOTH) != 0)
+ {
+ fprintf (stderr, "Certificate database file %s must not be executable by others.\n", cert_db_file);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/* Function: int check_cert_db_permissions (const char *cert_db_path);
+ *
+ * Check that the given certificate directory and its contents have
+ * the correct permissions.
+ *
+ * Returns 0 if there is an error, 1 otherwise.
+ */
+static int
+check_cert_db_permissions (const char *cert_db_path) {
+ struct stat info;
+ char *fileName;
+ int rc;
+
+ rc = stat (cert_db_path, & info);
+ if (rc)
+ {
+ fprintf (stderr, "Could not obtain information on certificate database directory %s.\n",
+ cert_db_path);
+ perror ("");
+ return 0;
+ }
+
+ rc = 1; /* ok */
+
+ /* The owner of the database must be root. */
+ if (info.st_uid != 0)
+ {
+ fprintf (stderr, "Certificate database directory %s must be owned by root.\n", cert_db_path);
+ rc = 0;
+ }
+
+ /* Check the database directory access permissions */
+ if ((info.st_mode & S_IRUSR) == 0)
+ fprintf (stderr, "Certificate database %s should be readable by the owner.\n", cert_db_path);
+ if ((info.st_mode & S_IWUSR) == 0)
+ fprintf (stderr, "Certificate database %s should be writeable by the owner.\n", cert_db_path);
+ if ((info.st_mode & S_IXUSR) == 0)
+ fprintf (stderr, "Certificate database %s should be searchable by the owner.\n", cert_db_path);
+ if ((info.st_mode & S_IRGRP) == 0)
+ fprintf (stderr, "Certificate database %s should be readable by the group.\n", cert_db_path);
+ if ((info.st_mode & S_IWGRP) != 0)
+ {
+ fprintf (stderr, "Certificate database %s must not be writable by the group.\n", cert_db_path);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXGRP) == 0)
+ fprintf (stderr, "Certificate database %s should be searchable by the group.\n", cert_db_path);
+ if ((info.st_mode & S_IROTH) == 0)
+ fprintf (stderr, "Certificate database %s should be readable by others.\n", cert_db_path);
+ if ((info.st_mode & S_IWOTH) != 0)
+ {
+ fprintf (stderr, "Certificate database %s must not be writable by others.\n", cert_db_path);
+ rc = 0;
+ }
+ if ((info.st_mode & S_IXOTH) == 0)
+ fprintf (stderr, "Certificate database %s should be searchable by others.\n", cert_db_path);
+
+ /* Now check the permissions of the critical files. */
+ fileName = PORT_Alloc (strlen (cert_db_path) + 11);
+ if (! fileName)
+ {
+ fprintf (stderr, "Unable to allocate memory for certificate database file names\n");
+ return 0;
+ }
+
+ sprintf (fileName, "%s/cert8.db", cert_db_path);
+ rc &= check_db_file_permissions (fileName);
+ sprintf (fileName, "%s/key3.db", cert_db_path);
+ rc &= check_db_file_permissions (fileName);
+ sprintf (fileName, "%s/secmod.db", cert_db_path);
+ rc &= check_db_file_permissions (fileName);
+
+ PORT_Free (fileName);
+
+ if (rc == 0)
+ fprintf (stderr, "Unable to use certificate database %s due to errors.\n", cert_db_path);
+
+ return rc;
+}
+
+static int
+verify_it (const char *inputName, const char *signatureName, SECKEYPublicKey *pubKey)
+{
+ unsigned char buffer[4096];
+ PRFileInfo info;
+ PRStatus prStatus;
+ PRInt32 numBytes;
+ PRFileDesc *local_file_fd;
+ VFYContext *vfy;
+ SECItem signature;
+ SECStatus secStatus;
+
+ /* Get the size of the signature file. */
+ prStatus = PR_GetFileInfo (signatureName, &info);
+ if (prStatus != PR_SUCCESS || info.type != PR_FILE_FILE || info.size < 0)
+ {
+ fprintf (stderr, "Unable to obtain information on the signature file %s.\n", signatureName);
+ nssError ();
+ return MODULE_UNTRUSTED; /* Not signed */
+ }
+
+ /* Open the signature file. */
+ local_file_fd = PR_Open (signatureName, PR_RDONLY, 0);
+ if (local_file_fd == NULL)
+ {
+ fprintf (stderr, "Could not open the signature file %s\n.", signatureName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ /* Allocate space to read the signature file. */
+ signature.data = PORT_Alloc (info.size);
+ if (! signature.data)
+ {
+ fprintf (stderr, "Unable to allocate memory for the signature in %s.\n", signatureName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ /* Read the signature. */
+ numBytes = PR_Read (local_file_fd, signature.data, info.size);
+ if (numBytes == 0) /* EOF */
+ {
+ fprintf (stderr, "EOF reading signature file %s.\n", signatureName);
+ return MODULE_CHECK_ERROR;
+ }
+ if (numBytes < 0)
+ {
+ fprintf (stderr, "Error reading signature file %s.\n", signatureName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+ if (numBytes != info.size)
+ {
+ fprintf (stderr, "Incomplete data while reading signature file %s.\n", signatureName);
+ return MODULE_CHECK_ERROR;
+ }
+ signature.len = info.size;
+
+ /* Done with the signature file. */
+ PR_Close (local_file_fd);
+
+ /* Create a verification context. */
+ vfy = VFY_CreateContextDirect (pubKey, & signature, SEC_OID_PKCS1_RSA_ENCRYPTION,
+ SEC_OID_UNKNOWN, NULL, NULL);
+ if (! vfy)
+ {
+ /* The key does not match the signature. This is not an error. It just means
+ we are currently trying the wrong certificate/key. i.e. the module
+ remains untrusted for now. */
+ return MODULE_UNTRUSTED;
+ }
+
+ /* Begin the verification process. */
+ secStatus = VFY_Begin(vfy);
+ if (secStatus != SECSuccess)
+ {
+ fprintf (stderr, "Unable to initialize verification context while verifying %s using the signature in %s.\n",
+ inputName, signatureName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ /* Now read the data and add it to the signature. */
+ local_file_fd = PR_Open (inputName, PR_RDONLY, 0);
+ if (local_file_fd == NULL)
+ {
+ fprintf (stderr, "Could not open module file %s.\n", inputName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ for (;;)
+ {
+ numBytes = PR_Read (local_file_fd, buffer, sizeof (buffer));
+ if (numBytes == 0)
+ break; /* EOF */
+
+ if (numBytes < 0)
+ {
+ fprintf (stderr, "Error reading module file %s.\n", inputName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ /* Add the data to the signature. */
+ secStatus = VFY_Update (vfy, buffer, numBytes);
+ if (secStatus != SECSuccess)
+ {
+ fprintf (stderr, "Error while verifying module file %s.\n", inputName);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+ }
+
+ PR_Close(local_file_fd);
+
+ /* Complete the verification. */
+ secStatus = VFY_End (vfy);
+ if (secStatus != SECSuccess) {
+ fprintf (stderr, "Unable to verify signed module %s. It may have been altered since it was created.\n", inputName);
+ nssError ();
+ return MODULE_ALTERED;
+ }
+
+ return MODULE_OK;
+}
+
+int verify_module (const char *module_name, const char *signature_name)
+{
+ const char *dbdir = SYSCONFDIR "/systemtap/staprun";
+ SECKEYPublicKey *pubKey;
+ SECStatus secStatus;
+ CERTCertList *certList;
+ CERTCertListNode *certListNode;
+ CERTCertificate *cert;
+ PRStatus prStatus;
+ PRFileInfo info;
+ int rc = 0;
+
+ /* Look for the certificate database. If it's not there, it's not an error, it
+ just means that the module can't be verified. */
+ prStatus = PR_GetFileInfo (dbdir, &info);
+ if (prStatus != PR_SUCCESS || info.type != PR_FILE_DIRECTORY)
+ return MODULE_UNTRUSTED;
+
+ /* Verify the permissions of the certificate database and its files. */
+ if (! check_cert_db_permissions (dbdir))
+ return MODULE_UNTRUSTED;
+
+ /* Call the NSPR initialization routines. */
+ PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+
+ /* Initialize NSS. */
+ secStatus = NSS_Init (dbdir);
+ if (secStatus != SECSuccess)
+ {
+ fprintf (stderr, "Unable to initialize nss library using the database in %s.\n",
+ dbdir);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ certList = PK11_ListCerts (PK11CertListAll, NULL);
+ if (certList == NULL)
+ {
+ fprintf (stderr, "Unable to find certificates in the certificate database in %s.\n",
+ dbdir);
+ nssError ();
+ return MODULE_UNTRUSTED;
+ }
+
+ /* We need to look at each certificate in the database. */
+ for (certListNode = CERT_LIST_HEAD (certList);
+ ! CERT_LIST_END (certListNode, certList);
+ certListNode = CERT_LIST_NEXT (certListNode))
+ {
+ cert = certListNode->cert;
+
+ pubKey = CERT_ExtractPublicKey (cert);
+ if (pubKey == NULL)
+ {
+ fprintf (stderr, "Unable to extract public key from the certificate with nickname %s from the certificate database in %s.\n",
+ cert->nickname, dbdir);
+ nssError ();
+ return MODULE_CHECK_ERROR;
+ }
+
+ /* Verify the file. */
+ rc = verify_it (module_name, signature_name, pubKey);
+ if (rc == MODULE_OK || rc == MODULE_ALTERED || rc == MODULE_CHECK_ERROR)
+ break; /* resolved or error */
+ }
+
+ /* Shutdown NSS and exit NSPR gracefully. */
+ nssCleanup ();
+
+ return rc;
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/runtime/staprun/modverify.h b/runtime/staprun/modverify.h
new file mode 100644
index 00000000..49b90bfe
--- /dev/null
+++ b/runtime/staprun/modverify.h
@@ -0,0 +1,9 @@
+int verify_module (const char *module_name, const char *signature_name);
+
+/* return codes for verify_module. */
+#define MODULE_OK 1
+#define MODULE_UNTRUSTED 0
+#define MODULE_CHECK_ERROR -1
+#define MODULE_ALTERED -2
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c
index 19621933..b9796241 100644
--- a/runtime/staprun/relay.c
+++ b/runtime/staprun/relay.c
@@ -17,6 +17,9 @@ static pthread_t reader[NR_CPUS];
static int relay_fd[NR_CPUS];
static int bulkmode = 0;
static volatile int stop_threads = 0;
+static time_t *time_backlog[NR_CPUS];
+static int backlog_order=0;
+#define BACKLOG_MASK ((1 << backlog_order) - 1)
/*
* ppoll exists in glibc >= 2.4
@@ -44,6 +47,90 @@ static int ppoll(struct pollfd *fds, nfds_t nfds,
}
#endif
+int init_backlog(int cpu)
+{
+ int order = 0;
+ if (!fnum_max)
+ return 0;
+ while (fnum_max >> order) order++;
+ if (fnum_max == 1<<(order-1)) order--;
+ time_backlog[cpu] = (time_t *)calloc(1<<order, sizeof(time_t));
+ if (time_backlog[cpu] == NULL) {
+ _err("Memory allocation failed\n");
+ return -1;
+ }
+ backlog_order = order;
+ return 0;
+}
+
+void write_backlog(int cpu, int fnum, time_t t)
+{
+ time_backlog[cpu][fnum & BACKLOG_MASK] = t;
+}
+
+time_t read_backlog(int cpu, int fnum)
+{
+ return time_backlog[cpu][fnum & BACKLOG_MASK];
+}
+
+int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t)
+{
+ int len;
+ len = stap_strfloctime(buf, max, outfile_name, t);
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ if (bulkmode) {
+ /* special case: for testing we sometimes want to write to /dev/null */
+ if (strcmp(outfile_name, "/dev/null") == 0) {
+ strcpy(buf, "/dev/null");
+ } else {
+ if (snprintf_chk(&buf[len], PATH_MAX - len,
+ "_cpu%d.%d", cpu, fnum))
+ return -1;
+ }
+ } else {
+ /* stream mode */
+ if (snprintf_chk(&buf[len], PATH_MAX - len, ".%d", fnum))
+ return -1;
+ }
+ return 0;
+}
+
+static int open_outfile(int fnum, int cpu, int remove_file)
+{
+ char buf[PATH_MAX];
+ time_t t;
+ if (!outfile_name) {
+ _err("-S is set without -o. Please file a bug report.\n");
+ return -1;
+ }
+
+ time(&t);
+ if (fnum_max) {
+ if (remove_file) {
+ /* remove oldest file */
+ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max,
+ cpu, read_backlog(cpu, fnum - fnum_max)) < 0)
+ return -1;
+ remove(buf); /* don't care */
+ }
+ write_backlog(cpu, fnum, t);
+ }
+
+ if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0)
+ return -1;
+ out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (out_fd[cpu] < 0) {
+ perr("Couldn't open output file %s", buf);
+ return -1;
+ }
+ if (set_clexec(out_fd[cpu]) < 0)
+ return -1;
+ return 0;
+}
+
/**
* reader_thread - per-cpu channel buffer reader
*/
@@ -57,6 +144,9 @@ static void *reader_thread(void *data)
struct timespec tim = {.tv_sec=0, .tv_nsec=200000000}, *timeout = &tim;
sigset_t sigs;
struct sigaction sa;
+ off_t wsize = 0;
+ int fnum = 0;
+ int remove_file = 0;
sigemptyset(&sigs);
sigaddset(&sigs,SIGUSR2);
@@ -95,17 +185,37 @@ static void *reader_thread(void *data)
dbug(3, "cpu=%d poll=%d errno=%d\n", cpu, rc, errno);
if (errno != EINTR) {
_perr("poll error");
- return(NULL);
+ goto error_out;
}
}
while ((rc = read(relay_fd[cpu], buf, sizeof(buf))) > 0) {
+ wsize += rc;
+ /* Switching file */
+ if (fsize_max && wsize > fsize_max) {
+ close(out_fd[cpu]);
+ fnum++;
+ if (fnum_max && fnum == fnum_max)
+ remove_file = 1;
+ if (open_outfile(fnum, cpu, remove_file) < 0) {
+ perr("Couldn't open file for cpu %d, exiting.", cpu);
+ goto error_out;
+ }
+ wsize = rc;
+ }
if (write(out_fd[cpu], buf, rc) != rc) {
- perr("Couldn't write to output %d for cpu %d, exiting.", out_fd[cpu], cpu);
- return(NULL);
+ if (errno != EPIPE)
+ perr("Couldn't write to output %d for cpu %d, exiting.", out_fd[cpu], cpu);
+ goto error_out;
}
}
} while (!stop_threads);
- dbug(3, "exiting thread %d\n", cpu);
+ dbug(3, "exiting thread for cpu %d\n", cpu);
+ return(NULL);
+
+error_out:
+ /* Signal the main thread that we need to quit */
+ kill(getpid(), SIGTERM);
+ dbug(2, "exiting thread for cpu %d after error\n", cpu);
return(NULL);
}
@@ -116,7 +226,7 @@ static void *reader_thread(void *data)
*/
int init_relayfs(void)
{
- int i;
+ int i, len;
struct statfs st;
char rqbuf[128];
char buf[PATH_MAX], relay_filebase[PATH_MAX];
@@ -163,14 +273,29 @@ int init_relayfs(void)
return -1;
}
- if (bulkmode) {
+ if (fsize_max) {
+ /* switch file mode */
+ for (i = 0; i < ncpus; i++) {
+ if (init_backlog(i) < 0)
+ return -1;
+ if (open_outfile(0, i, 0) < 0)
+ return -1;
+ }
+ } else if (bulkmode) {
for (i = 0; i < ncpus; i++) {
if (outfile_name) {
/* special case: for testing we sometimes want to write to /dev/null */
if (strcmp(outfile_name, "/dev/null") == 0) {
strcpy(buf, "/dev/null");
} else {
- if (sprintf_chk(buf, "%s_%d", outfile_name, i))
+ len = stap_strfloctime(buf, PATH_MAX,
+ outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ if (snprintf_chk(&buf[len],
+ PATH_MAX - len, "_%d", i))
return -1;
}
} else {
@@ -189,9 +314,15 @@ int init_relayfs(void)
} else {
/* stream mode */
if (outfile_name) {
- out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ len = stap_strfloctime(buf, PATH_MAX,
+ outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ out_fd[0] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (out_fd[0] < 0) {
- perr("Couldn't open output file %s", outfile_name);
+ perr("Couldn't open output file %s", buf);
return -1;
}
if (set_clexec(out_fd[i]) < 0)
diff --git a/runtime/staprun/relay_old.c b/runtime/staprun/relay_old.c
index bd746f19..33d2daf3 100644
--- a/runtime/staprun/relay_old.c
+++ b/runtime/staprun/relay_old.c
@@ -23,6 +23,14 @@ static int bulkmode = 0;
unsigned subbuf_size = 0;
unsigned n_subbufs = 0;
+struct switchfile_ctrl_block {
+ off_t wsize;
+ int fnum;
+ int rmfile;
+};
+
+static struct switchfile_ctrl_block global_scb = {0, 0, 0};
+
/* per-cpu buffer info */
static struct buf_status
{
@@ -70,6 +78,41 @@ void close_oldrelayfs(int detach)
close_relayfs_files(i);
}
+static int open_oldoutfile(int fnum, int cpu, int remove_file)
+{
+ char buf[PATH_MAX];
+ time_t t;
+ if (outfile_name) {
+ time(&t);
+ if (fnum_max) {
+ if (remove_file) {
+ /* remove oldest file */
+ if (make_outfile_name(buf, PATH_MAX, fnum - fnum_max,
+ cpu, read_backlog(cpu, fnum - fnum_max)) < 0)
+ return -1;
+ remove(buf); /* don't care */
+ }
+ write_backlog(cpu, fnum, t);
+ }
+ if (make_outfile_name(buf, PATH_MAX, fnum, cpu, t) < 0)
+ return -1;
+ } else if (bulkmode) {
+ if (sprintf_chk(buf, "stpd_cpu%d.%d", cpu, fnum))
+ return -1;
+ } else { /* stream mode */
+ out_fd[cpu] = STDOUT_FILENO;
+ return 0;
+ }
+
+ out_fd[cpu] = open (buf, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (out_fd[cpu] < 0) {
+ perr("Couldn't open output file %s", buf);
+ return -1;
+ }
+ if (set_clexec(out_fd[cpu]) < 0)
+ return -1;
+ return 0;
+}
/**
* open_relayfs_files - open and mmap buffer and open output file.
* Returns -1 on unexpected failure, 0 if file not found, 1 on success.
@@ -104,18 +147,31 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p
return -1;
}
+ if (fsize_max) {
+ if (init_backlog(cpu) < 0)
+ goto err2;
+ if (open_oldoutfile(0, cpu, 0) < 0)
+ goto err2;
+ goto opened;
+ }
if (outfile_name) {
/* special case: for testing we sometimes want to
* write to /dev/null */
if (strcmp(outfile_name, "/dev/null") == 0) {
strcpy(tmp, "/dev/null");
} else {
- if (sprintf_chk(tmp, "%s_%d", outfile_name, cpu))
- goto err1;
+ int len;
+ len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ goto err2;
+ }
+ if (snprintf_chk(&tmp[len], PATH_MAX - len, "_%d", cpu))
+ goto err2;
}
} else {
if (sprintf_chk(tmp, "stpd_cpu%d", cpu))
- goto err1;
+ goto err2;
}
if((percpu_tmpfile[cpu] = fopen(tmp, "w+")) == NULL) {
@@ -126,6 +182,7 @@ static int open_relayfs_files(int cpu, const char *relay_filebase, const char *p
perr("Couldn't open output file %s", tmp);
goto err2;
}
+opened:
total_bufsize = subbuf_size * n_subbufs;
relay_buffer[cpu] = mmap(NULL, total_bufsize, PROT_READ,
@@ -155,7 +212,8 @@ err1:
/**
* process_subbufs - write ready subbufs to disk
*/
-static int process_subbufs(struct _stp_buf_info *info)
+static int process_subbufs(struct _stp_buf_info *info,
+ struct switchfile_ctrl_block *scb)
{
unsigned subbufs_ready, start_subbuf, end_subbuf, subbuf_idx, i;
int len, cpu = info->cpu;
@@ -173,10 +231,23 @@ static int process_subbufs(struct _stp_buf_info *info)
padding = *((unsigned *)subbuf_ptr);
subbuf_ptr += sizeof(padding);
len = (subbuf_size - sizeof(padding)) - padding;
+ scb->wsize += len;
+ if (fsize_max && scb->wsize > fsize_max) {
+ fclose(percpu_tmpfile[cpu]);
+ scb->fnum ++;
+ if (fnum_max && scb->fnum == fnum_max)
+ scb->rmfile = 1;
+ if (open_oldoutfile(scb->fnum, cpu, scb->rmfile) < 0) {
+ perr("Couldn't open file for cpu %d, exiting.", cpu);
+ return -1;
+ }
+ scb->wsize = len;
+ }
if (len) {
if (fwrite_unlocked (subbuf_ptr, len, 1, percpu_tmpfile[cpu]) != 1) {
- _perr("Couldn't write to output file for cpu %d, exiting:", cpu);
- exit(1);
+ if (errno != EPIPE)
+ _perr("Couldn't write to output file for cpu %d, exiting:", cpu);
+ return -1;
}
}
subbufs_consumed++;
@@ -196,6 +267,7 @@ static void *reader_thread(void *data)
struct _stp_consumed_info consumed_info;
unsigned subbufs_consumed;
cpu_set_t cpu_mask;
+ struct switchfile_ctrl_block scb = {0, 0, 0};
CPU_ZERO(&cpu_mask);
CPU_SET(cpu, &cpu_mask);
@@ -210,14 +282,17 @@ static void *reader_thread(void *data)
if (rc < 0) {
if (errno != EINTR) {
_perr("poll error");
- exit(1);
+ break;
}
err("WARNING: poll warning: %s\n", strerror(errno));
rc = 0;
}
rc = read(proc_fd[cpu], &status[cpu].info, sizeof(struct _stp_buf_info));
- subbufs_consumed = process_subbufs(&status[cpu].info);
+ rc = process_subbufs(&status[cpu].info, &scb);
+ if (rc < 0)
+ break;
+ subbufs_consumed = rc;
if (subbufs_consumed) {
if (subbufs_consumed > status[cpu].max_backlog)
status[cpu].max_backlog = subbufs_consumed;
@@ -230,6 +305,37 @@ static void *reader_thread(void *data)
if (status[cpu].info.flushing)
pthread_exit(NULL);
} while (1);
+
+ /* Signal the main thread that we need to quit */
+ kill(getpid(), SIGTERM);
+ pthread_exit(NULL);
+}
+
+/**
+ * write_realtime_data - write realtime data packet to disk
+ */
+int write_realtime_data(void *data, ssize_t nb)
+{
+ ssize_t bw;
+ global_scb.wsize += nb;
+ if (fsize_max && global_scb.wsize > fsize_max) {
+ close(out_fd[0]);
+ global_scb.fnum++;
+ if (fnum_max && global_scb.fnum == fnum_max)
+ global_scb.rmfile = 1;
+ if (open_oldoutfile(global_scb.fnum, 0,
+ global_scb.rmfile) < 0) {
+ perr("Couldn't open file, exiting.");
+ return -1;
+ }
+ global_scb.wsize = nb;
+ }
+ bw = write(out_fd[0], data, nb);
+ if (bw >= 0 && bw != nb) {
+ nb = nb - bw;
+ bw = write(out_fd[0], data, nb);
+ }
+ return bw != nb;
}
/**
@@ -249,10 +355,22 @@ int init_oldrelayfs(void)
bulkmode = 1;
if (!bulkmode) {
+ int len;
+ char tmp[PATH_MAX];
+ if (fsize_max) {
+ if (init_backlog(0))
+ return -1;
+ return open_oldoutfile(0, 0, 0);
+ }
if (outfile_name) {
- out_fd[0] = open (outfile_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ len = stap_strfloctime(tmp, PATH_MAX, outfile_name, time(NULL));
+ if (len < 0) {
+ err("Invalid FILE name format\n");
+ return -1;
+ }
+ out_fd[0] = open (tmp, O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (out_fd[0] < 0 || set_clexec(out_fd[0]) < 0) {
- perr("Couldn't open output file '%s'", outfile_name);
+ perr("Couldn't open output file '%s'", tmp);
return -1;
}
} else
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index f49cc7db..bd6402e4 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -9,7 +9,7 @@
*
* Copyright (C) 2005-2008 Red Hat Inc.
*/
-
+#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
@@ -33,31 +33,35 @@
#include <sys/wait.h>
#include <sys/statfs.h>
#include <linux/version.h>
+#include <syslog.h>
/* Include config.h to pick up dependency for --prefix usage. */
#include "config.h"
-#define dbug(level, args...) {if (verbose>=level) {fprintf(stderr,"%s:%s:%d ",__name__,__FUNCTION__, __LINE__); fprintf(stderr,args);}}
+extern void eprintf(const char *fmt, ...);
+extern void switch_syslog(const char *name);
+
+#define dbug(level, args...) do {if (verbose>=level) {eprintf("%s:%s:%d ",__name__,__FUNCTION__, __LINE__); eprintf(args);}} while (0)
extern char *__name__;
/* print to stderr */
-#define err(args...) fprintf(stderr,args)
+#define err(args...) eprintf(args)
/* better perror() */
#define perr(args...) do { \
int _errno = errno; \
- fputs("ERROR: ", stderr); \
- fprintf(stderr, args); \
- fprintf(stderr, ": %s\n", strerror(_errno)); \
+ eprintf("ERROR: "); \
+ eprintf(args); \
+ eprintf(": %s\n", strerror(_errno)); \
} while (0)
/* Error messages. Use these for serious errors, not informational messages to stderr. */
-#define _err(args...) do {fprintf(stderr,"%s:%s:%d: ERROR: ",__name__, __FUNCTION__, __LINE__); fprintf(stderr,args);} while(0)
+#define _err(args...) do {eprintf("%s:%s:%d: ERROR: ",__name__, __FUNCTION__, __LINE__); eprintf(args);} while(0)
#define _perr(args...) do { \
int _errno = errno; \
_err(args); \
- fprintf(stderr, ": %s\n", strerror(_errno)); \
+ eprintf(": %s\n", strerror(_errno)); \
} while (0)
#define overflow_error() _err("Internal buffer overflow. Please file a bug report.\n")
@@ -114,7 +118,12 @@ int init_relayfs(void);
void close_relayfs(void);
int init_oldrelayfs(void);
void close_oldrelayfs(int);
+int write_realtime_data(void *data, ssize_t nb);
void setup_signals(void);
+int make_outfile_name(char *buf, int max, int fnum, int cpu, time_t t);
+int init_backlog(int cpu);
+void write_backlog(int cpu, int fnum, time_t t);
+time_t read_backlog(int cpu, int fnum);
/* staprun_funcs.c */
void setup_staprun_signals(void);
const char *moderror(int err);
@@ -126,6 +135,7 @@ void start_symbol_thread(void);
void stop_symbol_thread(void);
/* common.c functions */
+int stap_strfloctime(char *buf, size_t max, const char *fmt, time_t t);
void parse_args(int argc, char **argv);
void usage(char *prog);
void parse_modpath(const char *);
@@ -154,6 +164,9 @@ extern int attach_mod;
extern int delete_mod;
extern int load_only;
extern int need_uprobes;
+extern int daemon_mode;
+extern off_t fsize_max;
+extern int fnum_max;
/* getopt variables */
extern char *optarg;
diff --git a/runtime/staprun/staprun_funcs.c b/runtime/staprun/staprun_funcs.c
index 5e7fa102..8da7e7e8 100644
--- a/runtime/staprun/staprun_funcs.c
+++ b/runtime/staprun/staprun_funcs.c
@@ -7,14 +7,20 @@
* Public License (GPL); either version 2, or (at your option) any
* later version.
*
- * Copyright (C) 2007-2008 Red Hat Inc.
+ * Copyright (C) 2007-2009 Red Hat Inc.
*/
+#include "config.h"
#include "staprun.h"
+#if HAVE_NSS
+#include "modverify.h"
+#endif
+
#include <sys/mount.h>
#include <sys/utsname.h>
#include <grp.h>
#include <pwd.h>
+#include <assert.h>
extern long init_module(void *, unsigned long, const char *);
@@ -199,6 +205,44 @@ int mountfs(void)
return 0;
}
+#if HAVE_NSS
+/*
+ * Modules which have been signed using a certificate and private key
+ * corresponding to a certificate and public key in the database in
+ * the '$sysconfdir/systemtap/staprun' directory may be loaded by
+ * anyone.
+ *
+ * Returns: -1 on errors, 0 on failure, 1 on success.
+ */
+static int
+check_signature(void)
+{
+ char module_realpath[PATH_MAX];
+ char signature_realpath[PATH_MAX];
+ int rc;
+
+ dbug(2, "checking signature for %s\n", modpath);
+
+ /* Use realpath() to canonicalize the module path. */
+ if (realpath(modpath, module_realpath) == NULL) {
+ perr("Unable to canonicalize module path \"%s\"", modpath);
+ return MODULE_CHECK_ERROR;
+ }
+
+ /* Now add the .sgn suffix to get the signature file name. */
+ if (strlen (module_realpath) > PATH_MAX - 4) {
+ err("Path \"%s\" is too long.", modpath);
+ return MODULE_CHECK_ERROR;
+ }
+ sprintf (signature_realpath, "%s.sgn", module_realpath);
+
+ rc = verify_module (module_realpath, signature_realpath);
+
+ dbug(2, "verify_module returns %d\n", rc);
+
+ return rc;
+}
+#endif /* HAVE_NSS */
/*
* Members of the 'stapusr' group can only use "blessed" modules -
@@ -269,6 +313,15 @@ check_path(void)
return -1;
}
+ /* Overwrite the modpath with the canonicalized one, to defeat
+ a possible race between path checking below and somewhat later
+ module loading. */
+ modpath = strdup (module_realpath);
+ if (modpath == NULL) {
+ _perr("allocating memory failed");
+ exit (1);
+ }
+
/* To make sure the user can't specify something like
* /lib/modules/`uname -r`/systemtapmod.ko, put a '/' on the
* end of staplib_dir_realpath. */
@@ -293,22 +346,23 @@ check_path(void)
}
/*
- * Check the user's permissions. Is he allowed to run staprun (or is
- * he limited to "blessed" modules)?
+ * Check the user's group membership. Is he allowed to run staprun (or is
*
- * Returns: -1 on errors, 0 on failure, 1 on success.
+ * o members of stapdev can do anything
+ * o members of stapusr can load modules from /lib/modules/KVER/systemtap
+ *
+ * Returns: -2 if neither group exists
+ * -1 for other errors
+ * 0 on failure
+ * 1 on success
*/
-int check_permissions(void)
+static int
+check_groups (void)
{
gid_t gid, gidlist[NGROUPS_MAX];
gid_t stapdev_gid, stapusr_gid;
int i, ngids;
struct group *stgr;
- int path_check = 0;
-
- /* If we're root, we can do anything. */
- if (getuid() == 0)
- return 1;
/* Lookup the gid for group "stapdev" */
errno = 0;
@@ -332,55 +386,42 @@ int check_permissions(void)
else
stapusr_gid = stgr->gr_gid;
- /* If neither group was found, just return an error. */
- if (stapdev_gid == (gid_t)-1 && stapusr_gid == (gid_t)-1) {
- err("ERROR: You are trying to run stap as a normal user.\n"
- "You should either be root, or be part of either "
- "group \"stapdev\" or group \"stapusr\".\n"
- "Your system doesn't seem to have either group.\n"
- "For more information, please consult the \"SAFETY AND SECURITY\" section of the \"stap(1)\" manpage\n");
- return -1;
- }
+ /* If neither group was found, then return -2. */
+ if (stapdev_gid == (gid_t)-1 && stapusr_gid == (gid_t)-1)
+ return -2;
/* According to the getgroups() man page, getgroups() may not
* return the effective gid, so try to match it first. */
gid = getegid();
if (gid == stapdev_gid)
return 1;
- else if (gid == stapusr_gid)
- path_check = 1;
- /* Get the list of the user's groups. */
- ngids = getgroups(NGROUPS_MAX, gidlist);
- if (ngids < 0) {
- perr("Unable to retrieve group list");
- return -1;
- }
-
- for (i = 0; i < ngids; i++) {
- /* If the user is a member of 'stapdev', then we're
- * done, since he can use staprun without any
- * restrictions. */
- if (gidlist[i] == stapdev_gid)
- return 1;
-
- /* If the user is a member of 'stapusr', then we'll
- * need to check the module path. However, we'll keep
- * checking groups since it is possible the user is a
- * member of both groups and we haven't seen the
- * 'stapdev' group yet. */
- if (gidlist[i] == stapusr_gid)
- path_check = 1;
- }
+ if (gid != stapusr_gid) {
+ /* Get the list of the user's groups. */
+ ngids = getgroups(NGROUPS_MAX, gidlist);
+ if (ngids < 0) {
+ perr("Unable to retrieve group list");
+ return -1;
+ }
- /* If path_check is 0, then the user isn't a member of either
- * group. Error out. */
- if (path_check == 0) {
- err("ERROR: You are trying to run stap as a normal user.\n"
- "You must be a member of either group \"stapdev\" or group \"stapusr\".\n"
- "Please contact your system administrator to get yourself membership to either of those groups.\n"
- "For more information, please consult the \"SAFETY AND SECURITY\" section of the \"stap(1)\" manpage.\n");
- return 0;
+ for (i = 0; i < ngids; i++) {
+ /* If the user is a member of 'stapdev', then we're
+ * done, since he can use staprun without any
+ * restrictions. */
+ if (gidlist[i] == stapdev_gid)
+ return 1;
+
+ /* If the user is a member of 'stapusr', then we'll
+ * need to check the module path. However, we'll keep
+ * checking groups since it is possible the user is a
+ * member of both groups and we haven't seen the
+ * 'stapdev' group yet. */
+ if (gidlist[i] == stapusr_gid)
+ gid = stapusr_gid;
+ }
+ /* Not a member of stapusr? */
+ if (gid != stapusr_gid)
+ return 0;
}
/* At this point the user is only a member of the 'stapusr'
@@ -389,3 +430,50 @@ int check_permissions(void)
* is in that directory. */
return check_path();
}
+
+/*
+ * Check the user's permissions. Is he allowed to run staprun (or is
+ * he limited to "blessed" modules)?
+ *
+ * There are several levels of possible permission:
+ *
+ * 1) root can do anything
+ * 2) members of stapdev can do anything
+ * 3) members of stapusr can load modules from /lib/modules/KVER/systemtap
+ *
+ * It is only an error if all 3 levels of checking fail
+ *
+ * Returns: -1 on errors, 0 on failure, 1 on success.
+ */
+int check_permissions(void)
+{
+ int check_groups_rc;
+#if HAVE_NSS
+ int check_signature_rc = 0;
+
+ /* Attempt to verify the module against its signature. Return failure
+ if the module has been tampered with (altered). */
+ check_signature_rc = check_signature ();
+ if (check_signature_rc == MODULE_ALTERED)
+ return 0;
+#endif
+
+ /* If we're root, we can do anything. */
+ if (getuid() == 0)
+ return 1;
+
+ /* Check permissions for group membership. */
+ check_groups_rc = check_groups ();
+ if (check_groups_rc == 1)
+ return 1;
+
+ err("ERROR: You are trying to run stap as a normal user.\n"
+ "You should either be root, or be part of either "
+ "group \"stapdev\" or group \"stapusr\".\n");
+ if (check_groups_rc == -2) {
+ err("Your system doesn't seem to have either group.\n");
+ check_groups_rc = -1;
+ }
+
+ return check_groups_rc;
+}
diff --git a/runtime/sym.c b/runtime/sym.c
index 31700326..386005b2 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -14,6 +14,7 @@
#include "sym.h"
#include "string.c"
+#include "task_finder_vma.c"
/** @file sym.c
* @addtogroup sym Symbolic Functions
@@ -21,6 +22,62 @@
* @{
*/
+static void _stp_sym_init(void)
+{
+ static int initialized = 0;
+ if (! initialized) {
+ __stp_tf_vma_initialize();
+ initialized = 1;
+ }
+}
+
+/* Callback that needs to be registered (in tapsets.cxx for
+ emit_module_init) for every user task path or pid for which we
+ might need symbols or unwind info. */
+static int _stp_tf_mmap_cb(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ char *path,
+ unsigned long addr,
+ unsigned long length,
+ unsigned long offset,
+ unsigned long vm_flags)
+{
+ int i;
+ struct _stp_module *module = NULL;
+
+#ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "mmap_cb: tsk %d:%d path %s, addr 0x%08lx, length 0x%08lx, offset 0x%lx, flags 0x%lx\n",
+ tsk->pid, tsk->tgid, path, addr, length, offset, vm_flags);
+#endif
+ if (path != NULL) {
+ for (i = 0; i < _stp_num_modules; i++) {
+ if (strcmp(path, _stp_modules[i]->path) == 0)
+ {
+#ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "vm_cb: matched path %s to module\n",
+ path);
+#endif
+ module = _stp_modules[i];
+ break;
+ }
+ }
+ }
+ stap_add_vma_map_info(tsk->group_leader, addr, addr + length, offset,
+ module);
+ return 0;
+}
+
+static int _stp_tf_munmap_cb(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ unsigned long addr,
+ unsigned long length)
+{
+ stap_remove_vma_map_info(tsk->group_leader, addr, addr + length, 0);
+ return 0;
+}
+
/* XXX: this needs to be address-space-specific. */
static unsigned long _stp_module_relocate(const char *module, const char *section, unsigned long offset)
{
@@ -72,35 +129,54 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
return 0;
}
-
-/* Return module owner and fills in closest section of the address
- if found, return NULL otherwise.
+/* Return module owner and, if sec != NULL, fills in closest section
+ of the address if found, return NULL otherwise.
XXX: needs to be address-space-specific. */
static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
+ struct task_struct *task,
struct _stp_section **sec)
{
- struct _stp_module *m = NULL;
+ void *user = NULL;
unsigned midx = 0;
- unsigned long closest_section_offset = ~0;
+
+ // Try vma matching first if task given.
+ if (task)
+ {
+ unsigned long vm_start = 0;
+ if (stap_find_vma_map_info(task->group_leader, addr,
+ &vm_start, NULL,
+ NULL, &user) == 0)
+ if (user != NULL)
+ {
+ struct _stp_module *m = (struct _stp_module *)user;
+ if (sec)
+ *sec = &m->sections[0]; // XXX check actual section and relocate
+ dbug_sym(1, "found section %s in module %s at 0x%lx\n",
+ m->sections[0].name, m->name, vm_start);
+ if (strcmp(".dynamic", m->sections[0].name) == 0)
+ m->sections[0].addr = vm_start; // cheat...
+ return m;
+ }
+ }
+
for (midx = 0; midx < _stp_num_modules; midx++)
{
unsigned secidx;
for (secidx = 0; secidx < _stp_modules[midx]->num_sections; secidx++)
{
- unsigned long this_section_addr;
- unsigned long this_section_offset;
- this_section_addr = _stp_modules[midx]->sections[secidx].addr;
- if (addr < this_section_addr) continue;
- this_section_offset = addr - this_section_addr;
- if (this_section_offset < closest_section_offset)
- {
- closest_section_offset = this_section_offset;
- m = _stp_modules[midx];
- *sec = & m->sections[secidx];
+ unsigned long sec_addr;
+ unsigned long sec_size;
+ sec_addr = _stp_modules[midx]->sections[secidx].addr;
+ sec_size = _stp_modules[midx]->sections[secidx].size;
+ if (addr >= sec_addr && addr < sec_addr + sec_size)
+ {
+ if (sec)
+ *sec = & _stp_modules[midx]->sections[secidx];
+ return _stp_modules[midx];
}
}
}
- return m;
+ return NULL;
}
@@ -109,14 +185,15 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo
unsigned long *offset,
const char **modname,
/* char ** secname? */
- char *namebuf)
+ char *namebuf,
+ struct task_struct *task)
{
struct _stp_module *m = NULL;
struct _stp_section *sec = NULL;
struct _stp_symbol *s = NULL;
unsigned end, begin = 0;
- m = _stp_mod_sec_lookup(addr, &sec);
+ m = _stp_mod_sec_lookup(addr, task, &sec);
if (unlikely (m == NULL || sec == NULL))
return NULL;
@@ -195,34 +272,29 @@ static int _stp_module_check(void)
dwfl_module_build_id was not intended to return the end address. */
notes_addr -= m->build_id_len;
- if (notes_addr > base_addr) {
- for (j = 0; j < m->build_id_len; j++)
- {
- unsigned char theory, practice;
- theory = m->build_id_bits [j];
- practice = ((unsigned char*) notes_addr) [j];
- /* XXX: consider using kread() instead of above. */
- if (theory != practice)
- {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
- _stp_error ("%s: inconsistent %s build-id byte #%d "
- "(0x%x [actual] vs. 0x%x [debuginfo])\n",
- THIS_MODULE->name, m->name, j,
- practice, theory);
- return 1;
- #else
- /* This branch is a surrogate for
- kernels affected by Fedora bug
- #465873. */
- printk(KERN_WARNING
- "%s: inconsistent %s build-id byte #%d "
- "(0x%x [actual] vs. 0x%x [debuginfo])\n",
- THIS_MODULE->name, m->name, j,
- practice, theory);
- break; /* Note just the first mismatch. */
- #endif
- }
- }
+ if (notes_addr <= base_addr) /* shouldn't happen */
+ continue;
+ if (memcmp(m->build_id_bits, (unsigned char*) notes_addr, m->build_id_len)) {
+ const char *basename;
+
+ basename = strrchr(m->path, '/');
+ if (basename)
+ basename++;
+ else
+ basename = m->path;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ _stp_error ("Build-id mismatch: \"%s\" %.*M"
+ " vs. \"%s\" %.*M\n",
+ m->name, m->build_id_len, notes_addr,
+ basename, m->build_id_len, m->build_id_bits);
+ return 1;
+#else
+ /* This branch is a surrogate for kernels
+ * affected by Fedora bug #465873. */
+ printk(KERN_WARNING
+ "Build-id mismatch: \"%s\" vs. \"%s\"\n",
+ m->name, basename);
+#endif
}
} /* end checking */
} /* end loop */
@@ -241,7 +313,33 @@ static void _stp_symbol_print(unsigned long address)
const char *name;
unsigned long offset, size;
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, NULL);
+
+ _stp_printf("%p", (int64_t) address);
+
+ if (name) {
+ if (modname && *modname)
+ _stp_printf(" : %s+%#lx/%#lx [%s]", name, offset, size, modname);
+ else
+ _stp_printf(" : %s+%#lx/%#lx", name, offset, size);
+ }
+}
+
+/** Print an user space address from a specific task symbolically.
+ * @param address The address to lookup.
+ * @param task The address to lookup.
+ * @note Symbolic lookups should not normally be done within
+ * a probe because it is too time-consuming. Use at module exit time.
+ */
+
+static void _stp_usymbol_print(unsigned long address, struct task_struct *task)
+{
+ const char *modname;
+ const char *name;
+ unsigned long offset, size;
+
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL,
+ task);
_stp_printf("%p", (int64_t) address);
@@ -254,7 +352,8 @@ static void _stp_symbol_print(unsigned long address)
}
/* Like _stp_symbol_print, except only print if the address is a valid function address */
-static int _stp_func_print(unsigned long address, int verbose, int exact)
+static int _stp_func_print(unsigned long address, int verbose, int exact,
+ struct task_struct *task)
{
const char *modname;
const char *name;
@@ -266,7 +365,7 @@ static int _stp_func_print(unsigned long address, int verbose, int exact)
else
exstr = " (inexact)";
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL);
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL, task);
if (name) {
if (verbose) {
@@ -282,16 +381,29 @@ static int _stp_func_print(unsigned long address, int verbose, int exact)
return 0;
}
-static void _stp_symbol_snprint(char *str, size_t len, unsigned long address)
+/** Puts symbolic information of an address in a string.
+ * @param src The string to fill in.
+ * @param len The length of the given src string.
+ * @param address The address to lookup.
+ * @param add_mod Whether to include module name information if found.
+ */
+
+static void _stp_symbol_snprint(char *str, size_t len, unsigned long address,
+ struct task_struct *task, int add_mod)
{
const char *modname;
const char *name;
unsigned long offset, size;
- name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL);
- if (name)
- strlcpy(str, name, len);
- else
+ name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL,
+ task);
+ if (name) {
+ if (add_mod && modname && *modname)
+ _stp_snprintf(str, len, "%s %s+%#lx/%#lx",
+ name, modname, offset, size);
+ else
+ strlcpy(str, name, len);
+ } else
_stp_snprintf(str, len, "%p", (int64_t) address);
}
diff --git a/runtime/sym.h b/runtime/sym.h
index e642cab4..80c334fb 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -18,6 +18,7 @@ struct _stp_symbol {
struct _stp_section {
const char *name;
unsigned long addr; /* XXX: belongs in per-address-space tables */
+ unsigned long size; /* length of the address space module covers. */
struct _stp_symbol *symbols; /* ordered by address */
unsigned num_symbols;
};
@@ -25,6 +26,7 @@ struct _stp_section {
struct _stp_module {
const char* name;
+ const char* path; /* canonical path used for runtime matching. */
struct _stp_section *sections;
unsigned num_sections;
diff --git a/runtime/syscall.h b/runtime/syscall.h
index ae451070..38b523e1 100644
--- a/runtime/syscall.h
+++ b/runtime/syscall.h
@@ -1,5 +1,6 @@
-/* syscall defines and inlines
- * Copyright (C) 2008 Red Hat Inc.
+/*
+ * syscall defines and inlines
+ * Copyright (C) 2008-2009 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
@@ -89,9 +90,17 @@
#error "Unimplemented architecture"
#endif
+#ifdef STAPCONF_ASM_SYSCALL_H
+
+/* If the system has asm/syscall.h, use defines from it. */
+#include <asm/syscall.h>
+
+#else /* !STAPCONF_ASM_SYSCALL_H */
+
+/* If the system doesn't have asm/syscall.h, use our defines. */
#if defined(__i386__) || defined(__x86_64__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
#if defined(STAPCONF_X86_UNIREGS)
return regs->orig_ax;
@@ -104,37 +113,45 @@ __stp_user_syscall_nr(struct pt_regs *regs)
#endif
#if defined(__powerpc__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
return regs->gpr[0];
}
#endif
#if defined(__ia64__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
- return regs->r15;
+ if ((long)regs->cr_ifs < 0) /* Not a syscall */
+ return -1;
+
+#ifdef CONFIG_IA32_SUPPORT
+ if (IS_IA32_PROCESS(regs))
+ return regs->r1;
+#endif
+
+ return regs->r15;
}
#endif
#if defined(__s390__) || defined(__s390x__)
-static inline unsigned long
-__stp_user_syscall_nr(struct pt_regs *regs)
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
- // might need to be 'orig_gpr2'
+ // might need to be 'orig_gpr2'
return regs->gprs[2];
}
#endif
#if defined(__i386__) || defined(__x86_64__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
#ifdef CONFIG_IA32_EMULATION
// This code works, but isn't what we need. Since
-// __stp_user_syscall_arg() doesn't sign-extend, a value passed in as
+// syscall_get_syscall_arg() doesn't sign-extend, a value passed in as
// an argument and then returned won't compare correctly anymore. So,
// for now, disable this code.
# if 0
@@ -145,158 +162,332 @@ __stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
# endif
#endif
#if defined(STAPCONF_X86_UNIREGS)
- return &regs->ax;
+ return regs->ax;
#elif defined(__x86_64__)
- return &regs->rax;
+ return regs->rax;
#elif defined (__i386__)
- return &regs->eax;
+ return regs->eax;
#endif
}
#endif
#if defined(__powerpc__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
- return &regs->gpr[3];
+ return regs->gpr[3];
}
#endif
#if defined(__ia64__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
- return &regs->r8;
+ return regs->r8;
}
#endif
#if defined(__s390__) || defined(__s390x__)
-static inline long *
-__stp_user_syscall_return_value(struct task_struct *task, struct pt_regs *regs)
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
{
- return &regs->gprs[2];
+ return regs->gprs[2];
}
#endif
#if defined(__i386__) || defined(__x86_64__)
-static inline long *
-__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
{
-#if defined(__i386__)
- if (n > 5) {
- _stp_error("syscall arg > 5");
- return NULL;
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
}
+#if defined(__i386__)
#if defined(STAPCONF_X86_UNIREGS)
- return &regs->bx + n;
+ memcpy(args, &regs->bx + i, n * sizeof(args[0]));
#else
- return &regs->ebx + n;
+ memcpy(args, &regs->ebx + i, n * sizeof(args[0]));
#endif
#elif defined(__x86_64__)
#ifdef CONFIG_IA32_EMULATION
- if (test_tsk_thread_flag(task, TIF_IA32))
- switch (n) {
+ if (test_tsk_thread_flag(task, TIF_IA32)) {
+ switch (i) {
#if defined(STAPCONF_X86_UNIREGS)
- case 0: return &regs->bx;
- case 1: return &regs->cx;
- case 2: return &regs->dx;
- case 3: return &regs->si;
- case 4: return &regs->di;
- case 5: return &regs->bp;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->bx;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->cx;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->dx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->si;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->di;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->bp;
#else
- case 0: return &regs->rbx;
- case 1: return &regs->rcx;
- case 2: return &regs->rdx;
- case 3: return &regs->rsi;
- case 4: return &regs->rdi;
- case 5: return &regs->rbp;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->rbx;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->rcx;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->rdx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->rsi;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->rdi;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->rbp;
#endif
- default:
- _stp_error("syscall arg > 5");
- return NULL;
}
+ return;
+ }
#endif /* CONFIG_IA32_EMULATION */
- switch (n) {
+ switch (i) {
#if defined(STAPCONF_X86_UNIREGS)
- case 0: return &regs->di;
- case 1: return &regs->si;
- case 2: return &regs->dx;
- case 3: return &regs->r10;
- case 4: return &regs->r8;
- case 5: return &regs->r9;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->di;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->si;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->dx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->r10;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->r8;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->r9;
#else
- case 0: return &regs->rdi;
- case 1: return &regs->rsi;
- case 2: return &regs->rdx;
- case 3: return &regs->r10;
- case 4: return &regs->r8;
- case 5: return &regs->r9;
+ case 0:
+ if (!n--) break;
+ *args++ = regs->rdi;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->rsi;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->rdx;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->r10;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->r8;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->r9;
#endif
- default:
- _stp_error("syscall arg > 5");
- return NULL;
}
#endif /* CONFIG_X86_32 */
+ return;
}
#endif
#if defined(__powerpc__)
-static inline long *
-__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
{
- switch (n) {
- case 0: return &regs->gpr[3];
- case 1: return &regs->gpr[4];
- case 2: return &regs->gpr[5];
- case 3: return &regs->gpr[6];
- case 4: return &regs->gpr[7];
- case 5: return &regs->gpr[8];
- default:
- _stp_error("syscall arg > 5");
- return NULL;
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
}
+#ifdef CONFIG_PPC64
+ if (test_tsk_thread_flag(task, TIF_32BIT)) {
+ /*
+ * Zero-extend 32-bit argument values. The high bits are
+ * garbage ignored by the actual syscall dispatch.
+ */
+ while (n-- > 0)
+ args[n] = (u32) regs->gpr[3 + i + n];
+ return;
+ }
+#endif
+ memcpy(args, &regs->gpr[3 + i], n * sizeof(args[0]));
}
#endif
#if defined(__ia64__)
-#define __stp_user_syscall_arg(task, regs, n) \
- ____stp_user_syscall_arg(task, regs, n, &c->unwaddr)
-static inline long *
-____stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n, unsigned long **cache)
+/* Return TRUE if PT was created due to kernel-entry via a system-call. */
+
+static inline int
+in_syscall (struct pt_regs *pt)
+{
+ return (long) pt->cr_ifs >= 0;
+}
+
+struct syscall_get_set_args {
+ unsigned int i;
+ unsigned int n;
+ unsigned long *args;
+ struct pt_regs *regs;
+ int rw;
+};
+
+#define CFM_SOF(cfm) ((cfm) & 0x7f) /* Size of frame */
+#define CFM_SOL(cfm) (((cfm) >> 7) & 0x7f) /* Size of locals */
+#define CFM_OUT(cfm) (CFM_SOF(cfm) - CFM_SOL(cfm)) /* Size of outputs */
+
+static void syscall_get_set_args_cb(struct unw_frame_info *info, void *data)
+{
+ struct syscall_get_set_args *args = data;
+ struct pt_regs *pt = args->regs;
+ unsigned long *krbs, cfm, ndirty;
+ int i, count;
+
+ if (unw_unwind_to_user(info) < 0)
+ return;
+
+ cfm = pt->cr_ifs;
+ krbs = (unsigned long *)info->task + IA64_RBS_OFFSET/8;
+ ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
+
+ count = 0;
+ if (in_syscall(pt))
+ /* args->i + args->n must be less equal than nr outputs */
+ count = min_t(int, args->n, CFM_OUT(cfm) - args->i);
+
+ for (i = 0; i < count; i++) {
+ /* Skips dirties and locals */
+ if (args->rw)
+ *ia64_rse_skip_regs(krbs,
+ ndirty + CFM_SOL(cfm) + args->i + i) =
+ args->args[i];
+ else
+ args->args[i] = *ia64_rse_skip_regs(krbs,
+ ndirty + CFM_SOL(cfm) + args->i + i);
+ }
+
+ if (!args->rw) {
+ while (i < args->n) {
+ args->args[i] = 0;
+ i++;
+ }
+ }
+}
+
+void ia64_syscall_get_set_arguments(struct task_struct *task,
+ struct pt_regs *regs, unsigned int i, unsigned int n,
+ unsigned long *args, int rw)
{
- if (n > 5) {
- _stp_error("syscall arg > 5");
- return NULL;
+ struct syscall_get_set_args data = {
+ .i = i,
+ .n = n,
+ .args = args,
+ .regs = regs,
+ .rw = rw,
+ };
+
+ if (task == current)
+ unw_init_running(syscall_get_set_args_cb, &data);
+ else {
+ struct unw_frame_info ufi;
+ memset(&ufi, 0, sizeof(ufi));
+ unw_init_from_blocked_task(&ufi, task);
+ syscall_get_set_args_cb(&ufi, &data);
}
- return __ia64_fetch_register(n + 32, regs, cache);
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+
+#ifdef CONFIG_IA32_SUPPORT
+ if (IS_IA32_PROCESS(regs)) {
+ switch (i + n) {
+ case 6:
+ if (!n--) break;
+ *args++ = regs->r13;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->r15;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->r14;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->r10;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->r9;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->r11;
+ case 0:
+ if (!n--) break;
+ default:
+ BUG();
+ break;
+ }
+
+ return;
+ }
+#endif
+ ia64_syscall_get_set_arguments(task, regs, i, n, args, 0);
}
#endif
#if defined(__s390__) || defined(__s390x__)
-static inline long *
-__stp_user_syscall_arg(struct task_struct *task, struct pt_regs *regs,
- unsigned int n)
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+ unsigned int i, unsigned int n, unsigned long *args)
{
- /* If we were returning a value, we could check for TIF_31BIT
- * here and cast the value with '(u32)' to make sure it got
- * down to 32bits. But, since we're returning an address,
- * there isn't much we can do. */
- switch (n) {
- case 0: return &regs->orig_gpr2;
- case 1: return &regs->gprs[3];
- case 2: return &regs->gprs[4];
- case 3: return &regs->gprs[5];
- case 4: return &regs->gprs[6];
- case 5: return &regs->args[0];
- default:
- _stp_error("syscall arg > 5");
- return NULL;
+ unsigned long mask = -1UL;
+
+ if (i + n > 6) {
+ _stp_error("invalid syscall arg request");
+ return;
+ }
+#ifdef CONFIG_COMPAT
+ if (test_tsk_thread_flag(task, TIF_31BIT))
+ mask = 0xffffffff;
+#endif
+ switch (i) {
+ case 0:
+ if (!n--) break;
+ *args++ = regs->orig_gpr2 & mask;
+ case 1:
+ if (!n--) break;
+ *args++ = regs->gprs[3] & mask;
+ case 2:
+ if (!n--) break;
+ *args++ = regs->gprs[4] & mask;
+ case 3:
+ if (!n--) break;
+ *args++ = regs->gprs[5] & mask;
+ case 4:
+ if (!n--) break;
+ *args++ = regs->gprs[6] & mask;
+ case 5:
+ if (!n--) break;
+ *args++ = regs->args[0] & mask;
}
}
#endif
+#endif /* !STAPCONF_ASM_SYSCALL_H */
#endif /* _SYSCALL_H_ */
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 9db713c3..f5e059ca 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -2,17 +2,24 @@
#define TASK_FINDER_C
#if ! defined(CONFIG_UTRACE)
-#error "Need CONFIG_UTRACE!"
-#endif
+/* Dummy definitions for use in sym.c */
+struct stap_task_finder_target { };
+#else
#include <linux/utrace.h>
+
+/* PR9974: Adapt to struct renaming. */
+#ifdef UTRACE_API_VERSION
+#define utrace_attached_engine utrace_engine
+#endif
+
#include <linux/list.h>
#include <linux/binfmts.h>
#include <linux/mount.h>
#include "syscall.h"
#include "utrace_compatibility.h"
-#include "task_finder_vma.c"
+#include "task_finder_map.c"
static LIST_HEAD(__stp_task_finder_list);
@@ -33,51 +40,49 @@ static atomic_t __stp_attach_count = ATOMIC_INIT (0);
#define debug_task_finder_attach() (atomic_inc(&__stp_attach_count))
#define debug_task_finder_detach() (atomic_dec(&__stp_attach_count))
+#ifdef DEBUG_TASK_FINDER_PRINTK
+#define debug_task_finder_report() (printk(KERN_ERR \
+ "%s:%d attach count: %d, inuse count: %d\n", \
+ __FUNCTION__, __LINE__, \
+ atomic_read(&__stp_attach_count), \
+ atomic_read(&__stp_inuse_count)))
+#else
#define debug_task_finder_report() (_stp_dbug(__FUNCTION__, __LINE__, \
"attach count: %d, inuse count: %d\n", \
atomic_read(&__stp_attach_count), \
atomic_read(&__stp_inuse_count)))
+#endif /* !DEBUG_TASK_FINDER_PRINTK */
#else
#define debug_task_finder_attach() /* empty */
#define debug_task_finder_detach() /* empty */
#define debug_task_finder_report() /* empty */
-#endif
+#endif /* !DEBUG_TASK_FINDER */
typedef int (*stap_task_finder_callback)(struct stap_task_finder_target *tgt,
struct task_struct *tsk,
int register_p,
int process_p);
-typedef int (*stap_task_finder_vm_callback)(struct stap_task_finder_target *tgt,
- struct task_struct *tsk,
- int map_p, char *vm_path,
- unsigned long vm_start,
- unsigned long vm_end,
- unsigned long vm_pgoff);
-
-#ifdef DEBUG_TASK_FINDER_VMA
-static int __stp_tf_vm_cb(struct stap_task_finder_target *tgt,
- struct task_struct *tsk,
- int map_p, char *vm_path,
- unsigned long vm_start,
- unsigned long vm_end,
- unsigned long vm_pgoff)
-{
- _stp_dbug(__FUNCTION__, __LINE__,
- "vm_cb: tsk %d:%d path %s, start 0x%08lx, end 0x%08lx, offset 0x%lx\n",
- tsk->pid, map_p, vm_path, vm_start, vm_end, vm_pgoff);
- if (map_p) {
- // FIXME: What should we do with vm_path? We can't save
- // the vm_path pointer itself, but we don't have any
- // storage space allocated to save it in...
- stap_add_vma_map_info(tsk, vm_start, vm_end, vm_pgoff);
- }
- else {
- stap_remove_vma_map_info(tsk, vm_start, vm_end, vm_pgoff);
- }
- return 0;
-}
-#endif
+typedef int
+(*stap_task_finder_mmap_callback)(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ char *path,
+ unsigned long addr,
+ unsigned long length,
+ unsigned long offset,
+ unsigned long vm_flags);
+typedef int
+(*stap_task_finder_munmap_callback)(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ unsigned long addr,
+ unsigned long length);
+
+typedef int
+(*stap_task_finder_mprotect_callback)(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ unsigned long addr,
+ unsigned long length,
+ int prot);
struct stap_task_finder_target {
/* private: */
@@ -86,14 +91,18 @@ struct stap_task_finder_target {
struct list_head callback_list;
struct utrace_engine_ops ops;
unsigned engine_attached:1;
- unsigned vm_events:1;
+ unsigned mmap_events:1;
+ unsigned munmap_events:1;
+ unsigned mprotect_events:1;
size_t pathlen;
/* public: */
const char *pathname;
pid_t pid;
stap_task_finder_callback callback;
- stap_task_finder_vm_callback vm_callback;
+ stap_task_finder_mmap_callback mmap_callback;
+ stap_task_finder_munmap_callback munmap_callback;
+ stap_task_finder_mprotect_callback mprotect_callback;
};
#ifdef UTRACE_ORIG_VERSION
@@ -165,7 +174,9 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
// Make sure everything is initialized properly.
new_tgt->engine_attached = 0;
- new_tgt->vm_events = 0;
+ new_tgt->mmap_events = 0;
+ new_tgt->munmap_events = 0;
+ new_tgt->mprotect_events = 0;
memset(&new_tgt->ops, 0, sizeof(new_tgt->ops));
new_tgt->ops.report_death = &__stp_utrace_task_finder_target_death;
new_tgt->ops.report_quiesce = &__stp_utrace_task_finder_target_quiesce;
@@ -184,7 +195,7 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
&& strcmp(tgt->pathname, new_tgt->pathname) == 0)
/* pid-based target (a specific pid or all
* pids) */
- || (new_tgt->pathlen == 0
+ || (new_tgt->pathlen == 0 && tgt->pathlen == 0
&& tgt->pid == new_tgt->pid))) {
found_node = 1;
break;
@@ -202,9 +213,13 @@ stap_register_task_finder_target(struct stap_task_finder_target *new_tgt)
// Add this target to the callback list for this task.
list_add_tail(&new_tgt->callback_list, &tgt->callback_list_head);
- // If the new target has a vm_callback, remember this.
- if (new_tgt->vm_callback != NULL)
- tgt->vm_events = 1;
+ // If the new target has any m* callbacks, remember this.
+ if (new_tgt->mmap_callback != NULL)
+ tgt->mmap_events = 1;
+ if (new_tgt->munmap_callback != NULL)
+ tgt->munmap_events = 1;
+ if (new_tgt->mprotect_callback != NULL)
+ tgt->mprotect_events = 1;
return 0;
}
@@ -264,11 +279,15 @@ stap_utrace_detach(struct task_struct *tsk,
break;
case -ESRCH: /* REAP callback already begun */
case -EALREADY: /* DEATH callback already begun */
- rc = 0; /* ignore these errors*/
+ rc = 0; /* ignore these errors */
+ break;
+ case -EINPROGRESS:
+ debug_task_finder_detach();
+ rc = 0;
break;
default:
rc = -rc;
- _stp_error("utrace_detach returned error %d on pid %d",
+ _stp_error("utrace_control returned error %d on pid %d",
rc, tsk->pid);
break;
}
@@ -282,7 +301,6 @@ stap_utrace_detach_ops(struct utrace_engine_ops *ops)
{
struct task_struct *grp, *tsk;
struct utrace_attached_engine *engine;
- int rc = 0;
pid_t pid = 0;
// Notice we're not calling get_task_mm() in this loop. In
@@ -308,11 +326,12 @@ stap_utrace_detach_ops(struct utrace_engine_ops *ops)
continue;
#endif
- rc = stap_utrace_detach(tsk, ops);
- if (rc != 0)
- goto udo_err;
+ /* Notice we're purposefully ignoring errors from
+ * stap_utrace_detach(). Even if we got an error on
+ * this task, we need to keep detaching from other
+ * tasks. */
+ (void) stap_utrace_detach(tsk, ops);
} while_each_thread(grp, tsk);
-udo_err:
rcu_read_unlock();
debug_task_finder_report();
}
@@ -383,10 +402,10 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
/*
* __STP_TASK_BASE_EVENTS: base events for stap_task_finder_target's
- * without vm_callback's
+ * without map callback's
*
* __STP_TASK_VM_BASE_EVENTS: base events for
- * stap_task_finder_target's with vm_callback's
+ * stap_task_finder_target's with map callback's
*/
#define __STP_TASK_BASE_EVENTS (UTRACE_EVENT(DEATH))
@@ -403,8 +422,10 @@ __stp_get_mm_path(struct mm_struct *mm, char *buf, int buflen)
#define __STP_ATTACHED_TASK_EVENTS (__STP_TASK_BASE_EVENTS \
| UTRACE_EVENT(QUIESCE))
-#define __STP_ATTACHED_TASK_BASE_EVENTS(tgt) \
- ((tgt)->vm_events ? __STP_TASK_VM_BASE_EVENTS : __STP_TASK_BASE_EVENTS)
+#define __STP_ATTACHED_TASK_BASE_EVENTS(tgt) \
+ (((tgt)->mmap_events || (tgt)->munmap_events \
+ || (tgt)->mprotect_events) \
+ ? __STP_TASK_VM_BASE_EVENTS : __STP_TASK_BASE_EVENTS)
static int
__stp_utrace_attach(struct task_struct *tsk,
@@ -459,7 +480,7 @@ __stp_utrace_attach(struct task_struct *tsk,
* ref.
*/
rc = utrace_barrier(tsk, engine);
- if (rc != 0)
+ if (rc != -ESRCH && rc != -EALREADY)
_stp_error("utrace_barrier returned error %d on pid %d",
rc, (int)tsk->pid);
}
@@ -478,7 +499,7 @@ __stp_utrace_attach(struct task_struct *tsk,
}
}
- else
+ else if (rc != -ESRCH && rc != -EALREADY)
_stp_error("utrace_set_events2 returned error %d on pid %d",
rc, (int)tsk->pid);
utrace_engine_put(engine);
@@ -520,11 +541,113 @@ __stp_call_callbacks(struct stap_task_finder_target *tgt,
}
}
+static void
+__stp_call_mmap_callbacks(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk, char *path,
+ unsigned long addr, unsigned long length,
+ unsigned long offset, unsigned long vm_flags)
+{
+ struct list_head *cb_node;
+ int rc;
+
+ if (tgt == NULL || tsk == NULL)
+ return;
+
+#ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "pid %d, a/l/o/p/path 0x%lx 0x%lx 0x%lx %c%c%c%c %s\n",
+ tsk->pid, addr, length, offset,
+ vm_flags & VM_READ ? 'r' : '-',
+ vm_flags & VM_WRITE ? 'w' : '-',
+ vm_flags & VM_EXEC ? 'x' : '-',
+ vm_flags & VM_MAYSHARE ? 's' : 'p',
+ path);
+#endif
+ list_for_each(cb_node, &tgt->callback_list_head) {
+ struct stap_task_finder_target *cb_tgt;
+
+ cb_tgt = list_entry(cb_node, struct stap_task_finder_target,
+ callback_list);
+ if (cb_tgt == NULL || cb_tgt->mmap_callback == NULL)
+ continue;
+
+ rc = cb_tgt->mmap_callback(cb_tgt, tsk, path, addr, length,
+ offset, vm_flags);
+ if (rc != 0) {
+ _stp_error("mmap callback for %d failed: %d",
+ (int)tsk->pid, rc);
+ }
+ }
+}
+
+static void
+__stp_call_mmap_callbacks_with_vma(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ struct vm_area_struct *vma)
+{
+ char *mmpath_buf;
+ char *mmpath;
+ int rc;
+
+ // Allocate space for a path
+ mmpath_buf = _stp_kmalloc(PATH_MAX);
+ if (mmpath_buf == NULL) {
+ _stp_error("Unable to allocate space for path");
+ return;
+ }
+
+ // Grab the path associated with this vma.
+#ifdef STAPCONF_DPATH_PATH
+ mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, PATH_MAX);
+#else
+ mmpath = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt,
+ mmpath_buf, PATH_MAX);
+#endif
+ if (mmpath == NULL || IS_ERR(mmpath)) {
+ rc = -PTR_ERR(mmpath);
+ _stp_error("Unable to get path (error %d) for pid %d",
+ rc, (int)tsk->pid);
+ }
+ else {
+ __stp_call_mmap_callbacks(tgt, tsk, mmpath, vma->vm_start,
+ vma->vm_end - vma->vm_start,
+ (vma->vm_pgoff << PAGE_SHIFT),
+ vma->vm_flags);
+ }
+ _stp_kfree(mmpath_buf);
+}
+
+static inline void
+__stp_call_munmap_callbacks(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk, unsigned long addr,
+ unsigned long length)
+{
+ struct list_head *cb_node;
+ int rc;
+
+ if (tgt == NULL || tsk == NULL)
+ return;
+
+ list_for_each(cb_node, &tgt->callback_list_head) {
+ struct stap_task_finder_target *cb_tgt;
+
+ cb_tgt = list_entry(cb_node, struct stap_task_finder_target,
+ callback_list);
+ if (cb_tgt == NULL || cb_tgt->munmap_callback == NULL)
+ continue;
+
+ rc = cb_tgt->munmap_callback(cb_tgt, tsk, addr, length);
+ if (rc != 0) {
+ _stp_error("munmap callback for %d failed: %d",
+ (int)tsk->pid, rc);
+ }
+ }
+}
+
static inline void
-__stp_call_vm_callbacks(struct stap_task_finder_target *tgt,
- struct task_struct *tsk, int map_p, char *vm_path,
- unsigned long vm_start, unsigned long vm_end,
- unsigned long vm_pgoff)
+__stp_call_mprotect_callbacks(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk, unsigned long addr,
+ unsigned long length, int prot)
{
struct list_head *cb_node;
int rc;
@@ -537,13 +660,13 @@ __stp_call_vm_callbacks(struct stap_task_finder_target *tgt,
cb_tgt = list_entry(cb_node, struct stap_task_finder_target,
callback_list);
- if (cb_tgt == NULL || cb_tgt->vm_callback == NULL)
+ if (cb_tgt == NULL || cb_tgt->mprotect_callback == NULL)
continue;
- rc = cb_tgt->vm_callback(cb_tgt, tsk, map_p, vm_path,
- vm_start, vm_end, vm_pgoff);
+ rc = cb_tgt->mprotect_callback(cb_tgt, tsk, addr, length,
+ prot);
if (rc != 0) {
- _stp_error("vm callback for %d failed: %d",
+ _stp_error("mprotect callback for %d failed: %d",
(int)tsk->pid, rc);
}
}
@@ -853,11 +976,12 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
* a stale task pointer, if we have an engine ref.
*/
rc = utrace_barrier(tsk, engine);
- if (rc != 0)
+ if (rc == 0)
+ rc = utrace_set_events(tsk, engine,
+ __STP_ATTACHED_TASK_BASE_EVENTS(tgt));
+ else if (rc != -ESRCH && rc != -EALREADY)
_stp_error("utrace_barrier returned error %d on pid %d",
rc, (int)tsk->pid);
- rc = utrace_set_events(tsk, engine,
- __STP_ATTACHED_TASK_BASE_EVENTS(tgt));
}
if (rc != 0)
_stp_error("utrace_set_events returned error %d on pid %d",
@@ -869,16 +993,16 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
__stp_call_callbacks(tgt, tsk, 1, (tsk->pid == tsk->tgid));
/* If this is just a thread other than the thread group leader,
- don't bother inform vm_callback clients about its memory map,
+ don't bother inform map callback clients about its memory map,
since they will simply duplicate each other. */
- if (tgt->vm_events == 1 && tsk->tgid == tsk->pid) {
+ if (tgt->mmap_events == 1 && tsk->tgid == tsk->pid) {
struct mm_struct *mm;
char *mmpath_buf;
char *mmpath;
struct vm_area_struct *vma;
int rc;
- /* Call the vm_callback for every vma associated with
+ /* Call the mmap_callback for every vma associated with
* a file. */
mm = get_task_mm(tsk);
if (! mm)
@@ -905,12 +1029,13 @@ __stp_utrace_task_finder_target_quiesce(enum utrace_resume_action action,
mmpath_buf, PATH_MAX);
#endif
if (mmpath) {
- __stp_call_vm_callbacks(tgt, tsk, 1,
- mmpath,
- vma->vm_start,
- vma->vm_end,
- (vma->vm_pgoff
- << PAGE_SHIFT));
+ __stp_call_mmap_callbacks(tgt, tsk,
+ mmpath,
+ vma->vm_start,
+ vma->vm_end - vma->vm_start,
+ (vma->vm_pgoff
+ << PAGE_SHIFT),
+ vma->vm_flags);
}
else {
_stp_dbug(__FUNCTION__, __LINE__,
@@ -957,96 +1082,60 @@ __stp_utrace_task_finder_target_syscall_entry(enum utrace_resume_action action,
#endif
{
struct stap_task_finder_target *tgt = engine->data;
- unsigned long syscall_no;
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- unsigned long *arg0_addr, arg0;
+ long syscall_no;
+ unsigned long args[3] = { 0L };
int rc;
-#if defined(__ia64__)
- struct { unsigned long *unwaddr; } _c = {.unwaddr = NULL}, *c = &_c;
-#endif
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
debug_task_finder_detach();
return UTRACE_DETACH;
}
- if (tgt == NULL || tgt->vm_events == 0)
+ if (tgt == NULL)
return UTRACE_RESUME;
// See if syscall is one we're interested in.
//
// FIXME: do we need to handle mremap()?
- syscall_no = __stp_user_syscall_nr(regs);
+ syscall_no = syscall_get_nr(tsk, regs);
if (syscall_no != MMAP_SYSCALL_NO(tsk)
&& syscall_no != MMAP2_SYSCALL_NO(tsk)
&& syscall_no != MPROTECT_SYSCALL_NO(tsk)
&& syscall_no != MUNMAP_SYSCALL_NO(tsk))
return UTRACE_RESUME;
- __stp_tf_handler_start();
+ // The syscall is one we're interested in, but do we have a
+ // handler for it?
+ if (((syscall_no == MMAP_SYSCALL_NO(tsk)
+ || syscall_no == MMAP2_SYSCALL_NO(tsk)) && tgt->mmap_events == 0)
+ || (syscall_no == MPROTECT_SYSCALL_NO(tsk)
+ && tgt->mprotect_events == 0)
+ || (syscall_no == MUNMAP_SYSCALL_NO(tsk)
+ && tgt->munmap_events == 0))
+ return UTRACE_RESUME;
- // We need the first syscall argument to see what address
- // we're operating on.
- arg0_addr = __stp_user_syscall_arg(tsk, regs, 0);
- if ((rc = __stp_get_user(arg0, arg0_addr)) != 0) {
- _stp_error("couldn't read syscall arg 0 for pid %d: %d",
- tsk->pid, rc);
+ __stp_tf_handler_start();
+ if (syscall_no == MUNMAP_SYSCALL_NO(tsk)) {
+ // We need 2 arguments
+ syscall_get_arguments(tsk, regs, 0, 2, args);
}
- else if (arg0 != (unsigned long)NULL) {
- mm = get_task_mm(tsk);
- if (mm) {
- down_read(&mm->mmap_sem);
-
- // If we can find a matching vma associated
- // with a file, save off its details.
- vma = __stp_find_file_based_vma(mm, arg0);
- if (vma != NULL) {
- __stp_tf_add_vma(tsk, arg0, vma);
- }
-
- up_read(&mm->mmap_sem);
- mmput(mm);
- }
+ else if (syscall_no == MMAP_SYSCALL_NO(tsk)
+ || syscall_no == MMAP2_SYSCALL_NO(tsk)) {
+ // For mmap, we really just need the return value, so
+ // there is no need to save arguments
}
- __stp_tf_handler_end();
- return UTRACE_RESUME;
-}
-
-static void
-__stp_call_vm_callbacks_with_vma(struct stap_task_finder_target *tgt,
- struct task_struct *tsk,
- struct vm_area_struct *vma)
-{
- char *mmpath_buf;
- char *mmpath;
- int rc;
-
- // Allocate space for a path
- mmpath_buf = _stp_kmalloc(PATH_MAX);
- if (mmpath_buf == NULL) {
- _stp_error("Unable to allocate space for path");
- return;
+ else { // mprotect()
+ // We need 3 arguments
+ syscall_get_arguments(tsk, regs, 0, 3, args);
}
- // Grab the path associated with this vma.
-#ifdef STAPCONF_DPATH_PATH
- mmpath = d_path(&(vma->vm_file->f_path), mmpath_buf, PATH_MAX);
-#else
- mmpath = d_path(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt,
- mmpath_buf, PATH_MAX);
-#endif
- if (mmpath == NULL || IS_ERR(mmpath)) {
- rc = -PTR_ERR(mmpath);
- _stp_error("Unable to get path (error %d) for pid %d",
- rc, (int)tsk->pid);
- }
- else {
- __stp_call_vm_callbacks(tgt, tsk, 1, mmpath,
- vma->vm_start, vma->vm_end,
- (vma->vm_pgoff << PAGE_SHIFT));
- }
- _stp_kfree(mmpath_buf);
+ // Remember the syscall information
+ rc = __stp_tf_add_map(tsk, syscall_no, args[0], args[1], args[2]);
+ if (rc != 0)
+ _stp_error("__stp_tf_add_map returned error %d on pid %d",
+ rc, tsk->pid);
+ __stp_tf_handler_end();
+ return UTRACE_RESUME;
}
#ifdef UTRACE_ORIG_VERSION
@@ -1063,165 +1152,75 @@ __stp_utrace_task_finder_target_syscall_exit(enum utrace_resume_action action,
#endif
{
struct stap_task_finder_target *tgt = engine->data;
- unsigned long syscall_no;
- unsigned long *rv_addr, rv;
- unsigned long *arg0_addr, arg0;
- int rc;
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- struct __stp_tf_vma_entry *entry = NULL;
-#if defined(__ia64__)
- struct { unsigned long *unwaddr; } _c = {.unwaddr = NULL}, *c = &_c;
-#endif
+ unsigned long rv;
+ struct __stp_tf_map_entry *entry;
if (atomic_read(&__stp_task_finder_state) != __STP_TF_RUNNING) {
debug_task_finder_detach();
return UTRACE_DETACH;
}
- if (tgt == NULL || tgt->vm_events == 0)
+ if (tgt == NULL)
return UTRACE_RESUME;
- // See if syscall is one we're interested in.
- //
- // FIXME: do we need to handle mremap()?
- syscall_no = __stp_user_syscall_nr(regs);
- if (syscall_no != MMAP_SYSCALL_NO(tsk)
- && syscall_no != MMAP2_SYSCALL_NO(tsk)
- && syscall_no != MPROTECT_SYSCALL_NO(tsk)
- && syscall_no != MUNMAP_SYSCALL_NO(tsk))
+ // See if we can find saved syscall info. If we can, it must
+ // be one of the syscalls we are interested in (and we must
+ // have callbacks to call for it).
+ entry = __stp_tf_get_map_entry(tsk);
+ if (entry == NULL)
return UTRACE_RESUME;
// Get return value
- rv_addr = __stp_user_syscall_return_value(tsk, regs);
- if ((rc = __stp_get_user(rv, rv_addr)) != 0) {
- _stp_error("couldn't read syscall return value for pid %d: %d",
- tsk->pid, rc);
- return UTRACE_RESUME;
- }
-
- // We need the first syscall argument to see what address we
- // were operating on.
- arg0_addr = __stp_user_syscall_arg(tsk, regs, 0);
- if ((rc = __stp_get_user(arg0, arg0_addr)) != 0) {
- _stp_error("couldn't read syscall arg 0 for pid %d: %d",
- tsk->pid, rc);
- return UTRACE_RESUME;
- }
+ __stp_tf_handler_start();
+ rv = syscall_get_return_value(tsk, regs);
#ifdef DEBUG_TASK_FINDER_VMA
_stp_dbug(__FUNCTION__, __LINE__,
"tsk %d found %s(0x%lx), returned 0x%lx\n",
tsk->pid,
- ((syscall_no == MMAP_SYSCALL_NO(tsk)) ? "mmap"
- : ((syscall_no == MMAP2_SYSCALL_NO(tsk)) ? "mmap2"
- : ((syscall_no == MPROTECT_SYSCALL_NO(tsk)) ? "mprotect"
- : ((syscall_no == MUNMAP_SYSCALL_NO(tsk)) ? "munmap"
+ ((entry->syscall_no == MMAP_SYSCALL_NO(tsk)) ? "mmap"
+ : ((entry->syscall_no == MMAP2_SYSCALL_NO(tsk)) ? "mmap2"
+ : ((entry->syscall_no == MPROTECT_SYSCALL_NO(tsk))
+ ? "mprotect"
+ : ((entry->syscall_no == MUNMAP_SYSCALL_NO(tsk))
+ ? "munmap"
: "UNKNOWN")))),
- arg0, rv);
+ entry->arg0, rv);
#endif
- __stp_tf_handler_start();
- // Try to find the vma info we might have saved.
- if (arg0 != (unsigned long)NULL)
- entry = __stp_tf_get_vma_entry(tsk, arg0);
+ if (entry->syscall_no == MUNMAP_SYSCALL_NO(tsk)) {
+ // Call the callbacks
+ __stp_call_munmap_callbacks(tgt, tsk, entry->arg0, entry->arg1);
+ }
+ else if (entry->syscall_no == MMAP_SYSCALL_NO(tsk)
+ || entry->syscall_no == MMAP2_SYSCALL_NO(tsk)) {
+ struct mm_struct *mm;
- // If entry is NULL, this means we didn't find a file based
- // vma to store in the syscall_entry routine. This could mean
- // we just created a new vma.
- if (entry == NULL) {
mm = get_task_mm(tsk);
if (mm) {
+ struct vm_area_struct *vma;
+
down_read(&mm->mmap_sem);
vma = __stp_find_file_based_vma(mm, rv);
- if (vma != NULL) {
- __stp_call_vm_callbacks_with_vma(tgt, tsk, vma);
- }
- up_read(&mm->mmap_sem);
- mmput(mm);
- }
- }
- // If we found saved vma information, try to match it up with
- // what currently exists.
- else {
-#ifdef DEBUG_TASK_FINDER_VMA
- _stp_dbug(__FUNCTION__, __LINE__,
- "** found stored vma 0x%lx/0x%lx/0x%lx!\n",
- entry->vm_start, entry->vm_end, entry->vm_pgoff);
-#endif
- mm = get_task_mm(tsk);
- if (mm) {
- down_read(&mm->mmap_sem);
- vma = __stp_find_file_based_vma(mm, entry->vm_start);
-
- // We couldn't find the vma at all. The
- // original vma was deleted.
- if (vma == NULL) {
- // FIXME: We'll need to figure out to
- // retrieve the path of a deleted
- // vma.
-
- __stp_call_vm_callbacks(tgt, tsk, 0, NULL,
- entry->vm_start,
- entry->vm_end,
- (entry->vm_pgoff
- << PAGE_SHIFT));
- }
- // If nothing has changed, there is no
- // need to call the callback.
- else if (vma->vm_start == entry->vm_start
- && vma->vm_end == entry->vm_end
- && vma->vm_pgoff == entry->vm_pgoff) {
- // do nothing
+ // Call the callbacks
+ if (vma) {
+ __stp_call_mmap_callbacks_with_vma(tgt, tsk,
+ vma);
}
- // The original vma has been changed. It is
- // possible that calling mprotect (e.g.) split
- // up an existing vma into 2 or 3 new vma's
- // (assuming it protected a portion of the
- // original vma at the beginning, middle, or
- // end). Try to determine what happened.
- else {
- unsigned long tmp;
-
- // First report that the original vma
- // is gone.
- //
- // FIXME: We'll need to figure out to
- // retrieve the path of a deleted
- // vma.
- __stp_call_vm_callbacks(tgt, tsk, 0, NULL,
- entry->vm_start,
- entry->vm_end,
- (entry->vm_pgoff
- << PAGE_SHIFT));
-
- // Now find all the new vma's that
- // made up the original vma's address
- // space and call the callback on each
- // new vma.
- tmp = entry->vm_start;
- while (((vma = __stp_find_file_based_vma(mm,
- tmp))
- != NULL)
- && vma->vm_end <= entry->vm_end) {
- __stp_call_vm_callbacks_with_vma(tgt,
- tsk,
- vma);
- if (vma->vm_end >= entry->vm_end)
- break;
- tmp = vma->vm_end;
- }
- }
up_read(&mm->mmap_sem);
mmput(mm);
}
-
- // Cleanup by deleting the saved vma info.
- __stp_tf_remove_vma_entry(entry);
}
+ else { // mprotect
+ // Call the callbacks
+ __stp_call_mprotect_callbacks(tgt, tsk, entry->arg0,
+ entry->arg1, entry->arg2);
+ }
+
__stp_tf_handler_end();
+ __stp_tf_remove_map_entry(entry);
return UTRACE_RESUME;
}
@@ -1245,7 +1244,7 @@ stap_start_task_finder(void)
return ENOMEM;
}
- __stp_tf_vma_initialize();
+ __stp_tf_map_initialize();
atomic_set(&__stp_task_finder_state, __STP_TF_RUNNING);
@@ -1362,5 +1361,5 @@ stap_stop_task_finder(void)
debug_task_finder_report();
}
-
+#endif /* defined(CONFIG_UTRACE) */
#endif /* TASK_FINDER_C */
diff --git a/runtime/task_finder_map.c b/runtime/task_finder_map.c
new file mode 100644
index 00000000..b770dd0e
--- /dev/null
+++ b/runtime/task_finder_map.c
@@ -0,0 +1,191 @@
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/spinlock.h>
+
+// When handling mmap()/munmap()/mprotect() syscall tracing to notice
+// memory map changes, we need to cache syscall entry parameter values
+// for processing at syscall exit.
+
+// __stp_tf_map_lock protects the hash table.
+// Documentation/spinlocks.txt suggest we can be a bit more clever
+// if we guarantee that in interrupt context we only read, not write
+// the datastructures. We should never change the hash table or the
+// contents in interrupt context (which should only ever call
+// stap_find_map_map_info for getting stored info). So we might
+// want to look into that if this seems a bottleneck.
+static DEFINE_RWLOCK(__stp_tf_map_lock);
+
+#define __STP_TF_HASH_BITS 4
+#define __STP_TF_TABLE_SIZE (1 << __STP_TF_HASH_BITS)
+
+#ifndef TASK_FINDER_MAP_ENTRY_ITEMS
+#define TASK_FINDER_MAP_ENTRY_ITEMS 100
+#endif
+
+struct __stp_tf_map_entry {
+/* private: */
+ struct hlist_node hlist;
+ int usage;
+
+/* public: */
+ pid_t pid;
+ long syscall_no;
+ unsigned long arg0;
+ unsigned long arg1;
+ unsigned long arg2;
+};
+
+static struct __stp_tf_map_entry
+__stp_tf_map_free_list_items[TASK_FINDER_MAP_ENTRY_ITEMS];
+
+static struct hlist_head __stp_tf_map_free_list[1];
+
+static struct hlist_head __stp_tf_map_table[__STP_TF_TABLE_SIZE];
+
+// __stp_tf_map_initialize(): Initialize the free list. Grabs the
+// lock.
+static void
+__stp_tf_map_initialize(void)
+{
+ int i;
+ struct hlist_head *head = &__stp_tf_map_free_list[0];
+
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_map_lock, flags);
+ for (i = 0; i < TASK_FINDER_MAP_ENTRY_ITEMS; i++) {
+ hlist_add_head(&__stp_tf_map_free_list_items[i].hlist, head);
+ }
+ write_unlock_irqrestore(&__stp_tf_map_lock, flags);
+}
+
+
+// __stp_tf_map_get_free_entry(): Returns an entry from the free list
+// or NULL. The __stp_tf_map_lock must be write locked before calling this
+// function.
+static struct __stp_tf_map_entry *
+__stp_tf_map_get_free_entry(void)
+{
+ struct hlist_head *head = &__stp_tf_map_free_list[0];
+ struct hlist_node *node;
+ struct __stp_tf_map_entry *entry = NULL;
+
+ if (hlist_empty(head))
+ return NULL;
+ hlist_for_each_entry(entry, node, head, hlist) {
+ break;
+ }
+ if (entry != NULL)
+ hlist_del(&entry->hlist);
+ return entry;
+}
+
+
+// __stp_tf_map_put_free_entry(): Puts an entry back on the free
+// list. The __stp_tf_map_lock must be write locked before calling this
+// function.
+static void
+__stp_tf_map_put_free_entry(struct __stp_tf_map_entry *entry)
+{
+ struct hlist_head *head = &__stp_tf_map_free_list[0];
+ hlist_add_head(&entry->hlist, head);
+}
+
+
+// __stp_tf_map_hash(): Compute the map hash.
+static inline u32
+__stp_tf_map_hash(struct task_struct *tsk)
+{
+ return (jhash_1word(tsk->pid, 0) & (__STP_TF_TABLE_SIZE - 1));
+}
+
+
+// Get map_entry if the map is present in the map hash table.
+// Returns NULL if not present. Takes a read lock on __stp_tf_map_lock.
+static struct __stp_tf_map_entry *
+__stp_tf_get_map_entry(struct task_struct *tsk)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct __stp_tf_map_entry *entry;
+
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_map_lock, flags);
+ head = &__stp_tf_map_table[__stp_tf_map_hash(tsk)];
+ hlist_for_each_entry(entry, node, head, hlist) {
+ if (tsk->pid == entry->pid) {
+ read_unlock_irqrestore(&__stp_tf_map_lock, flags);
+ return entry;
+ }
+ }
+ read_unlock_irqrestore(&__stp_tf_map_lock, flags);
+ return NULL;
+}
+
+
+// Add the map info to the map hash table. Takes a write lock on
+// __stp_tf_map_lock.
+static int
+__stp_tf_add_map(struct task_struct *tsk, long syscall_no, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct __stp_tf_map_entry *entry;
+ unsigned long flags;
+
+ write_lock_irqsave(&__stp_tf_map_lock, flags);
+ head = &__stp_tf_map_table[__stp_tf_map_hash(tsk)];
+ hlist_for_each_entry(entry, node, head, hlist) {
+ // If we find an existing entry, just increment the
+ // usage count.
+ if (tsk->pid == entry->pid) {
+ entry->usage++;
+ write_unlock_irqrestore(&__stp_tf_map_lock, flags);
+ return 0;
+ }
+ }
+
+ // Get an element from the free list.
+ entry = __stp_tf_map_get_free_entry();
+ if (!entry) {
+ write_unlock_irqrestore(&__stp_tf_map_lock, flags);
+ return -ENOMEM;
+ }
+ entry->usage = 1;
+ entry->pid = tsk->pid;
+ entry->syscall_no = syscall_no;
+ entry->arg0 = arg0;
+ entry->arg1 = arg1;
+ entry->arg2 = arg2;
+ hlist_add_head(&entry->hlist, head);
+ write_unlock_irqrestore(&__stp_tf_map_lock, flags);
+ return 0;
+}
+
+
+// Remove the map entry from the map hash table. Takes a write lock on
+// __stp_tf_map_lock.
+static int
+__stp_tf_remove_map_entry(struct __stp_tf_map_entry *entry)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ int found = 0;
+
+ if (entry != NULL) {
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_map_lock, flags);
+
+ // Decrement the usage count.
+ entry->usage--;
+
+ // If the entry is unused, put it back on the free
+ // list.
+ if (entry->usage == 0) {
+ hlist_del(&entry->hlist);
+ __stp_tf_map_put_free_entry(entry);
+ }
+ write_unlock_irqrestore(&__stp_tf_map_lock, flags);
+ }
+ return 0;
+}
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index 4dce4be8..ed9c6f4f 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -1,13 +1,19 @@
#include <linux/list.h>
#include <linux/jhash.h>
-#include <linux/mutex.h>
+#include <linux/spinlock.h>
// When handling memcpy() syscall tracing to notice memory map
// changes, we need to cache memcpy() entry parameter values for
// processing at memcpy() exit.
-// __stp_tf_vma_mutex protects the hash table.
-static DEFINE_MUTEX(__stp_tf_vma_mutex);
+// __stp_tf_vma_lock protects the hash table.
+// Documentation/spinlocks.txt suggest we can be a bit more clever
+// if we guarantee that in interrupt context we only read, not write
+// the datastructures. We should never change the hash table or the
+// contents in interrupt context (which should only ever call
+// stap_find_vma_map_info for getting stored vma info). So we might
+// want to look into that if this seems a bottleneck.
+static DEFINE_RWLOCK(__stp_tf_vma_lock);
#define __STP_TF_HASH_BITS 4
#define __STP_TF_TABLE_SIZE (1 << __STP_TF_HASH_BITS)
@@ -25,6 +31,9 @@ struct __stp_tf_vma_entry {
unsigned long vm_end;
unsigned long vm_pgoff;
// Is that enough? Should we store a dcookie for vm_file?
+
+ // User data (possibly stp_module)
+ void *user;
};
static struct __stp_tf_vma_entry
@@ -37,23 +46,24 @@ static struct hlist_head __stp_tf_vma_table[__STP_TF_TABLE_SIZE];
static struct hlist_head __stp_tf_vma_map[__STP_TF_TABLE_SIZE];
// __stp_tf_vma_initialize(): Initialize the free list. Grabs the
-// mutex.
+// spinlock.
static void
__stp_tf_vma_initialize(void)
{
int i;
struct hlist_head *head = &__stp_tf_vma_free_list[0];
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
for (i = 0; i < TASK_FINDER_VMA_ENTRY_ITEMS; i++) {
hlist_add_head(&__stp_tf_vma_free_list_items[i].hlist, head);
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
}
// __stp_tf_vma_get_free_entry(): Returns an entry from the free list
-// or NULL. The __stp_tf_vma_mutex must be locked before calling this
+// or NULL. The __stp_tf_vma_lock must be write locked before calling this
// function.
static struct __stp_tf_vma_entry *
__stp_tf_vma_get_free_entry(void)
@@ -74,7 +84,7 @@ __stp_tf_vma_get_free_entry(void)
// __stp_tf_vma_put_free_entry(): Puts an entry back on the free
-// list. The __stp_tf_vma_mutex must be locked before calling this
+// list. The __stp_tf_vma_lock must be write locked before calling this
// function.
static void
__stp_tf_vma_put_free_entry(struct __stp_tf_vma_entry *entry)
@@ -98,7 +108,7 @@ __stp_tf_vma_hash(struct task_struct *tsk, unsigned long addr)
// Get vma_entry if the vma is present in the vma hash table.
-// Returns NULL if not present.
+// Returns NULL if not present. Takes a read lock on __stp_tf_vma_lock.
static struct __stp_tf_vma_entry *
__stp_tf_get_vma_entry(struct task_struct *tsk, unsigned long addr)
{
@@ -106,20 +116,22 @@ __stp_tf_get_vma_entry(struct task_struct *tsk, unsigned long addr)
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_vma_lock, flags);
head = &__stp_tf_vma_table[__stp_tf_vma_hash(tsk, addr)];
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
&& addr == entry->addr) {
- mutex_unlock(&__stp_tf_vma_mutex);
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return entry;
}
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return NULL;
}
// Add the vma info to the vma hash table.
+// Takes a write lock on __stp_tf_vma_lock.
static int
__stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
struct vm_area_struct *vma)
@@ -128,7 +140,8 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
head = &__stp_tf_vma_table[__stp_tf_vma_hash(tsk, addr)];
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
@@ -138,7 +151,7 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
"vma (pid: %d, vm_start: 0x%lx) present?\n",
tsk->pid, vma->vm_start);
#endif
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -EBUSY; /* Already there */
}
}
@@ -146,7 +159,7 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
// Get an element from the free list.
entry = __stp_tf_vma_get_free_entry();
if (!entry) {
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -ENOMEM;
}
entry->pid = tsk->pid;
@@ -155,11 +168,12 @@ __stp_tf_add_vma(struct task_struct *tsk, unsigned long addr,
entry->vm_end = vma->vm_end;
entry->vm_pgoff = vma->vm_pgoff;
hlist_add_head(&entry->hlist, head);
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
// Remove the vma entry from the vma hash table.
+// Takes a write lock on __stp_tf_vma_lock.
static int
__stp_tf_remove_vma_entry(struct __stp_tf_vma_entry *entry)
{
@@ -168,10 +182,11 @@ __stp_tf_remove_vma_entry(struct __stp_tf_vma_entry *entry)
int found = 0;
if (entry != NULL) {
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
hlist_del(&entry->hlist);
__stp_tf_vma_put_free_entry(entry);
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
}
return 0;
}
@@ -186,7 +201,7 @@ __stp_tf_vma_map_hash(struct task_struct *tsk)
}
// Get vma_entry if the vma is present in the vma map hash table.
-// Returns NULL if not present. The __stp_tf_vma_mutex must be locked
+// Returns NULL if not present. The __stp_tf_vma_lock must be read locked
// before calling this function.
static struct __stp_tf_vma_entry *
__stp_tf_get_vma_map_entry_internal(struct task_struct *tsk,
@@ -200,7 +215,6 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk,
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
&& vm_start == entry->addr) {
- mutex_unlock(&__stp_tf_vma_mutex);
return entry;
}
}
@@ -211,13 +225,17 @@ __stp_tf_get_vma_map_entry_internal(struct task_struct *tsk,
// Add the vma info to the vma map hash table.
static int
stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
- unsigned long vm_end, unsigned long vm_pgoff)
+ unsigned long vm_end, unsigned long vm_pgoff,
+ void *user)
{
struct hlist_head *head;
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ // Take a write lock, since we are most likely going to write
+ // after reading.
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
entry = __stp_tf_get_vma_map_entry_internal(tsk, vm_start);
if (entry != NULL) {
#if 0
@@ -225,14 +243,14 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
"vma (pid: %d, vm_start: 0x%lx) present?\n",
tsk->pid, entry->vm_start);
#endif
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -EBUSY; /* Already there */
}
// Get an element from the free list.
entry = __stp_tf_vma_get_free_entry();
if (!entry) {
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return -ENOMEM;
}
@@ -242,10 +260,11 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
entry->vm_start = vm_start;
entry->vm_end = vm_end;
entry->vm_pgoff = vm_pgoff;
+ entry->user = user;
head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
hlist_add_head(&entry->hlist, head);
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
@@ -259,23 +278,26 @@ stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
- mutex_lock(&__stp_tf_vma_mutex);
+ // Take a write lock since we are most likely going to delete
+ // after reading.
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
entry = __stp_tf_get_vma_map_entry_internal(tsk, vm_start);
if (entry != NULL) {
hlist_del(&entry->hlist);
__stp_tf_vma_put_free_entry(entry);
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return 0;
}
// Finds vma info if the vma is present in the vma map hash table.
-// Returns ESRCH if not present. The __stp_tf_vma_mutex must *not* be
+// Returns ESRCH if not present. The __stp_tf_vma_lock must *not* be
// locked before calling this function.
static int
stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
unsigned long *vm_start, unsigned long *vm_end,
- unsigned long *vm_pgoff)
+ unsigned long *vm_pgoff, void **user)
{
struct hlist_head *head;
struct hlist_node *node;
@@ -283,7 +305,8 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
struct __stp_tf_vma_entry *found_entry = NULL;
int rc = ESRCH;
- mutex_lock(&__stp_tf_vma_mutex);
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_vma_lock, flags);
head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
hlist_for_each_entry(entry, node, head, hlist) {
if (tsk->pid == entry->pid
@@ -300,8 +323,10 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
*vm_end = found_entry->vm_end;
if (vm_pgoff != NULL)
*vm_pgoff = found_entry->vm_pgoff;
+ if (user != NULL)
+ *user = found_entry->user;
rc = 0;
}
- mutex_unlock(&__stp_tf_vma_mutex);
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return rc;
}
diff --git a/runtime/transport/control.c b/runtime/transport/control.c
index 4e07a0a7..a1624152 100644
--- a/runtime/transport/control.c
+++ b/runtime/transport/control.c
@@ -18,6 +18,8 @@ static _stp_mempool_t *_stp_pool_q;
static struct list_head _stp_ctl_ready_q;
static DEFINE_SPINLOCK(_stp_ctl_ready_lock);
+static void _stp_cleanup_and_exit(int send_exit);
+
static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
u32 type;
@@ -51,7 +53,7 @@ static ssize_t _stp_ctl_write_cmd(struct file *file, const char __user *buf, siz
}
break;
case STP_EXIT:
- _stp_exit_flag = 1;
+ _stp_cleanup_and_exit(1);
break;
case STP_BULK:
#ifdef STP_BULKMODE
@@ -98,6 +100,9 @@ static void _stp_ctl_write_dbug(int type, void *data, int len)
case STP_TRANSPORT:
_dbug("sending STP_TRANSPORT\n");
break;
+ case STP_REQUEST_EXIT:
+ _dbug("sending STP_REQUEST_EXIT\n");
+ break;
default:
_dbug("ERROR: unknown message type: %d\n", type);
break;
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index 3d0453bf..792ea815 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -148,6 +148,18 @@ static void _stp_cleanup_and_exit(int send_exit)
}
}
+static void _stp_request_exit(void)
+{
+ static int called = 0;
+ if (!called) {
+ /* we only want to do this once */
+ called = 1;
+ dbug_trans(1, "ctl_send STP_REQUEST_EXIT\n");
+ _stp_ctl_send(STP_REQUEST_EXIT, NULL, 0);
+ dbug_trans(1, "done with ctl_send STP_REQUEST_EXIT\n");
+ }
+}
+
/*
* Called when stapio closes the control channel.
*/
@@ -202,7 +214,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_probes_started))
- _stp_cleanup_and_exit(1);
+ _stp_request_exit();
if (likely(_stp_ctl_attached))
queue_delayed_work(_stp_wq, &_stp_work, STP_WORK_TIMER);
}
diff --git a/runtime/transport/transport_msgs.h b/runtime/transport/transport_msgs.h
index 0d6853f7..aa50051c 100644
--- a/runtime/transport/transport_msgs.h
+++ b/runtime/transport/transport_msgs.h
@@ -21,12 +21,12 @@ struct _stp_trace {
enum
{
STP_START,
- STP_EXIT,
+ STP_EXIT,
STP_OOB_DATA,
STP_SYSTEM,
STP_TRANSPORT,
STP_CONNECT,
- STP_DISCONNECT,
+ STP_DISCONNECT,
STP_BULK,
STP_READY,
STP_RELOCATION,
@@ -34,6 +34,7 @@ enum
STP_BUF_INFO,
STP_SUBBUFS_CONSUMED,
STP_REALTIME_DATA,
+ STP_REQUEST_EXIT,
STP_MAX_CMD
};
@@ -52,6 +53,7 @@ static const char *_stp_command_name[] = {
"STP_BUF_INFO",
"STP_SUBBUFS_CONSUMED",
"STP_REALTIME_DATA",
+ "STP_REQUEST_EXIT",
};
#endif /* DEBUG_TRANS */
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 9c704e28..aacd56f1 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -345,7 +345,7 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s
state->label = NULL;
return 1;
}
- if (state->stackDepth >= MAX_STACK_DEPTH)
+ if (state->stackDepth >= STP_MAX_STACK_DEPTH)
return 0;
state->stack[state->stackDepth++] = ptr.p8;
break;
@@ -435,12 +435,18 @@ adjustStartLoc (unsigned long startLoc,
struct _stp_module *m,
struct _stp_section *s)
{
- if (startLoc && (strcmp (m->name, "kernel") != 0))
- {
- startLoc = _stp_module_relocate (m->name, s->name,
- startLoc);
- startLoc -= m->dwarf_module_base;
- }
+ /* XXX - some, or all, of this should really be done by
+ _stp_module_relocate. */
+ if (startLoc == 0
+ || strcmp (m->name, "kernel") == 0
+ || strcmp (s->name, ".absolute") == 0)
+ return startLoc;
+
+ if (strcmp (s->name, ".dynamic") == 0)
+ return startLoc + s->addr;
+
+ startLoc = _stp_module_relocate (m->name, s->name, startLoc);
+ startLoc -= m->dwarf_module_base;
return startLoc;
}
@@ -562,7 +568,7 @@ static char *_stp_eh_enc_name(signed type)
/* 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. */
-static int unwind(struct unwind_frame_info *frame)
+static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
const u32 *fde, *cie = NULL;
@@ -581,7 +587,7 @@ static int unwind(struct unwind_frame_info *frame)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = _stp_mod_sec_lookup (pc, &s);
+ m = _stp_mod_sec_lookup (pc, tsk, &s);
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h
index 78a4bfef..3b6d0de0 100644
--- a/runtime/unwind/unwind.h
+++ b/runtime/unwind/unwind.h
@@ -23,7 +23,7 @@
#error "Unsupported dwarf unwind architecture"
#endif
-#define MAX_STACK_DEPTH 8
+#define STP_MAX_STACK_DEPTH 8
#ifndef BUILD_BUG_ON_ZERO
#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
@@ -135,7 +135,7 @@ struct unwind_state {
unsigned stackDepth:8;
unsigned version:8;
const u8 *label;
- const u8 *stack[MAX_STACK_DEPTH];
+ const u8 *stack[STP_MAX_STACK_DEPTH];
};
static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
diff --git a/runtime/uprobes/.gitignore b/runtime/uprobes/.gitignore
new file mode 100644
index 00000000..c8172c41
--- /dev/null
+++ b/runtime/uprobes/.gitignore
@@ -0,0 +1,7 @@
+/*.o
+/*.cmd
+/.tmp_versions
+/Module.*
+/modules.order
+/uprobes.ko
+/uprobes.mod.c
diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c
index 9dfb82b9..27e923b8 100644
--- a/runtime/uprobes/uprobes.c
+++ b/runtime/uprobes/uprobes.c
@@ -1049,8 +1049,7 @@ fail_tsk:
}
EXPORT_SYMBOL_GPL(register_uprobe);
-/* See Documentation/uprobes.txt. */
-void unregister_uprobe(struct uprobe *u)
+void __unregister_uprobe(struct uprobe *u, bool remove_bkpt)
{
struct task_struct *p;
struct uprobe_process *uproc;
@@ -1104,10 +1103,13 @@ void unregister_uprobe(struct uprobe *u)
if (!list_empty(&ppt->uprobe_list))
goto done;
- /*
- * The last uprobe at ppt's probepoint is being unregistered.
- * Queue the breakpoint for removal.
- */
+ /* The last uprobe at ppt's probepoint is being unregistered. */
+ if (!remove_bkpt) {
+ uprobe_free_probept(ppt);
+ goto done;
+ }
+
+ /* Queue the breakpoint for removal. */
ppt->state = UPROBE_REMOVING;
list_add_tail(&ppt->pd_node, &uproc->pending_uprobes);
@@ -1132,8 +1134,20 @@ done:
up_write(&uproc->rwsem);
uprobe_put_process(uproc);
}
+
+/* See Documentation/uprobes.txt. */
+void unregister_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, true);
+}
EXPORT_SYMBOL_GPL(unregister_uprobe);
+void unmap_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, false);
+}
+EXPORT_SYMBOL_GPL(unmap_uprobe);
+
/* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */
static struct task_struct *find_surviving_thread(struct uprobe_process *uproc)
{
@@ -2540,6 +2554,14 @@ void unregister_uretprobe(struct uretprobe *rp)
}
EXPORT_SYMBOL_GPL(unregister_uretprobe);
+void unmap_uretprobe(struct uretprobe *rp)
+{
+ if (!rp)
+ return;
+ unmap_uprobe(&rp->u);
+}
+EXPORT_SYMBOL_GPL(unmap_uretprobe);
+
/*
* uproc->ssol_area has been successfully set up. Establish the
* uretprobe trampoline in slot 0.
diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h
index 0266cb7d..d542420d 100644
--- a/runtime/uprobes/uprobes.h
+++ b/runtime/uprobes/uprobes.h
@@ -35,6 +35,9 @@
#include <linux/types.h>
#include <linux/list.h>
+/* Version 2 includes unmap_u[ret]probe(). */
+#define UPROBES_API_VERSION 2
+
struct pt_regs;
enum uprobe_type {
@@ -89,6 +92,9 @@ extern void unregister_uprobe(struct uprobe *u);
/* For runtime, assume uprobes support includes uretprobes. */
extern int register_uretprobe(struct uretprobe *rp);
extern void unregister_uretprobe(struct uretprobe *rp);
+/* For PRs 9940, 6852... */
+extern void unmap_uprobe(struct uprobe *u);
+extern void unmap_uretprobe(struct uretprobe *rp);
#ifdef UPROBES_IMPLEMENTATION
diff --git a/runtime/uprobes/uprobes_i386.c b/runtime/uprobes/uprobes_i386.c
index ffa088ed..008f32de 100644
--- a/runtime/uprobes/uprobes_i386.c
+++ b/runtime/uprobes/uprobes_i386.c
@@ -44,7 +44,7 @@
W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1), /* 90 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -58,22 +58,22 @@
static const unsigned long good_2byte_insns[256 / 32] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* ------------------------------- */
- W(0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 00 */
- W(0x10, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 10 */
- W(0x20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 20 */
- W(0x30, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 30 */
- W(0x40, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 40 */
- W(0x50, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 50 */
- W(0x60, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* 60 */
- W(0x70, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* 70 */
+ W(0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1)| /* 00 */
+ W(0x10, 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1), /* 10 */
+ W(0x20, 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1)| /* 20 */
+ W(0x30, 0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0), /* 30 */
+ W(0x40, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 40 */
+ W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 50 */
+ W(0x60, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 60 */
+ W(0x70, 1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1), /* 70 */
W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 90 */
W(0xa0, 1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1), /* b0 */
- W(0xc0, 1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1)| /* c0 */
- W(0xd0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), /* d0 */
- W(0xe0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)| /* e0 */
- W(0xf0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0) /* f0 */
+ W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* c0 */
+ W(0xd0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* d0 */
+ W(0xe0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* e0 */
+ W(0xf0, 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0) /* f0 */
/* ------------------------------- */
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
};
@@ -114,7 +114,6 @@
* 26, 2e, 36, 3e, - es:, cs:, ss:, ds: segment prefixes --
* but 64 and 65 (fs: and gs:) seems to be used, so we support them.
* 67 - addr16 prefix
- * 9b - wait/fwait
* ce - into
* f0 - lock prefix
* f2, f3 - repnz, repz prefixes
@@ -302,9 +301,20 @@ unsigned long arch_hijack_uret_addr(unsigned long trampoline_address,
return orig_ret_addr;
}
+/*
+ * On x86_32, if a function returns a struct or union, the return
+ * value is copied into an area created by the caller. The address
+ * of this area is passed on the stack as a "hidden" first argument.
+ * When such a function returns, it uses a "ret $4" instruction to pop
+ * not only the return address but also the hidden arg. To accommodate
+ * such functions, we add 4 bytes of slop when predicting the return
+ * address. See PR #10078.
+ */
+#define STRUCT_RETURN_SLOP 4
+
static
unsigned long arch_predict_sp_at_ret(struct pt_regs *regs,
struct task_struct *tsk)
{
- return (unsigned long) (regs->esp + 4);
+ return (unsigned long) (regs->esp + 4 + STRUCT_RETURN_SLOP);
}
diff --git a/runtime/uprobes/uprobes_x86.c b/runtime/uprobes/uprobes_x86.c
index e3bdf8ff..93331715 100644
--- a/runtime/uprobes/uprobes_x86.c
+++ b/runtime/uprobes/uprobes_x86.c
@@ -45,8 +45,8 @@ static const unsigned long long good_insns_64[256 / 64] = {
W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */
W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
- W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */
+ W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -71,7 +71,7 @@ static const unsigned long long good_insns_32[256 / 64] = {
W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -119,7 +119,7 @@ static const unsigned long long good_2byte_insns[256 / 64] = {
* 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2
*
* invalid opcodes in 64-bit mode:
- * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, c4-c5, d4-d5
+ * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5
*
* 63 - we support this opcode in x86_64 but not in i386.
* opcodes we may need to refine support for:
@@ -141,7 +141,6 @@ static const unsigned long long good_2byte_insns[256 / 64] = {
* 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes --
* but 64 and 65 (fs: and gs:) seems to be used, so we support them.
* 67 - addr16 prefix
- * 9b - wait/fwait
* ce - into
* f0 - lock prefix
*/
@@ -717,12 +716,23 @@ unsigned long arch_hijack_uret_addr(unsigned long trampoline_address,
return orig_ret_addr;
}
+/*
+ * On x86_32, if a function returns a struct or union, the return
+ * value is copied into an area created by the caller. The address
+ * of this area is passed on the stack as a "hidden" first argument.
+ * When such a function returns, it uses a "ret $4" instruction to pop
+ * not only the return address but also the hidden arg. To accommodate
+ * such functions, we add 4 bytes of slop when predicting the return
+ * address. See PR #10078.
+ */
+#define STRUCT_RETURN_SLOP 4
+
static
unsigned long arch_predict_sp_at_ret(struct pt_regs *regs,
struct task_struct *tsk)
{
if (test_tsk_thread_flag(tsk, TIF_IA32))
- return (unsigned long) (REGS_SP + 4);
+ return (unsigned long) (REGS_SP + 4 + STRUCT_RETURN_SLOP);
else
return (unsigned long) (REGS_SP + 8);
}
diff --git a/runtime/uprobes/uprobes_x86_64.c b/runtime/uprobes/uprobes_x86_64.c
index 8cf36623..56ebe2e1 100644
--- a/runtime/uprobes/uprobes_x86_64.c
+++ b/runtime/uprobes/uprobes_x86_64.c
@@ -45,8 +45,8 @@ static const unsigned long good_insns_64[256 / 64] = {
W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */
W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
- W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */
+ W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -71,7 +71,7 @@ static const unsigned long good_insns_32[256 / 64] = {
W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -141,7 +141,6 @@ static const unsigned long good_2byte_insns[256 / 64] = {
* 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes --
* but 64 and 65 (fs: and gs:) seems to be used, so we support them.
* 67 - addr16 prefix
- * 9b - wait/fwait
* ce - into
* f0 - lock prefix
*/
diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c
index af187fc9..07ad3984 100644
--- a/runtime/uprobes2/uprobes.c
+++ b/runtime/uprobes2/uprobes.c
@@ -29,6 +29,12 @@
#include <linux/utrace.h>
#include <linux/regset.h>
#define UPROBES_IMPLEMENTATION 1
+
+/* PR9974: Adapt to struct renaming. */
+#ifdef UTRACE_API_VERSION
+#define utrace_attached_engine utrace_engine
+#endif
+
#include "uprobes.h"
#include <linux/tracehook.h>
#include <linux/mm.h>
@@ -949,10 +955,15 @@ static int defer_registration(struct uprobe *u, int regflag,
*/
static struct pid *uprobe_get_tg_leader(pid_t p)
{
- struct pid *pid;
+ struct pid *pid = NULL;
rcu_read_lock();
- pid = find_vpid(p);
+ /*
+ * We need this check because unmap_u[ret]probe() can be called
+ * from a report_death callback, where current->proxy is NULL.
+ */
+ if (current->nsproxy)
+ pid = find_vpid(p);
if (pid) {
struct task_struct *t = pid_task(pid, PIDTYPE_PID);
if (t)
@@ -1132,8 +1143,7 @@ fail_tsk:
}
EXPORT_SYMBOL_GPL(register_uprobe);
-/* See Documentation/uprobes.txt. */
-void unregister_uprobe(struct uprobe *u)
+void __unregister_uprobe(struct uprobe *u, bool remove_bkpt)
{
struct pid *p;
struct uprobe_process *uproc;
@@ -1187,10 +1197,13 @@ void unregister_uprobe(struct uprobe *u)
if (!list_empty(&ppt->uprobe_list))
goto done;
- /*
- * The last uprobe at ppt's probepoint is being unregistered.
- * Queue the breakpoint for removal.
- */
+ /* The last uprobe at ppt's probepoint is being unregistered. */
+ if (!remove_bkpt) {
+ uprobe_free_probept(ppt);
+ goto done;
+ }
+
+ /* Queue the breakpoint for removal. */
ppt->state = UPROBE_REMOVING;
list_add_tail(&ppt->pd_node, &uproc->pending_uprobes);
@@ -1215,8 +1228,20 @@ done:
up_write(&uproc->rwsem);
uprobe_put_process(uproc, false);
}
+
+/* See Documentation/uprobes.txt. */
+void unregister_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, true);
+}
EXPORT_SYMBOL_GPL(unregister_uprobe);
+void unmap_uprobe(struct uprobe *u)
+{
+ __unregister_uprobe(u, false);
+}
+EXPORT_SYMBOL_GPL(unmap_uprobe);
+
/* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */
static struct task_struct *find_surviving_thread(struct uprobe_process *uproc)
{
@@ -2214,7 +2239,8 @@ static u32 uprobe_report_exit(enum utrace_resume_action action,
}
}
up_read(&uproc->rwsem);
- if (utask->state == UPTASK_TRAMPOLINE_HIT)
+ if (utask->state == UPTASK_TRAMPOLINE_HIT ||
+ utask->state == UPTASK_BP_HIT)
uprobe_decref_process(uproc);
}
@@ -2712,6 +2738,14 @@ void unregister_uretprobe(struct uretprobe *rp)
}
EXPORT_SYMBOL_GPL(unregister_uretprobe);
+void unmap_uretprobe(struct uretprobe *rp)
+{
+ if (!rp)
+ return;
+ unmap_uprobe(&rp->u);
+}
+EXPORT_SYMBOL_GPL(unmap_uretprobe);
+
/*
* uproc->ssol_area has been successfully set up. Establish the
* uretprobe trampoline in the next available slot following the
diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h
index 11d01f5c..ae0692f0 100644
--- a/runtime/uprobes2/uprobes.h
+++ b/runtime/uprobes2/uprobes.h
@@ -23,6 +23,14 @@
#include <linux/types.h>
#include <linux/list.h>
+/* Adapt to struct renaming. */
+#ifdef UTRACE_API_VERSION
+#define utrace_attached_engine utrace_engine
+#endif
+
+/* Version 2 includes unmap_u[ret]probe(). */
+#define UPROBES_API_VERSION 2
+
struct pt_regs;
enum uprobe_type {
@@ -77,6 +85,9 @@ extern void unregister_uprobe(struct uprobe *u);
/* For runtime, assume uprobes support includes uretprobes. */
extern int register_uretprobe(struct uretprobe *rp);
extern void unregister_uretprobe(struct uretprobe *rp);
+/* For PRs 9940, 6852... */
+extern void unmap_uprobe(struct uprobe *u);
+extern void unmap_uretprobe(struct uretprobe *rp);
#ifdef UPROBES_IMPLEMENTATION
diff --git a/runtime/uprobes2/uprobes_x86.c b/runtime/uprobes2/uprobes_x86.c
index effb7444..8c80293d 100644
--- a/runtime/uprobes2/uprobes_x86.c
+++ b/runtime/uprobes2/uprobes_x86.c
@@ -50,8 +50,8 @@ static const u64 good_insns_64[256 / 64] = {
W(0x50, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 50 */
W(0x60, 0,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
- W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */
+ W(0x80, 1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -76,7 +76,7 @@ static const u64 good_insns_32[256 / 64] = {
W(0x60, 1,1,1,0,1,1,0,0,1,1,1,1,0,0,0,0)| /* 60 */
W(0x70, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* 70 */
W(0x80, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 80 */
- W(0x90, 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)| /* 90 */
+ W(0x90, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* 90 */
W(0xa0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)| /* a0 */
W(0xb0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), /* b0 */
W(0xc0, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0)| /* c0 */
@@ -124,7 +124,7 @@ static const u64 good_2byte_insns[256 / 64] = {
* 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2
*
* invalid opcodes in 64-bit mode:
- * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, c4-c5, d4-d5
+ * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5
*
* 63 - we support this opcode in x86_64 but not in i386.
* opcodes we may need to refine support for:
@@ -146,7 +146,6 @@ static const u64 good_2byte_insns[256 / 64] = {
* 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes --
* but 64 and 65 (fs: and gs:) seem to be used, so we support them
* 67 - addr16 prefix
- * 9b - wait/fwait
* ce - into
* f0 - lock prefix
*/
diff --git a/runtime/uprobes2/uprobes_x86.h b/runtime/uprobes2/uprobes_x86.h
index ca3f4873..a07fa0d3 100644
--- a/runtime/uprobes2/uprobes_x86.h
+++ b/runtime/uprobes2/uprobes_x86.h
@@ -93,11 +93,22 @@ static inline unsigned long arch_get_cur_sp(struct pt_regs *regs)
return (unsigned long) regs->sp;
}
+/*
+ * On x86_32, if a function returns a struct or union, the return
+ * value is copied into an area created by the caller. The address
+ * of this area is passed on the stack as a "hidden" first argument.
+ * When such a function returns, it uses a "ret $4" instruction to pop
+ * not only the return address but also the hidden arg. To accommodate
+ * such functions, we add 4 bytes of slop when predicting the return
+ * address. See PR #10078.
+ */
+#define STRUCT_RETURN_SLOP 4
+
static inline unsigned long arch_predict_sp_at_ret(struct pt_regs *regs,
struct task_struct *tsk)
{
if (test_tsk_thread_flag(tsk, TIF_IA32))
- return (unsigned long) (regs->sp + 4);
+ return (unsigned long) (regs->sp + 4 + STRUCT_RETURN_SLOP);
else
return (unsigned long) (regs->sp + 8);
}
diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h
index 00b841d2..5521a5c2 100644
--- a/runtime/utrace_compatibility.h
+++ b/runtime/utrace_compatibility.h
@@ -1,6 +1,6 @@
/*
* utrace compatibility defines and inlines
- * Copyright (C) 2008 Red Hat Inc.
+ * Copyright (C) 2008-2009 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
@@ -13,6 +13,11 @@
#include <linux/utrace.h>
+/* PR9974: Adapt to struct renaming. */
+#ifdef UTRACE_API_VERSION
+#define utrace_attached_engine utrace_engine
+#endif
+
#ifdef UTRACE_ACTION_RESUME
/*
@@ -28,6 +33,8 @@ enum utrace_resume_action {
UTRACE_STOP = UTRACE_ACTION_QUIESCE,
UTRACE_RESUME = UTRACE_ACTION_RESUME,
UTRACE_DETACH = UTRACE_ACTION_DETACH,
+ UTRACE_SINGLESTEP = UTRACE_ACTION_SINGLESTEP,
+ UTRACE_BLOCKSTEP = UTRACE_ACTION_BLOCKSTEP,
};
static inline struct utrace_attached_engine *
@@ -48,6 +55,11 @@ utrace_control(struct task_struct *target,
case UTRACE_STOP:
return utrace_set_flags(target, engine,
(engine->flags | UTRACE_ACTION_QUIESCE));
+ case UTRACE_SINGLESTEP:
+ case UTRACE_BLOCKSTEP:
+ return utrace_set_flags(target, engine,
+ engine->flags | action);
+
default:
return -EINVAL;
}
diff --git a/runtime/vsprintf.c b/runtime/vsprintf.c
index bd58d760..23810e75 100644
--- a/runtime/vsprintf.c
+++ b/runtime/vsprintf.c
@@ -12,6 +12,9 @@
#ifndef _VSPRINTF_C_
#define _VSPRINTF_C_
+//forward declaration for _stp_vsnprintf
+static void * _stp_reserve_bytes (int);
+
static int skip_atoi(const char **s)
{
int i=0;
@@ -22,6 +25,10 @@ static int skip_atoi(const char **s)
enum print_flag {STP_ZEROPAD=1, STP_SIGN=2, STP_PLUS=4, STP_SPACE=8, STP_LEFT=16, STP_SPECIAL=32, STP_LARGE=64};
+/*
+ * Changes to number() will require a corresponding change to number_size below,
+ * to ensure proper buffer allocation for _stp_printf.
+ */
static char * number(char * buf, char * end, uint64_t num, int base, int size, int precision, enum print_flag type)
{
char c,sign,tmp[66];
@@ -115,6 +122,85 @@ static char * number(char * buf, char * end, uint64_t num, int base, int size, i
return buf;
}
+/*
+ * Calculates the number of bytes required to print the paramater num. A change to
+ * number() requires a corresponding change here, and vice versa, to ensure the
+ * calculated size and printed size match.
+ */
+static int number_size(uint64_t num, int base, int size, int precision, enum print_flag type) {
+ char c,sign,tmp[66];
+ const char *digits;
+ static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ int i, num_bytes = 0;
+
+ digits = (type & STP_LARGE) ? large_digits : small_digits;
+ if (type & STP_LEFT)
+ type &= ~STP_ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & STP_ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & STP_SIGN) {
+ if ((int64_t) num < 0) {
+ sign = '-';
+ num = - (int64_t) num;
+ size--;
+ } else if (type & STP_PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & STP_SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & STP_SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++]='0';
+ else while (num != 0)
+ tmp[i++] = digits[do_div(num,base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type&(STP_ZEROPAD+STP_LEFT))) {
+ while(size-->0) {
+ num_bytes++;
+ }
+ }
+ if (sign) {
+ num_bytes++;
+ }
+ if (type & STP_SPECIAL) {
+ if (base==8) {
+ num_bytes++;
+ } else if (base==16) {
+ num_bytes+=2;
+ }
+ }
+ if (!(type & STP_LEFT)) {
+ while (size-- > 0) {
+ num_bytes++;
+ }
+ }
+ while (i < precision--) {
+ num_bytes++;
+ }
+ while (i-- > 0) {
+ num_bytes++;
+ }
+ while (size-- > 0) {
+ num_bytes++;
+ }
+ return num_bytes;
+
+}
+
static int check_binary_precision (int precision) {
/* precision can be unspecified (-1) or one of 1, 2, 4 or 8. */
switch (precision) {
@@ -148,9 +234,260 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
if (unlikely((int) size < 0))
return 0;
- str = buf;
- end = buf + size - 1;
+ /*
+ * buf will be NULL when this function is called from _stp_printf.
+ * This branch calculates the exact size print buffer required for
+ * the string and allocates it with _stp_reserve_bytes. A change
+ * to this branch requires a corresponding change to the same
+ * section of code below.
+ */
+ if (buf == NULL) {
+ const char* fmt_copy = fmt;
+ int num_bytes = 0;
+ va_list args_copy;
+
+ va_copy(args_copy, args);
+
+ for (; *fmt_copy ; ++fmt_copy) {
+ if (*fmt_copy != '%') {
+ num_bytes++;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat_copy:
+ ++fmt_copy; /* this also skips first '%' */
+ switch (*fmt_copy) {
+ case '-': flags |= STP_LEFT; goto repeat_copy;
+ case '+': flags |= STP_PLUS; goto repeat_copy;
+ case ' ': flags |= STP_SPACE; goto repeat_copy;
+ case '#': flags |= STP_SPECIAL; goto repeat_copy;
+ case '0': flags |= STP_ZEROPAD; goto repeat_copy;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt_copy))
+ field_width = skip_atoi(&fmt_copy);
+ else if (*fmt_copy == '*') {
+ ++fmt_copy;
+ /* it's the next argument */
+ field_width = va_arg(args_copy, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= STP_LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt_copy == '.') {
+ ++fmt_copy;
+ if (isdigit(*fmt_copy))
+ precision = skip_atoi(&fmt_copy);
+ else if (*fmt_copy == '*') {
+ ++fmt_copy;
+ /* it's the next argument */
+ precision = va_arg(args_copy, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt_copy == 'h' || *fmt_copy == 'l' || *fmt_copy == 'L') {
+ qualifier = *fmt_copy;
+ ++fmt_copy;
+ if (qualifier == 'l' && *fmt_copy == 'l') {
+ qualifier = 'L';
+ ++fmt_copy;
+ }
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt_copy) {
+ case 'b':
+ num = va_arg(args_copy, int64_t);
+
+ /* Only certain values are valid for the precision. */
+ precision = check_binary_precision (precision);
+
+ /* Unspecified field width defaults to the specified
+ precision and vice versa. If neither is specified,
+ then both default to 8. */
+ if (field_width == -1) {
+ if (precision == -1) {
+ field_width = 8;
+ precision = 8;
+ }
+ else
+ field_width = precision;
+ }
+ else if (precision == -1) {
+ precision = check_binary_precision (field_width);
+ if (precision == -1)
+ precision = 8;
+ }
+
+ len = precision;
+ if (!(flags & STP_LEFT)) {
+ while (len < field_width--) {
+ num_bytes++;
+ }
+ }
+
+ num_bytes += precision;
+
+ while (len < field_width--)
+ num_bytes++;
+
+ continue;
+
+ case 's':
+ case 'M':
+ case 'm':
+ s = va_arg(args_copy, char *);
+ if ((unsigned long)s < PAGE_SIZE)
+ s = "<NULL>";
+
+ if (*fmt_copy == 's')
+ len = strnlen(s, precision);
+ else if (precision > 0)
+ len = precision;
+ else
+ len = 1;
+
+ if (*fmt_copy == 'M')
+ len = len * 2; /* hex dump print size */
+
+ if (!(flags & STP_LEFT)) {
+ while (len < field_width--) {
+ num_bytes++;
+ }
+ }
+
+ num_bytes += len;
+
+ while (len < field_width--) {
+ num_bytes++;
+ }
+ if(flags & STP_ZEROPAD) {
+ num_bytes++;
+ }
+ continue;
+ case 'X':
+ flags |= STP_LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= STP_SIGN;
+ case 'u':
+ break;
+
+ case 'p':
+ /* Note that %p takes an int64_t argument. */
+ len = 2*sizeof(void *) + 2;
+ flags |= STP_ZEROPAD;
+
+ if (field_width == -1)
+ field_width = len;
+
+ if (!(flags & STP_LEFT)) {
+ while (len < field_width) {
+ field_width--;
+ num_bytes++;
+ }
+ }
+
+ //account for "0x"
+ num_bytes+=2;
+ field_width-=2;
+
+ num_bytes += number_size((unsigned long) va_arg(args_copy, int64_t),
+ 16, field_width, field_width, flags);
+ continue;
+
+ case '%':
+ num_bytes++;
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'c':
+ if (!(flags & STP_LEFT)) {
+ while (--field_width > 0) {
+ num_bytes++;
+ }
+ }
+ c = (unsigned char) va_arg(args_copy, int);
+ num_bytes++;
+ while (--field_width > 0) {
+ num_bytes++;
+ }
+ continue;
+
+ default:
+ num_bytes++;
+ if (*fmt_copy) {
+ num_bytes++;
+ } else {
+ --fmt_copy;
+ }
+ continue;
+ }
+
+ if (qualifier == 'L')
+ num = va_arg(args_copy, int64_t);
+ else if (qualifier == 'l') {
+ num = va_arg(args_copy, unsigned long);
+ if (flags & STP_SIGN)
+ num = (signed long) num;
+ } else if (qualifier == 'h') {
+ num = (unsigned short) va_arg(args_copy, int);
+ if (flags & STP_SIGN)
+ num = (signed short) num;
+ } else {
+ num = va_arg(args_copy, unsigned int);
+ if (flags & STP_SIGN)
+ num = (signed int) num;
+ }
+ num_bytes += number_size(num, base, field_width, precision, flags);
+ }
+
+ va_end(args_copy);
+
+ if (num_bytes == 0)
+ return 0;
+
+ //max print buffer size
+ if (num_bytes > STP_BUFFER_SIZE) {
+ num_bytes = STP_BUFFER_SIZE;
+ }
+
+ str = (char*)_stp_reserve_bytes(num_bytes);
+ size = num_bytes;
+ end = str + size - 1;
+
+ } else {
+ str = buf;
+ end = buf + size - 1;
+ }
+ /*
+ * Note that a change to code below requires a corresponding
+ * change in the code above to properly calculate the bytes
+ * required in the output buffer.
+ */
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
if (str <= end)
@@ -297,16 +634,25 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
len = 1;
if (!(flags & STP_LEFT)) {
- while (len < field_width--) {
+ int actlen = len;
+ if (*fmt == 'M')
+ actlen = len * 2;
+ while (actlen < field_width--) {
if (str <= end)
*str = ' ';
++str;
}
}
- if (*fmt == 'M') {
- str = number(str, str + len - 1 < end ? str + len - 1 : end,
- (unsigned long) *(uint64_t *) s,
- 16, field_width, len, flags);
+ if (*fmt == 'M') { /* stolen from kernel: trace_seq_putmem_hex() */
+ const char _stp_hex_asc[] = "0123456789abcdef";
+ int j;
+ for (i = 0, j = 0; i < len; i++) {
+ *str = _stp_hex_asc[((*s) & 0xf0) >> 4];
+ str++;
+ *str = _stp_hex_asc[((*s) & 0x0f)];
+ str++; s++;
+ }
+ len = len * 2; /* the actual length */
}
else {
for (i = 0; i < len; ++i) {
@@ -433,11 +779,13 @@ static int _stp_vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
field_width, precision, flags);
}
- if (likely(str <= end))
- *str = '\0';
- else if (size > 0)
- /* don't write out a null byte if the buf size is zero */
- *end = '\0';
+ if (buf != NULL) {
+ if (likely(str <= end))
+ *str = '\0';
+ else if (size > 0)
+ /* don't write out a null byte if the buf size is zero */
+ *end = '\0';
+ }
return str-buf;
}
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index add4ba3c..7f2db03f 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -981,7 +981,7 @@ sub output_probe_xml(%) {
print "</refentryinfo>\n";
print "<refmeta>\n";
print " <refentrytitle><phrase>".$args{'probe'}."</phrase></refentrytitle>\n";
- print " <manvolnum>5</manvolnum>\n";
+ print " <manvolnum>3stap</manvolnum>\n";
# print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
@@ -1039,7 +1039,7 @@ sub output_sfunction_xml(%) {
print "</refentryinfo>\n";
print "<refmeta>\n";
print " <refentrytitle><phrase>".$args{'sfunction'}."</phrase></refentrytitle>\n";
- print " <manvolnum>5</manvolnum>\n";
+ print " <manvolnum>3stap</manvolnum>\n";
# print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
@@ -1774,7 +1774,7 @@ sub create_sparameterlist($$$) {
my $param;
foreach my $arg (split($splitter, $args)) {
- if ($arg =~ m/s*([\w]+)\s*:?\s*([\w]*)/) {
+ if ($arg =~ m/\s*([\w]+)\s*:?\s*([\w]*)/) {
$param = $1;
$type = $2;
push_parameter($param, $type, $file);
@@ -2083,7 +2083,7 @@ sub process_state3_probe($$) {
my $prototype = shift;
my $file = shift;
- $prototype =~ s@/probe/@@o; # strip off leading 'probe'
+ $prototype =~ s@probe@@o; # strip off leading 'probe'
$prototype =~ s@^\s+@@gos; # strip leading spaces
dump_probe($prototype,$file);
reset_state();
diff --git a/session.h b/session.h
index ec6c2e3e..151094b1 100644
--- a/session.h
+++ b/session.h
@@ -30,6 +30,7 @@ struct functiondecl;
struct derived_probe;
struct be_derived_probe_group;
struct dwarf_derived_probe_group;
+struct kprobe_derived_probe_group;
struct uprobe_derived_probe_group;
struct utrace_derived_probe_group;
struct itrace_derived_probe_group;
@@ -74,8 +75,9 @@ struct statistic_decl
struct systemtap_session
{
systemtap_session ();
- // NB: new POD members likely need to be explicitly cleared in the ctor.
- // See elaborate.cxx.
+ // NB: It is very important for all of the above (and below) fields
+ // to be cleared in the systemtap_session ctor (elaborate.cxx)
+ // and/or main.cxx(main).
// command line args
std::vector<std::string> include_path;
@@ -87,9 +89,11 @@ struct systemtap_session
std::string architecture;
std::string runtime_path;
std::string data_path;
+ std::string cert_db_path;
std::string module_name;
std::string stapconf_name;
std::string output_file;
+ std::string size_option;
std::string cmd;
int target_pid;
int last_pass;
@@ -111,11 +115,16 @@ struct systemtap_session
bool need_uprobes;
bool load_only; // flight recorder mode
+ // NB: It is very important for all of the above (and below) fields
+ // to be cleared in the systemtap_session ctor (elaborate.cxx)
+ // and/or main.cxx(main).
+
// Cache data
bool use_cache;
std::string cache_path;
std::string hash_path;
std::string stapconf_path;
+ std::string tracequery_path;
// dwarfless operation
bool consult_symtab;
@@ -126,6 +135,10 @@ struct systemtap_session
// Skip bad $ vars
bool skip_badvars;
+ // NB: It is very important for all of the above (and below) fields
+ // to be cleared in the systemtap_session ctor (elaborate.cxx)
+ // and/or main.cxx(main).
+
// temporary directory for module builds etc.
// hazardous - it is "rm -rf"'d at exit
std::string tmpdir;
@@ -159,6 +172,7 @@ struct systemtap_session
// session.probes vector.
be_derived_probe_group* be_derived_probes;
dwarf_derived_probe_group* dwarf_derived_probes;
+ kprobe_derived_probe_group* kprobe_derived_probes;
uprobe_derived_probe_group* uprobe_derived_probes;
utrace_derived_probe_group* utrace_derived_probes;
itrace_derived_probe_group* itrace_derived_probes;
@@ -170,8 +184,10 @@ struct systemtap_session
hrtimer_derived_probe_group* hrtimer_derived_probes;
perfmon_derived_probe_group* perfmon_derived_probes;
procfs_derived_probe_group* procfs_derived_probes;
+
// NB: It is very important for all of the above (and below) fields
- // to be cleared in the systemtap_session ctor (elaborate.cxx).
+ // to be cleared in the systemtap_session ctor (elaborate.cxx)
+ // and/or main.cxx(main).
// unparser data
translator_output* op;
@@ -187,6 +203,10 @@ struct systemtap_session
std::set<std::string> unwindsym_modules;
struct module_cache* module_cache;
+ // NB: It is very important for all of the above (and below) fields
+ // to be cleared in the systemtap_session ctor (elaborate.cxx)
+ // and/or main.cxx(main).
+
std::set<std::string> seen_errors;
std::set<std::string> seen_warnings;
unsigned num_errors () { return seen_errors.size(); }
@@ -198,7 +218,9 @@ struct systemtap_session
void print_error_source (std::ostream&, std::string&, const token* tok);
void print_warning (const std::string& w, const token* tok = 0);
- // reNB: new POD members likely need to be explicitly cleared in the ctor.
+ // NB: It is very important for all of the above (and below) fields
+ // to be cleared in the systemtap_session ctor (elaborate.cxx)
+ // and/or main.cxx(main).
};
diff --git a/stap-add-server-cert b/stap-authorize-cert
index a94c5955..21af2ce0 100755..100644
--- a/stap-add-server-cert
+++ b/stap-authorize-cert
@@ -1,6 +1,6 @@
#!/bin/bash
-# Add an existing server certificate to the
+# Add an existing server certificate to a
# database of trusted servers for the client.
#
# Copyright (C) 2008, 2009 Red Hat Inc.
@@ -10,37 +10,40 @@
# Public License (GPL); either version 2, or (at your option) any
# later version.
+certfile=$1
+certdb=$2
+
# Obtain the filename of the certificate
-if test "X$1" = "X"; then
+if test "X$certfile" = "X"; then
echo "Certificate file must be specified" >&2
exit 1
fi
-if ! test -f $1; then
- echo "Cannot find certificate file $1" >&2
+if ! test -f $certfile; then
+ echo "Cannot find certificate file $certfile" >&2
exit 1
fi
# Obtain the certificate database directory name.
-if test "X$2" = "X"; then
+if test "X$certdb" = "X"; then
echo "Certificate database directory must be specified" >&2
exit 1
fi
-if ! test -d $2; then
- if ! mkdir -p -m 755 $2; then
- echo "Unable to find or create the client certificate database directory: $2" >&2
+if ! test -d $certdb; then
+ if ! mkdir -p -m 755 $certdb; then
+ echo "Unable to find or create the client certificate database directory: $certdb" >&2
exit 1
fi
fi
# Add the certificate
-if ! certutil -A -n stap-server -d $2 -i $1 -t "P,P,P" > /dev/null; then
- echo "Unable to add $1 to the client certificate database $2" >&2
+if ! certutil -A -n stap-server -d $certdb -i $certfile -t "P,P,P" > /dev/null; then
+ echo "Unable to add $certfile to the client certificate database $certdb" >&2
exit 1
fi
# Ensure that the database is readable by others
-if ! chmod +r $2/*.db; then
- echo "Warning: unable to make the client certificate database $2 readable by others" >&2
+if ! chmod +r $certdb/*.db; then
+ echo "Warning: unable to make the client certificate database $certdb readable by others" >&2
fi
exit 0
diff --git a/stap-authorize-server-cert b/stap-authorize-server-cert
new file mode 100644
index 00000000..13fb9c9f
--- /dev/null
+++ b/stap-authorize-server-cert
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Add an existing server certificate to the
+# database of trusted SSL servers for the client.
+#
+# Copyright (C) 2009 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.
+
+# Initialize the environment
+. `dirname $0`/stap-env
+
+certfile=$1
+certdb=$2
+
+# Obtain the filename of the certificate
+if test "X$certfile" = "X"; then
+ echo "Certificate file must be specified" >&2
+ exit 1
+fi
+
+# Obtain the certificate database directory name.
+if test "X$certdb" = "X"; then
+ certdb=$stap_ssl_db/client
+fi
+
+${stap_exec_prefix}stap-authorize-cert $certfile $certdb
diff --git a/stap-authorize-signing-cert b/stap-authorize-signing-cert
new file mode 100644
index 00000000..22da27c4
--- /dev/null
+++ b/stap-authorize-signing-cert
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Add an existing server certificate to the
+# database of trusted SSL servers for the client.
+#
+# Copyright (C) 2009 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.
+
+# Initialize the environment
+. `dirname $0`/stap-env
+
+certfile=$1
+certdb=$2
+
+# Obtain the filename of the certificate
+if test "X$certfile" = "X"; then
+ echo "Certificate file must be specified" >&2
+ exit 1
+fi
+
+# Obtain the certificate database directory name.
+if test "X$certdb" = "X"; then
+ certdb=$stap_signing_db
+fi
+
+${stap_exec_prefix}stap-authorize-cert $certfile $certdb
diff --git a/stap-client b/stap-client
index 70271b9a..c3afab89 100755
--- a/stap-client
+++ b/stap-client
@@ -21,23 +21,12 @@ trap 'terminate' SIGTERM
trap 'interrupt' SIGINT
trap 'ignore_signal' SIGHUP SIGPIPE
+# Initialize the environment
+. `dirname $0`/stap-env
+
#-----------------------------------------------------------------------------
# Helper functions.
#-----------------------------------------------------------------------------
-# function: configuration
-function configuration {
- # INSTALL-HOOK These settings work for running the client from the source tree
- # INSTALL-HOOK using the dejagnu test harness and will be overridden at install
- # INSTALL-HOOK time.
- exec_prefix=
- sysconfdir=`pwd`/net
-
- # General configuration
- tmpdir_prefix_client=stap.client
- tmpdir_prefix_server=stap.server
- avahi_service_tag=_stap._tcp
-}
-
# function: initialization
function initialization {
our_host_name=`expr "$HOSTNAME" : "\\\([a-zA-Z0-9-]*\\\).*"`
@@ -46,24 +35,21 @@ function initialization {
rc=0
wd=`pwd`
umask 0
- staprun_running=0
# Default location for server certificates if we're not root
# Must be owned by us.
local uid uname
if test $EUID != 0; then
- if test -e $HOME/.systemtap/ssl/client; then
- if check_db $HOME/.systemtap/ssl/client $EUID $USER; then
- local_ssl_dbs=$HOME/.systemtap/ssl/client
+ if test -e $stap_user_ssl_db/client; then
+ if check_db $stap_user_ssl_db/client $EUID $USER; then
+ local_ssl_dbs=$stap_user_ssl_db/client
fi
fi
fi
# Additional location for all users. Must be owned by root.
- if test "X$sysconfdir" != "X"; then
- if test -e $sysconfdir/systemtap/ssl/client; then
- if check_db $sysconfdir/systemtap/ssl/client 0 root; then
- public_ssl_dbs=$sysconfdir/systemtap/ssl/client
- fi
+ if test -e $stap_root_ssl_db/client; then
+ if check_db $stap_root_ssl_db/client 0 root; then
+ public_ssl_dbs=$stap_root_ssl_db/client
fi
fi
@@ -79,7 +65,7 @@ function initialization {
# Create a temporary directory to package things in
# Do this before parsing the command line so that there is a place
# to put -I and -R directories.
- tmpdir_client=`mktemp -dt $tmpdir_prefix_client.XXXXXX` || \
+ tmpdir_client=`mktemp -dt $stap_tmpdir_prefix_client.XXXXXX` || \
fatal "Cannot create temporary directory " $tmpdir_client
tmpdir_env=`dirname $tmpdir_client`
}
@@ -469,7 +455,7 @@ function package_request {
# Unpack the zip file received from the server and make the contents available
# for printing the results and/or running 'staprun'.
function unpack_response {
- tmpdir_server=`mktemp -dt $tmpdir_prefix_client.server.XXXXXX` || \
+ tmpdir_server=`mktemp -dt $stap_tmpdir_prefix_client.server.XXXXXX` || \
fatal "Cannot create temporary file " $tmpdir_server
# Unpack the server output directory
@@ -477,15 +463,15 @@ function unpack_response {
fatal "Cannot unpack server response, $zip_server"
# Check the contents of the expanded directory. It should contain a
- # single directory whose name matches stap.server.??????
+ # single directory whose name matches $stap_tmpdir_prefix_server.??????
local num_files=`ls $tmpdir_server | wc -l`
test $num_files = 1 || \
fatal "Wrong number of files in server's temp directory"
- test -d $tmpdir_server/stap.server.?????? || \
+ test -d $tmpdir_server/$stap_tmpdir_prefix_server.?????? || \
fatal "`ls $tmpdir_server` does not match the expected name or is not a directory"
# Move the contents of the directory down one level.
- mv $tmpdir_server/stap.server.??????/* $tmpdir_server
- rm -fr $tmpdir_server/stap.server.??????
+ mv $tmpdir_server/$stap_tmpdir_prefix_server.??????/* $tmpdir_server
+ rm -fr $tmpdir_server/$stap_tmpdir_prefix_server.??????
# Check the contents of the directory. It should contain:
# 1) a file called stdout
@@ -533,7 +519,7 @@ function find_and_connect_to_server {
local num_servers=0
# Make a place to receive the response file.
- zip_server=`mktemp -t $tmpdir_prefix_client.server.zip.XXXXXX` || \
+ zip_server=`mktemp -t $stap_tmpdir_prefix_client.server.zip.XXXXXX` || \
fatal "Cannot create temporary file " $zip_server
# Make a place to record connection errors
@@ -596,22 +582,22 @@ function find_and_connect_to_server {
fi
fi
- if test `${exec_prefix}stap-find-servers $find_all | grep $address | wc -l` = "0"; then
+ if test `${stap_exec_prefix}stap-find-servers $find_all | grep $address | wc -l` = "0"; then
warning "No server is available on $server" 2>> $tmpdir_client/connect
continue
fi
- ssl_db=`${exec_prefix}stap-find-servers $find_all | grep $address | choose_server`
+ ssl_db=`${stap_exec_prefix}stap-find-servers $find_all | grep $address | choose_server`
test "X$ssl_db" != "X" && return
done
else
# No servers specified. Find available servers and choose one of them.
# Remember which ssl certificate database was used to authenticate the chosen
# server.
- ssl_db=`${exec_prefix}stap-find-servers $find_all | choose_server`
+ ssl_db=`${stap_exec_prefix}stap-find-servers $find_all | choose_server`
test "X$ssl_db" != "X" && return
- num_servers=`${exec_prefix}stap-find-servers $find_all | wc -l`
+ num_servers=`${stap_exec_prefix}stap-find-servers $find_all | wc -l`
fi
if test $num_servers = 0; then
@@ -681,8 +667,8 @@ function send_receive {
do
# Send the request and receive the response using stap-client-connect
echo "Attempting connection with $server:$port using certificate database in '$db'" >> $tmpdir_client/connect
- ${exec_prefix}stap-client-connect -i $zip_client -o $zip_server -d $db -p $port -h $server >> $tmpdir_client/connect 2>&1 &
- wait '%${exec_prefix}stap-client-connect'
+ ${stap_exec_prefix}stap-client-connect -i $zip_client -o $zip_server -d $db -p $port -h $server >> $tmpdir_client/connect 2>&1 &
+ wait '%${stap_exec_prefix}stap-client-connect'
test $? = 0 && echo $db && return
sleep 1
done
@@ -692,8 +678,8 @@ function send_receive {
do
# Send the request and receive the response using stap-client-connect
echo "Attempting connection with $server:$port using certificate database in '$db'" >> $tmpdir_client/connect
- ${exec_prefix}stap-client-connect -i $zip_client -o $zip_server -d $db -p $port -h $server >> $tmpdir_client/connect 2>&1 &
- wait '%${exec_prefix}stap-client-connect'
+ ${stap_exec_prefix}stap-client-connect -i $zip_client -o $zip_server -d $db -p $port -h $server >> $tmpdir_client/connect 2>&1 &
+ wait '%${stap_exec_prefix}stap-client-connect'
test $? = 0 && echo $db && return
sleep 1
done
@@ -779,18 +765,13 @@ function maybe_call_staprun {
fi
# Run it in the background and wait for it. This
- # way any signals send to us can be caught.
+ # way any signals sent to us can be caught.
if test $v_level -ge 2; then
echo "running `which staprun` $staprun_opts $tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'`" >&2
fi
eval `staprun_PATH` "$staprun_opts" \
$tmpdir_stap/`ls $tmpdir_stap | grep '.ko$'`
- staprun_running=1
- wait '%?staprun' > /dev/null 2>&1
rc=$?
- staprun_running=0
- # 127 from wait means that the job was already finished.
- test $rc=127 && rc=0
# Wait until the job actually disappears so that its output is complete.
while jobs '%?staprun' >/dev/null 2>&1
@@ -814,8 +795,8 @@ function staprun_PATH {
fi
# Otherwise, if there is an exec_prefix, then use it.
- if test "X$exec_prefix" != "X"; then
- echo ${exec_prefix}staprun
+ if test "X$stap_exec_prefix" != "X"; then
+ echo ${stap_exec_prefix}staprun
return
fi
@@ -1020,7 +1001,7 @@ function terminate {
kill -s SIGTERM '%?staprun' 2>/dev/null
# Kill any stap-client-connect job
- kill -s SIGTERM '%${exec_prefix}stap-client-connect' 2>/dev/null
+ kill -s SIGTERM '%${stap_exec_prefix}stap-client-connect' 2>/dev/null
exit 1
}
@@ -1029,15 +1010,9 @@ function terminate {
#
# Pass an interrupt (ctrl-C) to staprun
function interrupt {
- # Pass the signal on to any running staprun job
- if test $staprun_running = 1; then
- kill -s SIGINT '%?staprun' 2>/dev/null
- return
- fi
-
# Kill any stap-client-connect job
# SIGINT won't do it.
- kill -s SIGTERM '%${exec_prefix}stap-client-connect' 2>/dev/null
+ kill -s SIGTERM '%${stap_exec_prefix}stap-client-connect' 2>/dev/null
# If staprun was not running, then exit.
cleanup
@@ -1054,7 +1029,6 @@ function ignore_signal {
#-----------------------------------------------------------------------------
# Beginning of main line execution.
#-----------------------------------------------------------------------------
-configuration
initialization
parse_options "$@"
create_request
diff --git a/stap-env b/stap-env
new file mode 100644
index 00000000..8d765ae6
--- /dev/null
+++ b/stap-env
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Generate a certificate for the systemtap server and add it to the
+# database of trusted servers for the client.
+#
+# Copyright (C) 2009 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.
+
+# Common environment setup for stap scripts
+
+# INSTALL-HOOK These settings work for running the server from the source tree
+# INSTALL-HOOK using the dejagnu test harness and will be overridden at install
+# INSTALL-HOOK time.
+stap_exec_prefix=
+stap_sysconfdir=`pwd`/net
+
+# General configuration
+stap_tmpdir_prefix_client=stap.client
+stap_tmpdir_prefix_server=stap.server
+stap_avahi_service_tag=_stap._tcp
+
+# NSS certificate databases
+stap_root_ssl_db=$stap_sysconfdir/systemtap/ssl
+stap_user_ssl_db=$HOME/.systemtap/ssl
+
+if test $EUID = 0; then
+ stap_ssl_db=$stap_root_ssl_db
+else
+ stap_ssl_db=$stap_user_ssl_db
+fi
+
+stap_signing_db=$stap_sysconfdir/systemtap/staprun
+stap_certfile=stap.cert
+stap_old_certfile=stap-server.cert
diff --git a/stap-find-or-start-server b/stap-find-or-start-server
index 97e7caca..a93b21fe 100755
--- a/stap-find-or-start-server
+++ b/stap-find-or-start-server
@@ -10,23 +10,21 @@
# later version.
# This script attempts to find a systemtap server. If one is found, it
-# echoes 0 and exits with 0.
+# echoes 0.
#
# Otherwise, it attempts to start a server. If succesful, it echoes the
-# process id and exits with 0.
+# process id.
#
-# Otherwise, it echoes -1 and exits with 1
+# Otherwise, it echoes -1
-# INSTALL-HOOK These settings work for running the client from the source tree
-# INSTALL-HOOK using the dejagnu test harness and will be overridden at install
-# INSTALL-HOOK time.
-exec_prefix=
+# Initialize the environment
+. `dirname $0`/stap-env
# Is there a server available?
-${exec_prefix}stap-find-servers >/dev/null 2>&1 && echo 0 && exit 0
+${stap_exec_prefix}stap-find-servers >/dev/null 2>&1 && echo 0 && exit 0
# No server available, try to start one.
-pid=`${exec_prefix}stap-start-server "$@"`
+pid=`${stap_exec_prefix}stap-start-server "$@"`
if test $? = 0; then
echo $pid
exit 0
@@ -34,4 +32,4 @@ fi
# Could not find or start a server
echo "-1"
-exit 1
+exit 0
diff --git a/stap-find-servers b/stap-find-servers
index fde7d9ef..77cd267a 100755
--- a/stap-find-servers
+++ b/stap-find-servers
@@ -12,15 +12,12 @@
# This script uses avahi to find systemtap compile servers on the local
# network. Information about each server found is printed to stdout.
+# Initialize the environment
+. `dirname $0`/stap-env
+
#-----------------------------------------------------------------------------
# Helper functions.
#-----------------------------------------------------------------------------
-# function: configuration
-function configuration {
- avahi_service_tag=_stap._tcp
- timeout=10 # seconds
-}
-
# function: initialization
function initialization {
rc=1 # not found yet
@@ -29,6 +26,7 @@ function initialization {
else
find_all=0
fi
+ timeout=10 # seconds
}
# function: find_servers
@@ -37,12 +35,12 @@ function initialization {
function find_servers {
# Create a temp file for the list of servers. We do this instead
# of using a pipe so that we can kill avahi-browse if it
- # takes more than a minute.
+ # takes too long.
tmpfile=`mktemp -t stap-serversXXXXXX` || \
fatal "Cannot create temporary file " $tmpfile
# Find servers
- avahi-browse $avahi_service_tag --terminate -r 2>/dev/null > $tmpfile &
+ avahi-browse $stap_avahi_service_tag --terminate -r 2>/dev/null > $tmpfile &
for ((attempt=0; $attempt < $timeout; ++attempt))
do
@@ -97,7 +95,7 @@ function match_server {
;;
address )
# Sometimes (seems random), avahi-resolve-host-name resolves a local server to its
- # hardware address rather its ip address. Keep trying until we get
+ # hardware address rather than its ip address. Keep trying until we get
# an ip address.
server_ip=`expr "$service_data" : '\[\([^]]*\)\]'`
local attempt
@@ -125,7 +123,7 @@ function match_server {
esac
done
- # It is a stap server, but is it compatible?
+ # It's an stap server, but is it compatible?
if test $find_all = 0 -a "$server_sysinfo" != "`client_sysinfo`"; then
continue
fi
@@ -159,7 +157,6 @@ function fatal {
#-----------------------------------------------------------------------------
# Beginning of main line execution.
#-----------------------------------------------------------------------------
-configuration
initialization "$@"
find_servers
diff --git a/stap-gen-server-cert b/stap-gen-cert
index 9b4a776b..574df351 100755..100644
--- a/stap-gen-server-cert
+++ b/stap-gen-cert
@@ -10,6 +10,9 @@
# Public License (GPL); either version 2, or (at your option) any
# later version.
+# Initialize the environment
+. `dirname $0`/stap-env
+
# Obtain a password from stdin and echo it.
function user_enter_password
{
@@ -35,14 +38,13 @@ function user_enter_password
}
# Obtain the certificate database directory name.
-if test "X$1" = "X"; then
- echo "Certificate database directory must be specified" >&2
- exit 1
+serverdb=$1
+if test "X$serverdb" = "X"; then
+ serverdb=$stap_ssl_db/server
fi
-rm -fr $1
+rm -fr $serverdb
# Create the server's certificate database directory.
-serverdb=$1/server
if ! mkdir -p -m 755 $serverdb; then
echo "Unable to create the server certificate database directory: $serverdb" >&2
exit 1
@@ -67,27 +69,27 @@ if ! certutil -N -d $serverdb -f $serverdb/pw > /dev/null; then
fi
# We need some random noise for generating keys
-dd bs=123 count=1 < /dev/urandom > $1/noise 2> /dev/null
+dd bs=123 count=1 < /dev/urandom > $serverdb/noise 2> /dev/null
# Generate a request for the server's certificate.
-certutil -R -d $serverdb -f $serverdb/pw -s "CN=Systemtap Compile Server, OU=Systemtap, O=Red Hat, C=US" -o $1/stap-server.req -z $1/noise 2> /dev/null
-rm -fr $1/noise
+certutil -R -d $serverdb -f $serverdb/pw -s "CN=Systemtap Compile Server, OU=Systemtap, O=Red Hat, C=US" -o $serverdb/stap.req -z $serverdb/noise 2> /dev/null
+rm -fr $serverdb/noise
# Create the certificate file first so that it always has the proper access permissions.
-if ! (touch $serverdb/stap-server.cert && chmod 644 $serverdb/stap-server.cert); then
- echo "Unable to create the server certificate file: $serverdb/stap-server.cert" >&2
+if ! (touch $serverdb/$stap_certfile && chmod 644 $serverdb/$stap_certfile); then
+ echo "Unable to create the server certificate file: $serverdb/$stap_certfile" >&2
exit 1
fi
# Now generate the actual certificate.
-certutil -C -i $1/stap-server.req -o $serverdb/stap-server.cert -x -d $serverdb -f $serverdb/pw -5 -8 "$HOSTNAME,localhost" >/dev/null <<-EOF
+certutil -C -i $serverdb/stap.req -o $serverdb/$stap_certfile -x -d $serverdb -f $serverdb/pw -5 -8 "$HOSTNAME,localhost" >/dev/null <<-EOF
1
3
7
8
y
EOF
-rm -fr $1/stap-server.req
+rm -fr $serverdb/stap.req
# Add the certificate to the server's certificate/key database as a trusted peer, ssl server and object signer
-certutil -A -n stap-server -t "PCu,,PCu" -i $serverdb/stap-server.cert -d $serverdb -f $serverdb/pw
+certutil -A -n stap-server -t "PCu,,PCu" -i $serverdb/$stap_certfile -d $serverdb -f $serverdb/pw
diff --git a/stap-server b/stap-server
index ec827a09..316cc954 100755
--- a/stap-server
+++ b/stap-server
@@ -16,22 +16,12 @@
# Catch ctrl-c and other termination signals
trap 'terminate' SIGTERM SIGINT
+# Initialize the environment
+. `dirname $0`/stap-env
+
#-----------------------------------------------------------------------------
# Helper functions.
#-----------------------------------------------------------------------------
-# function: configuration
-function configuration {
- # INSTALL-HOOK These settings work for running the client from the source tree
- # INSTALL-HOOK using the dejagnu test harness and will be overridden at install
- # INSTALL-HOOK time.
- exec_prefix=
- sysconfdir=`pwd`/net
-
- # Configuration
- tmpdir_prefix_client=stap.client
- tmpdir_prefix_server=stap.server
-}
-
# function: initialization
function initialization {
# Initialization
@@ -92,18 +82,18 @@ function unpack_request {
fatal "Cannot unpack zip archive $zip_client"
# Identify the client's request tree. The zip file should have expanded
- # into a single directory named to match $tmpdir_prefix_client.??????
+ # into a single directory named to match $stap_tmpdir_prefix_client.??????
# which should now be the only item in the current directory.
test "`ls | wc -l`" = 3 || \
fatal "Wrong number of files after expansion of client's zip file"
- tmpdir_client=`ls | grep $tmpdir_prefix_client.......\$`
+ tmpdir_client=`ls | grep $stap_tmpdir_prefix_client.......\$`
test "X$tmpdir_client" != "X" || \
fatal "Client zip file did not expand as expected"
# Move the client's temp directory to a local temp location
- local local_tmpdir_client=`mktemp -dt $tmpdir_prefix_server.client.XXXXXX` || \
+ local local_tmpdir_client=`mktemp -dt $stap_tmpdir_prefix_server.client.XXXXXX` || \
fatal "Cannot create temporary client request directory " $local_tmpdir_client
mv $tmpdir_client/* $local_tmpdir_client
rm -fr $tmpdir_client
@@ -340,7 +330,7 @@ function call_stap {
server_p_phase=$p_phase
fi
- eval ${exec_prefix}stap "$cmdline" -k -p $server_p_phase \
+ eval ${stap_exec_prefix}stap "$cmdline" -k -p $server_p_phase \
>> $tmpdir_server/stdout \
2>> $tmpdir_server/stderr
@@ -433,7 +423,6 @@ function terminate {
#-----------------------------------------------------------------------------
# Beginning of main line execution.
#-----------------------------------------------------------------------------
-configuration
initialization "$@"
unpack_request
check_request
diff --git a/stap-server-connect.c b/stap-server-connect.c
index 8263a3d5..33d4983b 100644
--- a/stap-server-connect.c
+++ b/stap-server-connect.c
@@ -94,7 +94,7 @@ readDataFromSocket(PRFileDesc *sslSocket)
return SECFailure;
}
- /* Read the number fo bytes to be received. */
+ /* Read the number of bytes to be received. */
numBytesRead = PR_Read(sslSocket, & info.size, sizeof (info.size));
if (numBytesRead == 0) /* EOF */
{
@@ -377,6 +377,7 @@ handle_connection(PRFileDesc *tcpSocket)
PRSocketOptionData socketOption;
PRFileInfo info;
char *cmdline;
+ char *stap_server_prefix;
int rc;
char *rc1;
@@ -465,10 +466,11 @@ handle_connection(PRFileDesc *tcpSocket)
#endif
/* Call the stap-server script. */
- cmdline = PORT_Alloc(sizeof ("stap-server") +
- sizeof (requestFileName) +
- sizeof (responseDirName) +
- sizeof (responseZipName) +
+ stap_server_prefix = getenv("SYSTEMTAP_SERVER_SCRIPTS") ?: BINDIR;
+ cmdline = PORT_Alloc(strlen (stap_server_prefix) + sizeof ("/stap-server") + 1 +
+ sizeof (requestFileName) + 1 +
+ sizeof (responseDirName) + 1 +
+ sizeof (responseZipName) + 1 +
strlen (dbdir) + 1);
if (! cmdline) {
errWarn ("PORT_Alloc");
@@ -476,7 +478,7 @@ handle_connection(PRFileDesc *tcpSocket)
goto cleanup;
}
- sprintf (cmdline, "stap-server %s %s %s %s",
+ sprintf (cmdline, "%s/stap-server %s %s %s %s", stap_server_prefix,
requestFileName, responseDirName, responseZipName, dbdir);
rc = system (cmdline);
diff --git a/stap-server.8.in b/stap-server.8.in
index 1976b6ea..0480b6d5 100644
--- a/stap-server.8.in
+++ b/stap-server.8.in
@@ -18,7 +18,7 @@ stap-server \- systemtap server and related utilities
.B stap\-stop\-server
.I PID
.br
-.B stap\-add\-server\-cert \fICERTFILE\fR \fIDIRNAME\fR
+.B stap\-authorize\-server\-cert \fICERTFILE\fR [ \fIDIRNAME\fR ]
.br
.B stap\-client
[
@@ -66,13 +66,13 @@ using
.IR stap\-find\-servers .
If a compatible server is found,
.I stap\-find\-or\-start\-server
-echoes \[aq]0\[aq] to stdout and the exit code is 0. Otherwise
+echoes \[aq]0\[aq] to stdout. Otherwise
.I stap\-find\-or\-start\-server
attempts to start a server on the local network using
.IR stap\-start\-server .
-If successful, the process id of the new server is echoed to stdout and the
-exit code is 0. If no server can be found or started, \[aq]-1\[aq] is echoed
-to stdout and the exit code is 1.
+If successful, the process id of the new server is echoed to stdout.
+If no server can be found or started, \[aq]-1\[aq] is echoed
+to stdout. The exit code is 0 in all cases.
.PP
The
@@ -86,14 +86,14 @@ does not verify that the server actually shuts down.
.PP
The
-.I stap\-add\-server\-cert
+.I stap\-authorize\-server\-cert
program adds the given server certificate to the given client\-side
certificate database, making that server a trusted server for clients using that database.
.PP
The
.I stap\-client
-program is analagous to the
+program is analogous to the
.I stap
front end except that it attempts to find a compatible systemtap server on the
local network and then attempts to use that server for actions related to
@@ -125,13 +125,13 @@ accepts the following:
.TP
.B \-\-server=\fIHOSTNAME\fR|\fIIP_ADDRESS\fR[\fB:\fIPORT\fR]
-This option intructs
+This option instructs
.I stap\-client
to use the named server instead of looking for one automatically. The server may
be specified using a valid host name or ip address. If no port is specified, then
.I stap\-client
-searches for the server among the servers advertizing their presence on the
-local network and uses the port which is being advertized. This is useful for
+searches for the server among the servers advertising their presence on the
+local network and uses the port which is being advertised. This is useful for
connecting to a specific server on the local network. If a port is specified,
then
.I stap\-client
@@ -168,19 +168,23 @@ program requires a process id argument which identifies the server to be stopped
.PP
The
-.I stap\-add\-server\-cert
+.I stap\-authorize\-server\-cert
program accepts two arguments:
.TP
.B CERTFILE
This is the name of the file containing the certificate of the new trusted
-server. This is the file named \fIstap-server.cert\fR which can be found in the
+server. This is the file named \fIstap.cert\fR which can be found in the
server\[aq]s certificate database.
.TP
.B DIRNAME
-This is the name of the directory containing the client\-side certificate database to which
-the certificate is to be added.
+This optional argument is the name of the directory containing the client\-side
+certificate database to which the certificate is to be added. If not specified, the
+default, for non\-root users, is
+.I $HOME/.systemtap/ssl/server\fP.
+For root users (EUID=0), the default is
+.I $sysconfdir/systemtap/ssl/server\fP.
.PP
The
@@ -218,7 +222,7 @@ For root users (EUID=0), it will be created in
.I $sysconfdir/systemtap/ssl/server\fP.
.IP \(bu 4
-At this time the
+At this time, the
server will also create a local client\-side certificate database and add the
server\[aq]s certificate to it. For non\-root users,
this database will be created in
@@ -249,9 +253,9 @@ will be considered to be trusted for that invocation of the client.
.IP \(bu 4
A user may add the certificate of a new trusted server to his own local
client\-side certificate database using
-\[aq]\fBstap-add-server-cert \fICERTFILE\fR \fIDIRNAME\fR\[aq]
+\[aq]\fBstap\-authorize\-server\-cert \fICERTFILE\fR\[aq]
(see above), where \fICERTFILE\fP is the server\[aq]s certificate file
-(\fIstap\-server.cert\fP) from the servers certificate database directory and
+(\fIstap.cert\fP) from the server\[aq]s certificate database directory and
\fIDIRNAME\fP is the
directory containing the user\[aq]s client\-side certificate database.
@@ -265,7 +269,7 @@ host.
.SH EXAMPLES
See the
-.IR stapex (5)
+.IR stapex (3stap)
manual page for a collection of sample scripts.
.PP
Here is a very basic example of how to use
@@ -312,11 +316,11 @@ simple example
.PP
To permanently trust a given server for your own use
.PP
-.B \& $ stap\-add\-server\-cert \fICERTFILE\fP $HOME/.systemtap/ssl/client
+.B \& $ stap\-authorize\-server\-cert \fICERTFILE\fP
.PP
As root, to permanently trust a given server for all users on your host
.PP
-.B \& $ stap\-add\-server\-cert \fICERTFILE\fP $sysconfdir/systemtap/ssl/client
+.B \& $ stap\-authorize\-server\-cert \fICERTFILE\fP
.PP
If a process id was echoed by
.I stap\-start\-server
@@ -337,11 +341,9 @@ manual page for additional information on safety and security.
.PP
The systemtap server and its related utilities use the Secure Socket Layer
(SSL) as implemented by Network Security Services (NSS)
-for network security and the NSS tools
+for network security. The NSS tool
.I certutil
-and
-.I signtool
-for the generation of certificates and for signing respectively. The related
+is used for the generation of certificates. The related
certificate databases must be protected in order to maintain the security of
the system.
Use of the utilities provided will help to ensure that the proper protection
@@ -351,12 +353,11 @@ access permissions before making use of any certificate database.
.SH SEE ALSO
.IR stap (1),
.IR staprun (8),
-.IR stapprobes (5),
-.IR stapfuncs (5),
-.IR stapex (5),
+.IR stapprobes (3stap),
+.IR stapfuncs (3stap),
+.IR stapex (3stap),
.IR NSS ,
-.IR certutil ,
-.IR signtool
+.IR certutil
.SH BUGS
Use the Bugzilla link off of the project web page or our mailing list.
diff --git a/stap-serverd b/stap-serverd
index 6467ec55..4eee8c38 100755
--- a/stap-serverd
+++ b/stap-serverd
@@ -16,20 +16,14 @@
# Catch ctrl-c and other termination signals
trap 'terminate' SIGTERM SIGINT
+# Initialize the environment
+. `dirname $0`/stap-env
+
#-----------------------------------------------------------------------------
# Helper functions.
#-----------------------------------------------------------------------------
# function: initialization PORT
function initialization {
- # INSTALL-HOOK These settings work for running the server from the source tree
- # INSTALL-HOOK using the dejagnu test harness and will be overridden at install
- # INSTALL-HOOK time.
- exec_prefix=
- sysconfdir=`pwd`/net
-
- # Default settings.
- avahi_type=_stap._tcp
-
# What port will we listen on?
port=$1
test "X$port" = "X" && port=65000
@@ -43,19 +37,31 @@ function initialization {
# Where is the ssl certificate/key database?
ssl_db=$2
if test "X$ssl_db" = "X"; then
+ ssl_db=$stap_ssl_db/server
+ # Update the certificate file if it is old.
+ if test -f $ssl_db/$stap_old_certfile; then
+ if ! test -e $ssl_db/$stap_certfile; then
+ mv $ssl_db/$stap_old_certfile $ssl_db/$stap_certfile
+ else
+ rm -fr $ssl_db/$stap_old_certfile
+ fi
+ fi
# If no certificate/key database has been specified, then find/create
# a local one.
- if test $EUID = 0; then
- ssl_db=$sysconfdir/systemtap/ssl/server
- else
- ssl_db=$HOME/.systemtap/ssl/server
- fi
- if ! test -f $ssl_db/stap-server.cert; then
- ${exec_prefix}stap-gen-server-cert `dirname $ssl_db` || exit 1
+ if ! test -f $ssl_db/$stap_certfile; then
+ ${stap_exec_prefix}stap-gen-cert $ssl_db || exit 1
# Now add the server's certificate to the client's database,
# making it a trusted peer. Do this only if the client has been installed.
- if test -f `which ${exec_prefix}stap-add-server-cert` -a -x `which ${exec_prefix}stap-add-server-cert`; then
- ${exec_prefix}stap-add-server-cert $ssl_db/stap-server.cert `dirname $ssl_db`/client
+ if test -f `which ${stap_exec_prefix}stap-client` -a \
+ -x `which ${stap_exec_prefix}stap-client`; then
+ ${stap_exec_prefix}stap-authorize-server-cert $ssl_db/$stap_certfile
+ fi
+ elif ! test -f $stap_ssl_db/client/cert8.db; then
+ # If the client's database does not exist, then initialize it with our certificate.
+ # Do this only if the client has been installed.
+ if test -f `which ${stap_exec_prefix}stap-client` -a \
+ -x `which ${stap_exec_prefix}stap-client`; then
+ ${stap_exec_prefix}stap-authorize-server-cert $ssl_db/$stap_certfile
fi
fi
fi
@@ -78,7 +84,7 @@ function advertise_presence {
# Call avahi-publish-service to advertise our presence.
avahi-publish-service "Systemtap Compile Server on `uname -n`" \
- $avahi_type $port "$txt" > /dev/null 2>&1 &
+ $stap_avahi_service_tag $port "$txt" > /dev/null 2>&1 &
echo "Systemtap Compile Server on `uname -n` listening on port $port"
}
@@ -89,8 +95,8 @@ function advertise_presence {
function listen {
# The stap-server-connect program will listen forever
# accepting requests.
- ${exec_prefix}stap-server-connect -p $port -n $nss_cert -d $ssl_db -w $nss_pw 2>&1 &
- wait '%${exec_prefix}stap-server-connect' >/dev/null 2>&1
+ ${stap_exec_prefix}stap-server-connect -p $port -n $nss_cert -d $ssl_db -w $nss_pw 2>&1 &
+ wait '%${stap_exec_prefix}stap-server-connect' >/dev/null 2>&1
}
# function: check_db DBNAME
@@ -160,7 +166,7 @@ function check_db {
check_db_file $dir/key3.db || rc=1
check_db_file $dir/secmod.db || rc=1
check_db_file $dir/pw || rc=1
- check_cert_file $dir/stap-server.cert || rc=1
+ check_cert_file $dir/$stap_certfile || rc=1
test $rc = 1 && fatal "Unable to use certificate database '$dir' due to errors"
@@ -328,8 +334,8 @@ function terminate {
wait '%avahi-publish-service' >/dev/null 2>&1
# Kill any running 'stap-server-connect' job.
- kill -s SIGTERM '%${exec_prefix}stap-server-connect' 2> /dev/null
- wait '%${exec_prefix}stap-server-connect' >/dev/null 2>&1
+ kill -s SIGTERM '%${stap_exec_prefix}stap-server-connect' 2> /dev/null
+ wait '%${stap_exec_prefix}stap-server-connect' >/dev/null 2>&1
exit
}
diff --git a/stap-start-server b/stap-start-server
index d718ed30..6471db96 100755
--- a/stap-start-server
+++ b/stap-start-server
@@ -12,14 +12,11 @@
# This script attempts to start a systemtap server and echoes the
# process id, if successful.
-# INSTALL-HOOK These settings work for running the client from the source tree
-# INSTALL-HOOK using the dejagnu test harness and will be overridden at install
-# INSTALL-HOOK time.
-exec_prefix=
-sysconfdir=`pwd`/net
+# Initialize the environment
+. `dirname $0`/stap-env
# start the server
-${exec_prefix}stap-serverd "$@" </dev/null >/dev/null 2>&1 &
+${stap_exec_prefix}stap-serverd "$@" </dev/null >/dev/null 2>&1 &
server_pid=$!
# Make sure the server is started
@@ -30,6 +27,7 @@ do
sleep 1
continue
fi
+
# Is avahi advertizing the server?
if ! (ps -fa | grep avahi-publish-service | grep $server_pid) > /dev/null 2>&1; then
sleep 1
diff --git a/stap.1.in b/stap.1.in
index 5a2e35f9..7736a612 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -150,18 +150,23 @@ Add the given directory to the tapset search directory. See the
description of pass 2 for details.
.TP
.BI \-D " NAME=VALUE"
-Add the given C preprocessor directive to the module Makefile. These can
+Add the given C preprocessor directive to the module Makefile. These can
be used to override limit parameters described below.
.TP
.BI \-R " DIR"
Look for the systemtap runtime sources in the given directory.
.TP
.BI \-r " /DIR"
-Build for kernel in given build tree.
+Build for kernel in given build tree. Can also be set with the
+.I SYSTEMTAP_RELEASE
+environment variable.
.TP
.BI \-r " RELEASE"
Build for kernel in build tree
-.BR /lib/modules/RELEASE/build .
+.BR /lib/modules/RELEASE/build .
+Can also be set with the
+.I SYSTEMTAP_RELEASE
+environment variable.
.TP
.BI \-m " MODULE"
Use the given name for the generated kernel object module, instead
@@ -175,13 +180,14 @@ even if they do not have an explicit probe placed into them.
.TP
.BI \-o " FILE"
Send standard output to named file. In bulk mode, percpu files will
-start with FILE_ followed by the cpu number.
+start with FILE_ (FILE_cpu with -F) followed by the cpu number.
+This supports strftime(3) formats for FILE.
.TP
.BI \-c " CMD"
Start the probes, run CMD, and exit when CMD finishes.
.TP
.BI \-x " PID"
-Sets target() to PID. This allows scripts to be written that filter on
+Sets target() to PID. This allows scripts to be written that filter on
a specific process.
.TP
.BI \-l " PROBE"
@@ -193,8 +199,18 @@ and aliases.
Similar to "-l", but list probe points and script-level local variables.
.TP
.BI \-F
-Load module and start probes, then detach from the module leaving the
-probes running.
+Without -o option, load module and start probes, then detach from the module
+leaving the probes running.
+With -o option, run staprun in background as a daemon and show its pid.
+.TP
+.BI \-S " size[,N]"
+Sets the maximum size of output file and the maximum number of output files.
+If the size of output file will exceed
+.B size
+, systemtap switches output file to the next file. And if the number of
+output files exceed
+.B N
+, systemtap removes the oldest output file. You can omit the second argument.
.TP
.B \-\-kelf
For names and addresses of functions to probe,
@@ -241,7 +257,7 @@ parser for substitution. See below.
.SH SCRIPT LANGUAGE
-The systemtap script language resembles
+The systemtap script language resembles
.IR awk .
There are two main outermost constructs: probes and functions. Within
these, statements and expressions use C-like operator syntax and
@@ -280,7 +296,7 @@ number beyond what was actually given is an error.
.SS PREPROCESSING
A simple conditional preprocessing stage is run as a part of parsing.
-The general form is similar to the
+The general form is similar to the
.RB cond " ? " exp1 " : " exp2
ternary operator:
.SAMPLE
@@ -304,7 +320,7 @@ version of the target kernel (as optionally overridden by the
option) compares to the given version string. The comparison is
performed by the glibc function
.BR strverscmp .
-As a special case, if the operator is for simple equality
+As a special case, if the operator is for simple equality
.RB ( == ),
or inequality
.RB ( != ),
@@ -336,14 +352,14 @@ kernel version is newer than 2.6.5:
.ESAMPLE
The following code might adapt to hypothetical kernel version drift:
.SAMPLE
-probe kernel.function (
- %( kernel_v <= "2.6.12" %? "__mm_do_fault" %:
+probe kernel.function (
+ %( kernel_v <= "2.6.12" %? "__mm_do_fault" %:
%( kernel_vr == "2.6.13*smp" %? "do_page_fault" %:
UNSUPPORTED %) %)
) { /* ... */ }
%( arch == "ia64" %?
- probe syscall.vliw = kernel.function("vliw_widget") {}
+ probe syscall.vliw = kernel.function("vliw_widget") {}
%)
.ESAMPLE
@@ -411,7 +427,7 @@ Execute the string- or integer-valued expression and throw away
the value.
.TP
.BR { " STMT1 STMT2 ... " }
-Execute each statement in sequence in this block. Note that
+Execute each statement in sequence in this block. Note that
separators or terminators are generally not necessary between statements.
.TP
.BR ;
@@ -433,14 +449,14 @@ STMT, then the iteration expression EXP3.
.BR foreach " (VAR " in " ARRAY [ "limit " EXP ]) STMT"
Loop over each element of the named global array, assigning current
key to VAR. The array may not be modified within the statement.
-By adding a single
+By adding a single
.BR + " or " \-
operator after the VAR or the ARRAY identifier, the iteration will
proceed in a sorted order, by ascending or descending index or value.
Using the optional
-.BR limit
+.BR limit
keyword limits the number of loop iterations to EXP times. EXP is
-evaluted once at the beginning of the loop.
+evaluated once at the beginning of the loop.
.TP
.BR foreach " ([VAR1, VAR2, ...] " in " ARRAY [ "limit " EXP ]) STMT"
Same as above, used when the array is indexed with a tuple of keys.
@@ -491,7 +507,7 @@ string assignment operators
.B = .=
.TP
unary numeric operators
-.B + \- ! ~ ++ \-\-
+.B + \- ! ~ ++ \-\-
.TP
binary numeric or string comparison operators
.B < > <= >= == !=
@@ -523,14 +539,14 @@ Events are specified in a special syntax called "probe points". There
are several varieties of probe points defined by the translator, and
tapset scripts may define further ones using aliases. These are
listed in the
-.IR stapprobes (5)
+.IR stapprobes (3stap)
manual pages.
.PP
The probe handler is interpreted relative to the context of each
event. For events associated with kernel code, this context may
include
.I variables
-defined in the
+defined in the
.I source code
at that spot. These "target variables" are presented to the script as
variables whose names are prefixed with "$". They may be accessed
@@ -541,9 +557,9 @@ with optimized code. Some other events have very little context.
New probe points may be defined using "aliases". Probe point aliases
look similar to probe definitions, but instead of activating a probe
at the given point, it just defines a new probe point name as an alias
-to an existing one. There are two types of alias, i.e. the prologue
+to an existing one. There are two types of alias, i.e. the prologue
style and the epilogue style which are identified by "=" and "+="
-respectively.
+respectively.
.PP
For prologue style alias, the statement block that follows an alias
definition is implicitly added as a prologue to any probe that refers
@@ -643,9 +659,9 @@ The
.IR printf
formatting directives similar to those of C, except that they are
fully type-checked by the translator:
-.RS
+.RS
.TP
-%b
+%b
Writes a binary blob of the value given, instead of ASCII text. The width specifier determines the number of bytes to write; valid specifiers are %b %1b %2b %4b %8b. Default (%b) is 8 bytes.
.TP
%c
@@ -658,7 +674,7 @@ Signed decimal.
Safely reads kernel memory at the given address, outputs its content. The precision specifier determines the number of bytes to read. Default is 1 byte.
.TP
%M
-Same as %m, but outputs in hexadecimal. The precision specifier determines the number of hexadecimal digits to output. Default is 1 digit.
+Same as %m, but outputs in hexadecimal. The minimal size of output is double the precision specifier.
.TP
%o
Unsigned octal.
@@ -726,7 +742,7 @@ distinct extraction function operating on a given identifier, the
translator arranges to compute a set of statistics that satisfy it.
The statistics system is thereby "on-demand". Each execution of
an extraction function causes the aggregation to be computed for
-that moment across all processors.
+that moment across all processors.
.PP
Here is the set of extractor functions. The first argument of each is
the same style of lvalue used on the left hand side of the accumulate
@@ -739,7 +755,7 @@ integers.
Histograms are also available, but are more complicated because they
have a vector rather than scalar value.
.I @hist_linear(v,start,stop,interval)
-represents a linear histogram from "start" to "stop" by increments
+represents a linear histogram from "start" to "stop" by increments
of "interval". The interval must be positive. Similarly,
.I @hist_log(v)
represents a base-2 logarithmic histogram. Printing a histogram
@@ -751,7 +767,7 @@ family of functions renders a histogram object as a tabular
probe foo {
x <<< $value
}
-probe end {
+probe end {
printf ("avg %d = sum %d / count %d\\n",
@avg(x), @sum(x), @count(x))
print (@hist_log(v))
@@ -776,10 +792,21 @@ and dereference the
.I member
value. The optional
.I module
-tells the translator where to look for information about that type. If
-the module is not specified, it will default either to the probe module
-for dwarf probes, or to "kernel" for functions and all other probes
-types.
+tells the translator where to look for information about that type.
+Multiple modules may be specified as a list with
+.IR :
+separators. If the module is not specified, it will default either to
+the probe module for dwarf probes, or to "kernel" for functions and all
+other probes types.
+.PP
+The translator can create its own module with type information from a header
+surrounded by angle brackets, in case normal debuginfo is not available. For
+kernel headers, prefix it with "kernel" to use the appropriate build system.
+All other headers are build with default GCC parameters into a user module.
+.SAMPLE
+@cast(tv, "timeval", "<sys/time.h>")->tv_sec
+@cast(task, "task_struct", "kernel<linux/sched.h>")->tgid
+.ESAMPLE
.PP
When in guru mode, the translator will also allow scripts to assign new
values to members of typecasted pointers.
@@ -809,7 +836,7 @@ sequence, into the generated C code. At the outermost level, this may
be useful to add
.IR #include
instructions, and any auxiliary definitions for use by other embedded
-code.
+code.
.PP
The other place where embedded code is permitted is as a function body.
In this case, the script language body is replaced entirely by a piece
@@ -846,7 +873,7 @@ by the scripts installed under the
.IR @prefix@/share/systemtap/tapset
.hy
directory. These are described in the
-.IR stapfuncs "(5) and " stapprobes (5)
+.IR stapfuncs "(3stap) and " stapprobes (3stap)
manual pages.
.SH PROCESSING
@@ -870,7 +897,7 @@ the following patterns would be searched, in sequence:
.IR 2.6/*.stp ,
and finally
.IR *.stp
-Stopping the translator after pass 1 causes it to print the parse trees.
+Stopping the translator after pass 1 causes it to print the parse trees.
.PP
In pass 2, the translator analyzes the input script to resolve symbols
@@ -882,7 +909,7 @@ added to the translator's resolution queue. This process iterates
until all symbols are resolved and a subset of tapset scripts is
selected.
.PP
-Next, all probe point descriptions are validated
+Next, all probe point descriptions are validated
against the wide variety supported by the translator. Probe points that
refer to code locations ("synchronous probe points") require the
appropriate kernel debugging information to be installed. In the
@@ -899,7 +926,7 @@ Since this optimization can hide latent code errors such as type
mismatches or invalid $target variables, it sometimes may be useful
to disable the optimizations with the
.BR \-u
-option.
+option.
.PP
Finally, all variable, function, parameter, array, and index types are
inferred from context (literals and operators). Stopping the
@@ -942,8 +969,8 @@ Finally,
unloads the module, and cleans up.
.SH EXAMPLES
-See the
-.IR stapex (5)
+See the
+.IR stapex (3stap)
manual page for a collection of samples.
.SH CACHING
@@ -956,10 +983,10 @@ the
.I $SYSTEMTAP_DIR/cache
directory. The cache can be limited by having the file
.I cache_mb_limit
-placed in the cache directory (shown above) containing only an ASCII
+placed in the cache directory (shown above) containing only an ASCII
integer representing how many MiB the cache should not exceed. Note that
this is a 'soft' limit in that the cache will be cleaned after a new entry
-is added, so the total cache size may temporarily exceed this limit. In the
+is added, so the total cache size may temporarily exceed this limit. In the
absence of this file, a default will be created with the limit set to 64MiB.
.SH SAFETY AND SECURITY
@@ -991,11 +1018,11 @@ program are run by the
.IR staprun
program. The latter is a part of the Systemtap package, dedicated to
module loading and unloading (but only in the white zone), and
-kernel-to-user data transfer. Since
+kernel-to-user data transfer. Since
.IR staprun
does not perform any additional security checks on the kernel objects
it is given, it would be unwise for a system administrator to add
-untrusted users to the
+untrusted users to the
.I stapdev
or
.I stapusr
@@ -1012,7 +1039,7 @@ to kernel crash or data corruption.
The resource use limits are set by macros in the generated C code.
These may be overridden with the
.BR \-D
-flag. A selection of these is as follows:
+flag. A selection of these is as follows:
.TP
MAXNESTING
Maximum number of recursive function call levels, default 10.
@@ -1044,7 +1071,8 @@ means that the first error will exit the script.
MAXSKIPPED
Maximum number of skipped probes before an exit is triggered, default 100.
Running systemtap with \-t (timing) mode gives more details about skipped
-probes.
+probes. With the default \-DINTERRUPTIBLE=1 setting, probes skipped due to
+reentrancy are not accumulated against this limit.
.TP
MINSTACKSPACE
Minimum number of free kernel stack bytes required in order to
@@ -1084,7 +1112,7 @@ Note that you must unload guests before unloading a host. If there are some
guests connected to the host, unloading the host will be failed.
.PP
-In case something goes wrong with
+In case something goes wrong with
.IR stap " or " staprun
after a probe has already started running, one may safely kill both
user processes, and remove the active probe kernel module with
@@ -1158,7 +1186,7 @@ environment variable.
Temporary directory for systemtap files, including translated C code
and kernel object.
.TP
-@prefix@/share/systemtap/tapset
+@prefix@/share/systemtap/tapset
The automatic tapset search directory, unless overridden by
the
.I SYSTEMTAP_TAPSET
@@ -1187,10 +1215,10 @@ The auxiliary program supervising module loading, interaction, and
unloading.
.SH SEE ALSO
-.IR stapprobes (5),
-.IR stapfuncs (5),
-.IR stapvars (5),
-.IR stapex (5),
+.IR stapprobes (3stap),
+.IR stapfuncs (3stap),
+.IR stapvars (3stap),
+.IR stapex (3stap),
.IR awk (1),
.IR gdb (1)
diff --git a/stapex.5.in b/stapex.3stap.in
index 38f30f62..8d02fc5c 100644
--- a/stapex.5.in
+++ b/stapex.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPEX 5 @DATE@ "Red Hat"
+.TH STAPEX 3stap @DATE@ "Red Hat"
.SH NAME
stapex \- systemtap examples
@@ -121,6 +121,6 @@ it is ordinarily run.
.SH SEE ALSO
.BR @prefix@/doc/systemtap*/examples
.IR stap (1)
-.IR stapprobes (5)
-.IR stapfuncs (5)
+.IR stapprobes (3stap)
+.IR stapfuncs (3stap)
diff --git a/stapfuncs.5.in b/stapfuncs.3stap.in
index 0322369e..b9326fde 100644
--- a/stapfuncs.5.in
+++ b/stapfuncs.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPFUNCS 5 @DATE@ "Red Hat"
+.TH STAPFUNCS 3stap @DATE@ "Red Hat"
.SH NAME
stapfuncs \- systemtap functions
@@ -154,6 +154,9 @@ Return the number of characters in str.
substr:string (str:string,start:long, stop:long)
Return the substring of str starting from character start and ending at character stop.
.TP
+stringat:string (str:string,pos:long)
+Return the character in given position of string.
+.TP
isinstr:long (s1:string, s2:string)
Return 1 if string s1 contains string s2, returns 0 otherwise.
.TP
@@ -346,6 +349,14 @@ Return the number of open file handles for the given task.
task_max_file_handles:long(task:long)
Return the maximum number of file handles for the given task.
+.TP
+pid2task:long(pid:long)
+Return the task of the given process id.
+
+.TP
+pid2execname:string(pid:long)
+Return the name of the given process id.
+
.SS CPU REGISTERS
.TP
registers_valid:long ()
@@ -565,7 +576,7 @@ the handle being used for that event.
These functions convert arguments in the socket tapset back and
forth between their numeric and string representations.
See
-.IR stapprobes.socket (5)
+.IR stapprobes.socket (3stap)
for details.
.TP
diff --git a/stapprobes.5.in b/stapprobes.3stap.in
index 70d045c4..795a9a92 100644
--- a/stapprobes.5.in
+++ b/stapprobes.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPPROBES 5 @DATE@ "Red Hat"
+.TH STAPPROBES 3stap @DATE@ "Red Hat"
.SH NAME
stapprobes \- systemtap probe points
@@ -37,7 +37,7 @@ that it is optional, and that no error should result if it fails to
resolve. Optionalness passes down through all levels of
alias/wildcard expansion. Alternately, a probe point may be followed
by a "!" character, to indicate that it is both optional and
-sufficient. (Think vaguely of the prolog cut operator.) If it does
+sufficient. (Think vaguely of the Prolog cut operator.) If it does
resolve, then no further probe points in the same comma-separated list
will be resolved. Therefore, the "!" sufficiency mark only makes
sense in a list of probe point alternatives.
@@ -49,19 +49,25 @@ including alias's body is skipped. The condition is stacked up through
all levels of alias/wildcard expansion. So the final condition becomes
the logical-and of conditions of all expanded alias/wildcard.
-These are all syntactically valid probe points:
+These are all
+.B syntactically
+valid probe points. (They are generally
+.B semantically
+invalid, depending on the contents of the tapsets, and the versions of
+kernel/user software installed.)
.SAMPLE
kernel.function("foo").return
-syscall(22)
-user.inode("/bin/vi").statement(0x2222)
+process("/bin/vi").statement(0x2222)
end
syscall.*
kernel.function("no_such_function") ?
module("awol").function("no_such_function") !
signal.*? if (switch)
+kprobe.function("foo")
.ESAMPLE
+
Probes may be broadly classified into "synchronous" and
"asynchronous". A "synchronous" event is deemed to occur when any
processor executes an instruction matched by the specification. This
@@ -109,7 +115,7 @@ probe point is similar to the
.IR end
probe, except that each such probe handler run when the session ends
after errors have occurred. In such cases, "end" probes are skipped,
-but each "error" prober is still attempted. This kind of probe can be
+but each "error" probe is still attempted. This kind of probe can be
used to clean up or emit a "final gasp". It may also be numerically
parametrized to set a sequence.
@@ -373,9 +379,47 @@ Other local variables are not generally accessible, since by the time
a ".return" probe hits, the probed function will have already returned.
+.SS DWARFLESS
+In absence of debugging information, entry & exit points of kernel & module
+functions can be probed using the "kprobe" family of probes.
+However, these do not permit looking up the arguments / local variables
+of the function.
+Following constructs are supported :
+.SAMPLE
+kprobe.function(FUNCTION)
+kprobe.function(FUNCTION).return
+kprobe.module(NAME).function(FUNCTION)
+kprobe.module(NAME).function(FUNCTION).return
+kprobe.statement.(ADDRESS).absolute
+.ESAMPLE
+.PP
+Probes of type
+.B function
+are recommended for kernel functions, whereas probes of type
+.B module
+are recommended for probing functions of the specified module.
+In case the absolute address of a kernel or module function is known,
+.B statement
+probes can be utilized.
+.PP
+Note that
+.I FUNCTION
+and
+.I MODULE
+names
+.B must not
+contain wildcards, or the probe will not be registered.
+Also, statement probes must be run under guru-mode only.
+
+
.SS USER-SPACE
-Early prototype support for user-space probing is available in the
-form of a non-symbolic probe point:
+Support for user-space probing is available for kernels
+that are configured with the utrace extensions. See
+.SAMPLE
+http://people.redhat.com/roland/utrace/
+.ESAMPLE
+.PP
+There are several forms. First, a non-symbolic probe point:
.SAMPLE
process(PID).statement(ADDRESS).absolute
.ESAMPLE
@@ -387,7 +431,8 @@ 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:
+Second, non-symbolic user-kernel interface events handled by
+utrace may be probed:
.SAMPLE
process(PID).begin
process("PATH").begin
@@ -407,9 +452,10 @@ process.syscall
process(PID).syscall.return
process("PATH").syscall.return
process.syscall.return
-process(PID).itrace
-process("PATH").itrace
-process("PATH").mark("LABEL")
+process(PID).insn
+process("PATH").insn
+process(PID).insn.block
+process("PATH").insn.block
.ESAMPLE
.PP
A
@@ -443,8 +489,20 @@ in the
.BR $return
context variable.
A
-.B .itrace
-probe gets called for every single step of the process described by PID or PATH.
+.B .insn
+probe gets called for every single-stepped instruction of the process described by PID or PATH.
+A
+.B .insn.block
+probe gets called for every block-stepped instruction of the process described by PID or PATH.
+
+.PP
+Third, symbolic static instrumentation compiled into programs and
+shared libraries may be
+probed:
+.SAMPLE
+process("PATH").mark("LABEL")
+.ESAMPLE
+.PP
A
.B .mark
probe gets called via a static probe which is defined in the
@@ -456,14 +514,29 @@ for probes with 2 arguments, and so on.
The arguments of the probe are available in the context variables
$arg1, $arg2, ... An alternative to using the STAP_PROBE macros is to
use the dtrace script to create custom macros.
+
.PP
-Note that
+Finally, full symbolic source-level probes in user-space programs
+and shared libraries are supported. These are exactly analogous
+to the symbolic DWARF-based kernel/module probes described above,
+and expose similar contextual $-variables.
+.SAMPLE
+process("PATH").function("NAME")
+process("PATH").statement("*@FILE.c:123")
+process("PATH").function("*").return
+process("PATH").function("myfun").label("foo")
+.ESAMPLE
+
+.PP
+Note that for all process probes,
.I PATH
names refer to executables that are searched the same way shells do: relative
to the working directory if they contain a "/" character, otherwise in
.BR $PATH .
If a process probe is specified without a PID or PATH, all user
-threads are probed.
+threads are probed. PATH may sometimes name a shared library
+in which case all processes that map that shared library may be
+probed.
.SS PROCFS
@@ -533,7 +606,7 @@ The marker name string, which may contain the usual wildcard characters,
is matched against the names given to the marker macros when the kernel
and/or module was compiled. Optionally, you can specify
.BR format("format") .
-Specifying the marker format string allows differentation between two
+Specifying the marker format string allows differentiation between two
markers with the same name but different marker format strings.
The handler associated with a marker-based probe may read the
@@ -545,7 +618,7 @@ and string parameters are passed in a type-safe manner.
The marker format string associated with a marker is available in
.BR $format .
-And also the marker name string is avalable in
+And also the marker name string is available in
.BR $name .
.SS TRACEPOINTS
@@ -596,10 +669,10 @@ Performance monitor hardware points begin with a
The next part of the names the event being counted
.BR counter("event") .
The event names are processor implementation specific with the
-execption of the generic
+exception of the generic
.BR cycles " and " instructions
events, which are available on all processors. This sets up a counter
-on the processor to count the number of events occuring on the
+on the processor to count the number of events occurring on the
processor. For more details on the performance monitoring events
available on a specific processor use the command perfmon2 command:
@@ -656,16 +729,16 @@ refers to the group of probe aliases with any name in the third position
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes.iosched (5),
-.IR stapprobes.netdev (5),
-.IR stapprobes.nfs (5),
-.IR stapprobes.nfsd (5),
-.IR stapprobes.pagefault (5),
-.IR stapprobes.process (5),
-.IR stapprobes.rpc (5),
-.IR stapprobes.scsi (5),
-.IR stapprobes.signal (5),
-.IR stapprobes.socket (5),
-.IR stapprobes.tcp (5),
-.IR stapprobes.udp (5),
-.IR proc (5)
+.IR stapprobes.iosched (3stap),
+.IR stapprobes.netdev (3stap),
+.IR stapprobes.nfs (3stap),
+.IR stapprobes.nfsd (3stap),
+.IR stapprobes.pagefault (3stap),
+.IR stapprobes.process (3stap),
+.IR stapprobes.rpc (3stap),
+.IR stapprobes.scsi (3stap),
+.IR stapprobes.signal (3stap),
+.IR stapprobes.socket (3stap),
+.IR stapprobes.tcp (3stap),
+.IR stapprobes.udp (3stap),
+.IR proc (3stap)
diff --git a/staprun.8.in b/staprun.8.in
index c7e77dc4..5fe2e7fa 100644
--- a/staprun.8.in
+++ b/staprun.8.in
@@ -52,7 +52,9 @@ The '_stp_target' variable will be set to PID.
.TP
.B \-o FILE
Send output to FILE. If the module uses bulk mode, the output will
-be in percpu files FILE_x where 'x' is the cpu number.
+be in percpu files FILE_x(FILE_cpux in background and bulk mode)
+where 'x' is the cpu number. This supports strftime(3) formats
+for FILE.
.TP
.B \-b BUFFER_SIZE
The systemtap module will specify a buffer size.
@@ -73,6 +75,18 @@ Attach to loaded systemtap module.
Delete a module. Only detached or unused modules
the user has permission to access will be deleted. Use "*"
(quoted) to delete all unused modules.
+.TP
+.BI \-D
+Run staprun in background as a daemon and show it's pid.
+.TP
+.BI \-S " size[,N]"
+Sets the maximum size of output file and the maximum number of output files.
+If the size of output file will exceed
+.B size
+, systemtap switches output file to the next file. And if the number of
+output files exceed
+.B N
+, systemtap removes the oldest output file. You can omit the second argument.
.SH ARGUMENTS
.B MODULE
@@ -88,7 +102,7 @@ module.
.SH EXAMPLES
See the
-.IR stapex (5)
+.IR stapex (3stap)
manual page for a collection of sample scripts.
.PP
Here is a very basic example of how to use
@@ -152,9 +166,9 @@ located in this directory. This directory should be owned by the root
user and not be world writable.
.SH SEE ALSO
.IR stap (1),
-.IR stapprobes (5),
-.IR stapfuncs (5),
-.IR stapex (5),
+.IR stapprobes (3stap),
+.IR stapfuncs (3stap),
+.IR stapex (3stap),
.SH BUGS
Use the Bugzilla link off of the project web page or our mailing list.
diff --git a/staptree.h b/staptree.h
index 5125cd85..7e9506bb 100644
--- a/staptree.h
+++ b/staptree.h
@@ -231,6 +231,7 @@ struct target_symbol: public symbol
};
std::string base_name;
std::vector<std::pair<component_type, std::string> > components;
+ std::string probe_context_var;
semantic_error* saved_conversion_error;
target_symbol(): saved_conversion_error (0) {}
void print (std::ostream& o) const;
diff --git a/stapvars.5.in b/stapvars.3stap.in
index 94e47667..0ece000f 100644
--- a/stapvars.5.in
+++ b/stapvars.3stap.in
@@ -1,5 +1,5 @@
.\" -*- nroff -*-
-.TH STAPVARS 5 @DATE@ "Red Hat"
+.TH STAPVARS 3stap @DATE@ "Red Hat"
.SH NAME
stapvars \- systemtap variables
diff --git a/systemtap.spec b/systemtap.spec
index 7277f92a..5b9283cf 100644
--- a/systemtap.spec
+++ b/systemtap.spec
@@ -1,14 +1,14 @@
-%{!?release: %define release 1}
%{!?with_sqlite: %define with_sqlite 1}
%{!?with_docs: %define with_docs 1}
%{!?with_crash: %define with_crash 0}
%{!?with_bundled_elfutils: %define with_bundled_elfutils 0}
%{!?elfutils_version: %define elfutils_version 0.127}
+%{!?pie_supported: %define pie_supported 1}
Name: systemtap
+Version: 0.9.7
+Release: 1%{?dist}
# for version, see also configure.ac
-Version: 0.9
-Release: %{release}%{?dist}
Summary: Instrumentation System
Group: Development/System
License: GPLv2+
@@ -30,7 +30,7 @@ Requires: kernel-devel
Requires: gcc make
# Suggest: kernel-debuginfo
Requires: systemtap-runtime = %{version}-%{release}
-BuildRequires: nss-devel
+BuildRequires: nss-devel nss-tools pkgconfig
%if %{with_bundled_elfutils}
Source1: elfutils-%{elfutils_version}.tar.gz
@@ -176,9 +176,15 @@ cd ..
%define docs_config --disable-docs
%endif
+# Enable pie as configure defaults to disabling it
+%if %{pie_supported}
+%define pie_config --enable-pie
+%else
+%define pie_config --disable-pie
+%endif
-%configure %{?elfutils_config} %{sqlite_config} %{crash_config} %{docs_config}
+%configure %{?elfutils_config} %{sqlite_config} %{crash_config} %{docs_config} %{pie_config}
make %{?_smp_mflags}
%install
@@ -250,8 +256,12 @@ exit 0
%{_bindir}/stap
%{_bindir}/stap-report
+%{_bindir}/stap-env
+%{_bindir}/stap-gen-cert
+%{_bindir}/stap-authorize-cert
+%{_bindir}/stap-authorize-signing-cert
%{_mandir}/man1/*
-%{_mandir}/man5/*
+%{_mandir}/man3/*
%dir %{_datadir}/%{name}
%{_datadir}/%{name}/runtime
@@ -283,9 +293,8 @@ exit 0
%files client
%defattr(-,root,root)
%{_bindir}/stap-client
+%{_bindir}/stap-env
%{_bindir}/stap-find-servers
-%{_bindir}/stap-find-or-start-server
-%{_bindir}/stap-add-server-cert
%{_bindir}/stap-client-connect
%{_mandir}/man8/stap-server.8*
@@ -293,9 +302,14 @@ exit 0
%defattr(-,root,root)
%{_bindir}/stap-server
%{_bindir}/stap-serverd
+%{_bindir}/stap-env
%{_bindir}/stap-start-server
+%{_bindir}/stap-find-servers
+%{_bindir}/stap-find-or-start-server
%{_bindir}/stap-stop-server
-%{_bindir}/stap-gen-server-cert
+%{_bindir}/stap-gen-cert
+%{_bindir}/stap-authorize-cert
+%{_bindir}/stap-authorize-server-cert
%{_bindir}/stap-server-connect
%{_mandir}/man8/stap-server.8*
@@ -317,6 +331,15 @@ exit 0
%changelog
+* Thu Apr 23 2009 Josh Stone <jistone@redhat.com> - 0.9.7-1
+- Upstream release.
+
+* Fri Mar 27 2009 Josh Stone <jistone@redhat.com> - 0.9.5-1
+- Upstream release.
+
+* Wed Mar 18 2009 Will Cohen <wcohen@redhat.com> - 0.9-2
+- Add location of man pages.
+
* Tue Feb 17 2009 Frank Ch. Eigler <fche@redhat.com> - 0.9-1
- Upstream release.
diff --git a/tapset-been.cxx b/tapset-been.cxx
new file mode 100644
index 00000000..e007a4f7
--- /dev/null
+++ b/tapset-been.cxx
@@ -0,0 +1,228 @@
+// tapset for begin/end/error/never
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "translate.h"
+#include "util.h"
+
+#include <algorithm>
+#include <string>
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+static string TOK_BEGIN("begin");
+static string TOK_END("end");
+static string TOK_ERROR("error");
+static string TOK_NEVER("never");
+
+
+// ------------------------------------------------------------------------
+// begin/end/error probes are run right during registration / deregistration
+// ------------------------------------------------------------------------
+
+enum be_t { BEGIN, END, ERROR };
+
+struct be_derived_probe: public derived_probe
+{
+ be_t type;
+ int64_t priority;
+
+ be_derived_probe (probe* p, probe_point* l, be_t t, int64_t pr):
+ derived_probe (p, l), type (t), priority (pr) {}
+
+ void join_group (systemtap_session& s);
+
+ static inline bool comp(be_derived_probe const *a,
+ be_derived_probe const *b)
+ {
+ // This allows the BEGIN/END/ERROR probes to intermingle.
+ // But that's OK - they're always treversed with a nested
+ // "if (type==FOO)" conditional.
+ return a->priority < b->priority;
+ }
+
+ bool needs_global_locks () { return false; }
+ // begin/end probes don't need locks around global variables, since
+ // they aren't run concurrently with any other probes
+};
+
+
+struct be_derived_probe_group: public generic_dpg<be_derived_probe>
+{
+public:
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+struct be_builder: public derived_probe_builder
+{
+ be_t type;
+
+ be_builder(be_t t) : type(t) {}
+
+ virtual void build(systemtap_session &,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+ {
+ int64_t priority;
+ if ((type == BEGIN && !get_param(parameters, TOK_BEGIN, priority)) ||
+ (type == END && !get_param(parameters, TOK_END, priority)) ||
+ (type == ERROR && !get_param(parameters, TOK_ERROR, priority)))
+ priority = 0;
+ finished_results.push_back
+ (new be_derived_probe(base, location, type, priority));
+ }
+};
+
+
+void
+be_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.be_derived_probes)
+ s.be_derived_probes = new be_derived_probe_group ();
+ s.be_derived_probes->enroll (this);
+}
+
+
+void
+be_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ map<be_t, const char *> states;
+ states[BEGIN] = "STAP_SESSION_STARTING";
+ states[END] = "STAP_SESSION_STOPPING";
+ states[ERROR] = "STAP_SESSION_ERROR";
+
+ s.op->newline() << "/* ---- begin/end/error probes ---- */";
+
+ // NB: We emit the table in sorted order here, so we don't have to
+ // store the priority numbers as integers and sort at run time.
+
+ sort(probes.begin(), probes.end(), be_derived_probe::comp);
+
+ s.op->newline() << "static struct stap_be_probe {";
+ s.op->newline(1) << "void (*ph)(struct context*);";
+ s.op->newline() << "const char* pp;";
+ s.op->newline() << "int state, type;";
+ s.op->newline(-1) << "} stap_be_probes[] = {";
+ s.op->indent(1);
+
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ s.op->newline () << "{";
+ s.op->line() << " .pp="
+ << lex_cast_qstring (*probes[i]->sole_location()) << ",";
+ s.op->line() << " .ph=&" << probes[i]->name << ",";
+ s.op->line() << " .state=" << states[probes[i]->type] << ",";
+ s.op->line() << " .type=" << probes[i]->type;
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+
+ s.op->newline() << "static void enter_be_probe (struct stap_be_probe *stp) {";
+ s.op->indent(1);
+ common_probe_entryfn_prologue (s.op, "stp->state", "stp->pp", false);
+ s.op->newline() << "(*stp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op, false);
+ s.op->newline(-1) << "}";
+}
+
+void
+be_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
+ s.op->newline() << "if (stp->type == " << BEGIN << ")";
+ s.op->newline(1) << "enter_be_probe (stp); /* rc = 0 */";
+ // NB: begin probes that cause errors do not constitute registration
+ // failures. An error message will probably get printed and if
+ // MAXERRORS was left at 1, we'll get an stp_exit. The
+ // error-handling probes will be run during the ordinary
+ // unregistration phase.
+ s.op->newline(-2) << "}";
+}
+
+void
+be_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
+ s.op->newline() << "if (stp->type == " << END << ")";
+ s.op->newline(1) << "enter_be_probe (stp);";
+ s.op->newline(-2) << "}";
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
+ s.op->newline() << "if (stp->type == " << ERROR << ")";
+ s.op->newline(1) << "enter_be_probe (stp);";
+ s.op->newline(-2) << "}";
+}
+
+
+
+// ------------------------------------------------------------------------
+// never probes are never run
+// ------------------------------------------------------------------------
+
+struct never_derived_probe: public derived_probe
+{
+ never_derived_probe (probe* p): derived_probe (p) {}
+ never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {}
+ void join_group (systemtap_session&) { /* thus no probe_group */ }
+};
+
+
+struct never_builder: public derived_probe_builder
+{
+ never_builder() {}
+ virtual void build(systemtap_session &,
+ probe * base,
+ probe_point * location,
+ literal_map_t const &,
+ vector<derived_probe *> & finished_results)
+ {
+ finished_results.push_back(new never_derived_probe(base, location));
+ }
+};
+
+
+
+// ------------------------------------------------------------------------
+// unified registration for begin/end/error/never
+// ------------------------------------------------------------------------
+
+void
+register_tapset_been(systemtap_session& s)
+{
+ match_node* root = s.pattern_root;
+
+ root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN));
+ root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN));
+ root->bind(TOK_END)->bind(new be_builder(END));
+ root->bind_num(TOK_END)->bind(new be_builder(END));
+ root->bind(TOK_ERROR)->bind(new be_builder(ERROR));
+ root->bind_num(TOK_ERROR)->bind(new be_builder(ERROR));
+
+ root->bind(TOK_NEVER)->bind(new never_builder());
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
new file mode 100644
index 00000000..38304a98
--- /dev/null
+++ b/tapset-itrace.cxx
@@ -0,0 +1,337 @@
+// tapset for timers
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "task_finder.h"
+#include "translate.h"
+#include "util.h"
+
+#include <cstring>
+#include <string>
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+static string TOK_PROCESS("process");
+static string TOK_INSN("insn");
+static string TOK_BLOCK("block");
+
+
+// ------------------------------------------------------------------------
+// itrace user-space probes
+// ------------------------------------------------------------------------
+
+
+struct itrace_derived_probe: public derived_probe
+{
+ bool has_path;
+ string path;
+ int64_t pid;
+ int single_step;
+
+ itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
+ bool hp, string &pn, int64_t pd, int ss
+ );
+ void join_group (systemtap_session& s);
+};
+
+
+struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe>
+{
+private:
+ map<string, vector<itrace_derived_probe*> > probes_by_path;
+ typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator;
+ map<int64_t, vector<itrace_derived_probe*> > probes_by_pid;
+ typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator;
+ unsigned num_probes;
+
+ void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p);
+
+public:
+ itrace_derived_probe_group(): num_probes(0) { }
+
+ void enroll (itrace_derived_probe* probe);
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+itrace_derived_probe::itrace_derived_probe (systemtap_session &s,
+ probe* p, probe_point* l,
+ bool hp, string &pn, int64_t pd,
+ int ss
+ ):
+ derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss)
+{
+}
+
+
+void
+itrace_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.itrace_derived_probes)
+ s.itrace_derived_probes = new itrace_derived_probe_group ();
+
+ s.itrace_derived_probes->enroll (this);
+
+ enable_task_finder(s);
+}
+
+struct itrace_builder: public derived_probe_builder
+{
+ itrace_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ std::map<std::string, literal *> const & parameters,
+ vector<derived_probe *> & finished_results)
+ {
+ string path;
+ int64_t pid = 0;
+ int single_step;
+
+ bool has_path = get_param (parameters, TOK_PROCESS, path);
+ bool has_pid = get_param (parameters, TOK_PROCESS, pid);
+ // XXX: PR 6445 needs !has_path && !has_pid support
+ assert (has_path || has_pid);
+
+ single_step = ! has_null_param (parameters, TOK_BLOCK);
+
+ // If we have a path, we need to validate it.
+ if (has_path)
+ path = find_executable (path);
+
+ finished_results.push_back(new itrace_derived_probe(sess, base, location,
+ has_path, path, pid,
+ single_step
+ ));
+ }
+};
+
+
+void
+itrace_derived_probe_group::enroll (itrace_derived_probe* p)
+{
+ if (p->has_path)
+ probes_by_path[p->path].push_back(p);
+ else
+ probes_by_pid[p->pid].push_back(p);
+ num_probes++;
+
+ // XXX: multiple exec probes (for instance) for the same path (or
+ // pid) should all share a itrace report function, and have their
+ // handlers executed sequentially.
+}
+
+
+void
+itrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
+ itrace_derived_probe *p)
+{
+ s.op->newline() << "{";
+ s.op->line() << " .tgt={";
+
+ if (p->has_path)
+ {
+ s.op->line() << " .pathname=\"" << p->path << "\",";
+ s.op->line() << " .pid=0,";
+ }
+ else
+ {
+ s.op->line() << " .pathname=NULL,";
+ s.op->line() << " .pid=" << p->pid << ",";
+ }
+
+ s.op->line() << " .callback=&_stp_itrace_probe_cb,";
+ s.op->line() << " },";
+ s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
+ s.op->line() << " .single_step=" << p->single_step << ",";
+ s.op->line() << " .ph=&" << p->name << ",";
+
+ s.op->line() << " },";
+}
+
+
+void
+itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes_by_path.empty() && probes_by_pid.empty())
+ return;
+
+ s.op->newline();
+ s.op->newline() << "/* ---- itrace probes ---- */";
+
+ s.op->newline() << "struct stap_itrace_probe {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target tgt;";
+ s.op->newline() << "const char *pp;";
+ s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "int single_step;";
+ s.op->newline(-1) << "};";
+ s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);";
+ s.op->newline() << "#include \"itrace.c\"";
+
+ // output routine to call itrace probe
+ s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {";
+ s.op->indent(1);
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp");
+ s.op->newline() << "c->regs = regs;";
+ s.op->newline() << "c->data = data;";
+
+ // call probe function
+ s.op->newline() << "(*p->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+
+ s.op->newline() << "return;";
+ s.op->newline(-1) << "}";
+
+ // Output task finder callback routine that gets called for all
+ // itrace probe types.
+ s.op->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "int rc = 0;";
+ s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
+
+ s.op->newline() << "if (register_p) ";
+ s.op->indent(1);
+
+ s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk->pid, p);";
+ s.op->newline(-1) << "else";
+ s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(p->tgt.pid));";
+ s.op->newline(-1) << "return rc;";
+ s.op->newline(-1) << "}";
+
+ // Emit vma callbacks.
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "static struct stap_task_finder_target stap_itrace_vmcbs[] = {";
+ s.op->indent(1);
+ if (! probes_by_path.empty())
+ {
+ for (p_b_path_iterator it = probes_by_path.begin();
+ it != probes_by_path.end(); it++)
+ emit_vma_callback_probe_decl (s, it->first, (int64_t)0);
+ }
+ if (! probes_by_pid.empty())
+ {
+ for (p_b_pid_iterator it = probes_by_pid.begin();
+ it != probes_by_pid.end(); it++)
+ emit_vma_callback_probe_decl (s, "", it->first);
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline() << "#endif";
+
+ s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
+ s.op->indent(1);
+
+ // Set up 'process(PATH)' probes
+ if (! probes_by_path.empty())
+ {
+ for (p_b_path_iterator it = probes_by_path.begin();
+ it != probes_by_path.end(); it++)
+ {
+ for (unsigned i = 0; i < it->second.size(); i++)
+ {
+ itrace_derived_probe *p = it->second[i];
+ emit_probe_decl(s, p);
+ }
+ }
+ }
+
+ // Set up 'process(PID)' probes
+ if (! probes_by_pid.empty())
+ {
+ for (p_b_pid_iterator it = probes_by_pid.begin();
+ it != probes_by_pid.end(); it++)
+ {
+ for (unsigned i = 0; i < it->second.size(); i++)
+ {
+ itrace_derived_probe *p = it->second[i];
+ emit_probe_decl(s, p);
+ }
+ }
+ }
+ s.op->newline(-1) << "};";
+}
+
+
+void
+itrace_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes_by_path.empty() && probes_by_pid.empty())
+ return;
+
+ s.op->newline();
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "_stp_sym_init();";
+ s.op->newline() << "/* ---- itrace vma callbacks ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_itrace_vmcbs); i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target *r = &stap_itrace_vmcbs[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(r);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#endif";
+
+ s.op->newline();
+ s.op->newline() << "/* ---- itrace probes ---- */";
+
+ s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
+
+ // 'arch_has_single_step' needs to be defined for either single step mode
+ // or branch mode.
+ s.op->newline() << "if (!arch_has_single_step()) {";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error (\"insn probe init: arch does not support step mode\");";
+ s.op->newline() << "rc = -EPERM;";
+ s.op->newline() << "break;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "if (!p->single_step && !arch_has_block_step()) {";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error (\"insn probe init: arch does not support block step mode\");";
+ s.op->newline() << "rc = -EPERM;";
+ s.op->newline() << "break;";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
+ s.op->newline(-1) << "}";
+}
+
+
+void
+itrace_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes_by_path.empty() && probes_by_pid.empty()) return;
+ s.op->newline();
+ s.op->newline() << "/* ---- itrace probes ---- */";
+ s.op->newline() << "cleanup_usr_itrace();";
+}
+
+void
+register_tapset_itrace(systemtap_session& s)
+{
+ match_node* root = s.pattern_root;
+ derived_probe_builder *builder = new itrace_builder();
+
+ root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(builder);
+ root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(builder);
+ root->bind_str(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)->bind(builder);
+ root->bind_num(TOK_PROCESS)->bind(TOK_INSN)->bind(TOK_BLOCK)->bind(builder);
+}
+
+
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset-mark.cxx b/tapset-mark.cxx
new file mode 100644
index 00000000..1f0ef2ce
--- /dev/null
+++ b/tapset-mark.cxx
@@ -0,0 +1,712 @@
+// tapset for kernel static markers
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "translate.h"
+#include "util.h"
+
+#include <cerrno>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+extern "C" {
+#include <fnmatch.h>
+}
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+static string TOK_KERNEL("kernel");
+static string TOK_MARK("mark");
+static string TOK_FORMAT("format");
+
+
+// ------------------------------------------------------------------------
+// statically inserted macro-based derived probes
+// ------------------------------------------------------------------------
+
+struct mark_arg
+{
+ bool str;
+ string c_type;
+ exp_type stp_type;
+};
+
+struct mark_derived_probe: public derived_probe
+{
+ mark_derived_probe (systemtap_session &s,
+ const string& probe_name, const string& probe_format,
+ probe* base_probe, probe_point* location);
+
+ systemtap_session& sess;
+ string probe_name, probe_format;
+ vector <struct mark_arg *> mark_args;
+ bool target_symbol_seen;
+
+ void join_group (systemtap_session& s);
+ void print_dupe_stamp (ostream& o);
+ void emit_probe_context_vars (translator_output* o);
+ void initialize_probe_context_vars (translator_output* o);
+ void printargs (std::ostream &o) const;
+
+ void parse_probe_format ();
+};
+
+
+struct mark_derived_probe_group: public generic_dpg<mark_derived_probe>
+{
+public:
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+struct mark_var_expanding_visitor: public var_expanding_visitor
+{
+ mark_var_expanding_visitor(systemtap_session& s, const string& pn,
+ vector <struct mark_arg *> &mark_args):
+ sess (s), probe_name (pn), mark_args (mark_args),
+ target_symbol_seen (false) {}
+ systemtap_session& sess;
+ string probe_name;
+ vector <struct mark_arg *> &mark_args;
+ bool target_symbol_seen;
+
+ void visit_target_symbol (target_symbol* e);
+ void visit_target_symbol_arg (target_symbol* e);
+ void visit_target_symbol_context (target_symbol* e);
+};
+
+
+void
+mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
+{
+ string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
+ int argnum = atoi (argnum_s.c_str());
+
+ if (argnum < 1 || argnum > (int)mark_args.size())
+ throw semantic_error ("invalid marker argument number", e->tok);
+
+ if (is_active_lvalue (e))
+ throw semantic_error("write to marker parameter not permitted", e->tok);
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("marker argument may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("marker argument may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid marker argument use", e->tok);
+ break;
+ }
+ }
+
+ // Remember that we've seen a target variable.
+ target_symbol_seen = true;
+
+ e->probe_context_var = "__mark_arg" + lex_cast<string>(argnum);
+ e->type = mark_args[argnum-1]->stp_type;
+ provide (e);
+}
+
+
+void
+mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
+{
+ string sname = e->base_name;
+
+ if (is_active_lvalue (e))
+ throw semantic_error("write to marker '" + sname + "' not permitted", e->tok);
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("marker '" + sname + "' may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("marker '" + sname + "' may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid marker '" + sname + "' use", e->tok);
+ break;
+ }
+ }
+
+ string fname;
+ if (e->base_name == "$format") {
+ fname = string("_mark_format_get");
+ } else {
+ fname = string("_mark_name_get");
+ }
+
+ // 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 (n);
+}
+
+void
+mark_var_expanding_visitor::visit_target_symbol (target_symbol* e)
+{
+ assert(e->base_name.size() > 0 && e->base_name[0] == '$');
+
+ if (e->base_name.substr(0,4) == "$arg")
+ visit_target_symbol_arg (e);
+ else if (e->base_name == "$format" || e->base_name == "$name")
+ visit_target_symbol_context (e);
+ else
+ throw semantic_error ("invalid target symbol for marker, $argN, $name or $format expected",
+ e->tok);
+}
+
+
+
+mark_derived_probe::mark_derived_probe (systemtap_session &s,
+ const string& p_n,
+ const string& p_f,
+ probe* base, probe_point* loc):
+ derived_probe (base, new probe_point(*loc) /* .components soon rewritten */),
+ sess (s), probe_name (p_n), probe_format (p_f),
+ target_symbol_seen (false)
+{
+ // create synthetic probe point name; preserve condition
+ vector<probe_point::component*> comps;
+ comps.push_back (new probe_point::component (TOK_KERNEL));
+ comps.push_back (new probe_point::component (TOK_MARK, new literal_string (probe_name)));
+ comps.push_back (new probe_point::component (TOK_FORMAT, new literal_string (probe_format)));
+ this->sole_location()->components = comps;
+
+ // expand the marker format
+ parse_probe_format();
+
+ // Now expand the local variables in the probe body
+ mark_var_expanding_visitor v (sess, name, mark_args);
+ this->body = v.require (this->body);
+ target_symbol_seen = v.target_symbol_seen;
+
+ if (sess.verbose > 2)
+ clog << "marker-based " << name << " mark=" << probe_name
+ << " fmt='" << probe_format << "'" << endl;
+}
+
+
+static int
+skip_atoi(const char **s)
+{
+ int i = 0;
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
+
+
+void
+mark_derived_probe::parse_probe_format()
+{
+ const char *fmt = probe_format.c_str();
+ int qualifier; // 'h', 'l', or 'L' for integer fields
+ mark_arg *arg;
+
+ for (; *fmt ; ++fmt)
+ {
+ if (*fmt != '%')
+ {
+ /* Skip text */
+ continue;
+ }
+
+repeat:
+ ++fmt;
+
+ // skip conversion flags (if present)
+ switch (*fmt)
+ {
+ case '-':
+ case '+':
+ case ' ':
+ case '#':
+ case '0':
+ goto repeat;
+ }
+
+ // skip minimum field witdh (if present)
+ if (isdigit(*fmt))
+ skip_atoi(&fmt);
+
+ // skip precision (if present)
+ if (*fmt == '.')
+ {
+ ++fmt;
+ if (isdigit(*fmt))
+ skip_atoi(&fmt);
+ }
+
+ // get the conversion qualifier (if present)
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
+ {
+ qualifier = *fmt;
+ ++fmt;
+ if (qualifier == 'l' && *fmt == 'l')
+ {
+ qualifier = 'L';
+ ++fmt;
+ }
+ }
+
+ // get the conversion type
+ switch (*fmt)
+ {
+ case 'c':
+ arg = new mark_arg;
+ arg->str = false;
+ arg->c_type = "int";
+ arg->stp_type = pe_long;
+ mark_args.push_back(arg);
+ continue;
+
+ case 's':
+ arg = new mark_arg;
+ arg->str = true;
+ arg->c_type = "char *";
+ arg->stp_type = pe_string;
+ mark_args.push_back(arg);
+ continue;
+
+ case 'p':
+ arg = new mark_arg;
+ arg->str = false;
+ // This should really be 'void *'. But, then we'll get a
+ // compile error when we assign the void pointer to an
+ // integer without a cast. So, we use 'long' instead, since
+ // it should have the same size as 'void *'.
+ arg->c_type = "long";
+ arg->stp_type = pe_long;
+ mark_args.push_back(arg);
+ continue;
+
+ case '%':
+ continue;
+
+ case 'o':
+ case 'X':
+ case 'x':
+ case 'd':
+ case 'i':
+ case 'u':
+ // fall through...
+ break;
+
+ default:
+ if (!*fmt)
+ --fmt;
+ continue;
+ }
+
+ arg = new mark_arg;
+ arg->str = false;
+ arg->stp_type = pe_long;
+ switch (qualifier)
+ {
+ case 'L':
+ arg->c_type = "long long";
+ break;
+
+ case 'l':
+ arg->c_type = "long";
+ break;
+
+ case 'h':
+ arg->c_type = "short";
+ break;
+
+ default:
+ arg->c_type = "int";
+ break;
+ }
+ mark_args.push_back(arg);
+ }
+}
+
+
+void
+mark_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.mark_derived_probes)
+ {
+ 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);
+}
+
+
+void
+mark_derived_probe::print_dupe_stamp (ostream& o)
+{
+ if (target_symbol_seen)
+ for (unsigned i = 0; i < mark_args.size(); i++)
+ o << mark_args[i]->c_type << " __mark_arg" << (i+1) << endl;
+}
+
+
+void
+mark_derived_probe::emit_probe_context_vars (translator_output* o)
+{
+ // If we haven't seen a target symbol for this probe, quit.
+ if (! target_symbol_seen)
+ return;
+
+ for (unsigned i = 0; i < mark_args.size(); i++)
+ {
+ string localname = "__mark_arg" + lex_cast<string>(i+1);
+ switch (mark_args[i]->stp_type)
+ {
+ case pe_long:
+ o->newline() << "int64_t " << localname << ";";
+ break;
+ case pe_string:
+ o->newline() << "string_t " << localname << ";";
+ break;
+ default:
+ throw semantic_error ("cannot expand unknown type");
+ break;
+ }
+ }
+}
+
+
+void
+mark_derived_probe::initialize_probe_context_vars (translator_output* o)
+{
+ // If we haven't seen a target symbol for this probe, quit.
+ if (! target_symbol_seen)
+ return;
+
+ bool deref_fault_needed = false;
+ for (unsigned i = 0; i < mark_args.size(); i++)
+ {
+ string localname = "l->__mark_arg" + lex_cast<string>(i+1);
+ switch (mark_args[i]->stp_type)
+ {
+ case pe_long:
+ o->newline() << localname << " = va_arg(*c->mark_va_list, "
+ << mark_args[i]->c_type << ");";
+ break;
+
+ case pe_string:
+ // We're assuming that this is a kernel string (this code is
+ // basically the guts of kernel_string), not a user string.
+ o->newline() << "{ " << mark_args[i]->c_type
+ << " tmp_str = va_arg(*c->mark_va_list, "
+ << mark_args[i]->c_type << ");";
+ o->newline() << "deref_string (" << localname
+ << ", tmp_str, MAXSTRINGLEN); }";
+ deref_fault_needed = true;
+ break;
+
+ default:
+ throw semantic_error ("cannot expand unknown type");
+ break;
+ }
+ }
+ if (deref_fault_needed)
+ // Need to report errors?
+ o->newline() << "deref_fault: ;";
+}
+
+void
+mark_derived_probe::printargs(std::ostream &o) const
+{
+ for (unsigned i = 0; i < mark_args.size(); i++)
+ {
+ string localname = "$arg" + lex_cast<string>(i+1);
+ switch (mark_args[i]->stp_type)
+ {
+ case pe_long:
+ o << " " << localname << ":long";
+ break;
+ case pe_string:
+ o << " " << localname << ":string";
+ break;
+ default:
+ o << " " << localname << ":unknown";
+ break;
+ }
+ }
+}
+
+
+void
+mark_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes.empty())
+ return;
+
+ s.op->newline() << "/* ---- marker probes ---- */";
+
+ s.op->newline() << "static struct stap_marker_probe {";
+ s.op->newline(1) << "const char * const name;";
+ s.op->newline() << "const char * const format;";
+ s.op->newline() << "const char * const pp;";
+ s.op->newline() << "void (* const ph) (struct context *);";
+
+ s.op->newline(-1) << "} stap_marker_probes [" << probes.size() << "] = {";
+ s.op->indent(1);
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ s.op->newline () << "{";
+ s.op->line() << " .name=" << lex_cast_qstring(probes[i]->probe_name)
+ << ",";
+ s.op->line() << " .format=" << lex_cast_qstring(probes[i]->probe_format)
+ << ",";
+ s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location())
+ << ",";
+ s.op->line() << " .ph=&" << probes[i]->name;
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline();
+
+
+ // Emit the marker callback function
+ s.op->newline();
+ s.op->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {";
+ s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;";
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "smp->pp");
+ s.op->newline() << "c->marker_name = smp->name;";
+ s.op->newline() << "c->marker_format = smp->format;";
+ s.op->newline() << "c->mark_va_list = args;";
+ s.op->newline() << "(*smp->ph) (c);";
+ s.op->newline() << "c->mark_va_list = NULL;";
+ s.op->newline() << "c->data = NULL;";
+
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline(-1) << "}";
+
+ return;
+}
+
+
+void
+mark_derived_probe_group::emit_module_init (systemtap_session &s)
+{
+ if (probes.size () == 0)
+ return;
+
+ s.op->newline() << "/* init marker probes */";
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
+ s.op->newline() << "probe_point = smp->pp;";
+ s.op->newline() << "rc = marker_probe_register(smp->name, smp->format, enter_marker_probe, smp);";
+ s.op->newline() << "if (rc) {";
+ s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
+ s.op->newline(1) << "struct stap_marker_probe *smp2 = &stap_marker_probes[j];";
+ s.op->newline() << "marker_probe_unregister(smp2->name, enter_marker_probe, smp2);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;"; // don't attempt to register any more probes
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+
+void
+mark_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes.empty())
+ return;
+
+ s.op->newline() << "/* deregister marker probes */";
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
+ s.op->newline() << "marker_probe_unregister(smp->name, enter_marker_probe, smp);";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+
+struct mark_builder: public derived_probe_builder
+{
+private:
+ bool cache_initialized;
+ typedef multimap<string, string> mark_cache_t;
+ typedef multimap<string, string>::const_iterator mark_cache_const_iterator_t;
+ typedef pair<mark_cache_const_iterator_t, mark_cache_const_iterator_t>
+ mark_cache_const_iterator_pair_t;
+ mark_cache_t mark_cache;
+
+public:
+ mark_builder(): cache_initialized(false) {}
+
+ void build_no_more (systemtap_session &s)
+ {
+ if (! mark_cache.empty())
+ {
+ if (s.verbose > 3)
+ clog << "mark_builder releasing cache" << endl;
+ mark_cache.clear();
+ }
+ }
+
+ void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results);
+};
+
+
+void
+mark_builder::build(systemtap_session & sess,
+ probe * base,
+ probe_point *loc,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+{
+ string mark_str_val;
+ bool has_mark_str = get_param (parameters, TOK_MARK, mark_str_val);
+ string mark_format_val;
+ bool has_mark_format = get_param (parameters, TOK_FORMAT, mark_format_val);
+ assert (has_mark_str);
+ (void) has_mark_str;
+
+ if (! cache_initialized)
+ {
+ cache_initialized = true;
+ string module_markers_path = sess.kernel_build_tree + "/Module.markers";
+
+ ifstream module_markers;
+ module_markers.open(module_markers_path.c_str(), ifstream::in);
+ if (! module_markers)
+ {
+ if (sess.verbose>3)
+ clog << module_markers_path << " cannot be opened: "
+ << strerror(errno) << endl;
+ return;
+ }
+
+ string name, module, format;
+ do
+ {
+ module_markers >> name >> module;
+ getline(module_markers, format);
+
+ // trim leading whitespace
+ 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;
+
+ if (mark_cache.count(name) > 0)
+ {
+ // If we have 2 markers with the same we've got 2 cases:
+ // different format strings or duplicate format strings.
+ // If an existing marker in the cache doesn't have the
+ // same format string, add this marker.
+ mark_cache_const_iterator_pair_t ret;
+ mark_cache_const_iterator_t it;
+ bool matching_format_string = false;
+
+ ret = mark_cache.equal_range(name);
+ for (it = ret.first; it != ret.second; ++it)
+ {
+ if (format == it->second)
+ {
+ matching_format_string = true;
+ break;
+ }
+ }
+
+ if (! matching_format_string)
+ mark_cache.insert(pair<string,string>(name, format));
+ }
+ else
+ mark_cache.insert(pair<string,string>(name, format));
+ }
+ while (! module_markers.eof());
+ module_markers.close();
+ }
+
+ // Search marker list for matching markers
+ for (mark_cache_const_iterator_t it = mark_cache.begin();
+ it != mark_cache.end(); it++)
+ {
+ // Below, "rc" has negative polarity: zero iff matching.
+ int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0);
+ if (! rc)
+ {
+ bool add_result = true;
+
+ // Match format strings (if the user specified one)
+ if (has_mark_format && fnmatch(mark_format_val.c_str(),
+ it->second.c_str(), 0))
+ add_result = false;
+
+ if (add_result)
+ {
+ derived_probe *dp
+ = new mark_derived_probe (sess,
+ it->first, it->second,
+ base, loc);
+ finished_results.push_back (dp);
+ }
+ }
+ }
+}
+
+
+
+void
+register_tapset_mark(systemtap_session& s)
+{
+ match_node* root = s.pattern_root;
+ derived_probe_builder *builder = new mark_builder();
+
+ root = root->bind(TOK_KERNEL);
+ root = root->bind_str(TOK_MARK);
+
+ root->bind(builder);
+ root->bind_str(TOK_FORMAT)->bind(builder);
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset-perfmon.cxx b/tapset-perfmon.cxx
new file mode 100644
index 00000000..e3f30ece
--- /dev/null
+++ b/tapset-perfmon.cxx
@@ -0,0 +1,463 @@
+// tapset for HW performance monitoring
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "util.h"
+
+#include <string>
+
+#ifdef PERFMON
+#include <perfmon/pfmlib.h>
+#include <perfmon/perfmon.h>
+#endif
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+
+// ------------------------------------------------------------------------
+// perfmon derived probes
+// ------------------------------------------------------------------------
+// This is a new interface to the perfmon hw.
+//
+
+
+struct perfmon_var_expanding_visitor: public var_expanding_visitor
+{
+ systemtap_session & sess;
+ unsigned counter_number;
+ perfmon_var_expanding_visitor(systemtap_session & s, unsigned c):
+ sess(s), counter_number(c) {}
+ void visit_target_symbol (target_symbol* e);
+};
+
+
+void
+perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e)
+{
+ assert(e->base_name.size() > 0 && e->base_name[0] == '$');
+
+ // Synthesize a function.
+ functiondecl *fdecl = new functiondecl;
+ fdecl->tok = e->tok;
+ embeddedcode *ec = new embeddedcode;
+ ec->tok = e->tok;
+ bool lvalue = is_active_lvalue(e);
+
+ if (lvalue )
+ throw semantic_error("writes to $counter not permitted");
+
+ string fname = string("_perfmon_tvar_get")
+ + "_" + e->base_name.substr(1)
+ + "_" + lex_cast<string>(counter_number);
+
+ if (e->base_name != "$counter")
+ throw semantic_error ("target variables not available to perfmon probes");
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("perfmon probe '$counter' variable may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("perfmon probe '$counter' variable may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid use of perfmon probe '$counter' variable",
+ e->tok);
+ break;
+ }
+ }
+
+ ec->code = "THIS->__retvalue = _pfm_pmd_x[" +
+ lex_cast<string>(counter_number) + "].reg_num;";
+ ec->code += "/* pure */";
+ fdecl->name = fname;
+ fdecl->body = ec;
+ fdecl->type = pe_long;
+ sess.functions[fdecl->name]=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 (n);
+}
+
+
+enum perfmon_mode
+{
+ perfmon_count,
+ perfmon_sample
+};
+
+
+struct perfmon_derived_probe: public derived_probe
+{
+protected:
+ static unsigned probes_allocated;
+
+public:
+ systemtap_session & sess;
+ string event;
+ perfmon_mode mode;
+
+ perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s,
+ string e, perfmon_mode m);
+ virtual void join_group (systemtap_session& s);
+};
+
+
+struct perfmon_derived_probe_group: public generic_dpg<perfmon_derived_probe>
+{
+public:
+ void emit_module_decls (systemtap_session&) {}
+ void emit_module_init (systemtap_session&) {}
+ void emit_module_exit (systemtap_session&) {}
+};
+
+
+struct perfmon_builder: public derived_probe_builder
+{
+ perfmon_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+ {
+ string event;
+ if (!get_param (parameters, "counter", event))
+ throw semantic_error("perfmon requires an event");
+
+ sess.perfmon++;
+
+ // XXX: need to revise when doing sampling
+ finished_results.push_back(new perfmon_derived_probe(base, location,
+ sess, event,
+ perfmon_count));
+ }
+};
+
+
+unsigned perfmon_derived_probe::probes_allocated;
+
+perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
+ systemtap_session &s,
+ string e, perfmon_mode m)
+ : derived_probe (p, l), sess(s), event(e), mode(m)
+{
+ ++probes_allocated;
+
+ // Now expand the local variables in the probe body
+ perfmon_var_expanding_visitor v (sess, probes_allocated-1);
+ this->body = v.require (this->body);
+
+ if (sess.verbose > 1)
+ clog << "perfmon-based probe" << endl;
+}
+
+
+void
+perfmon_derived_probe::join_group (systemtap_session& s)
+{
+ throw semantic_error ("incomplete", this->tok);
+
+ if (! s.perfmon_derived_probes)
+ s.perfmon_derived_probes = new perfmon_derived_probe_group ();
+ s.perfmon_derived_probes->enroll (this);
+}
+
+
+#if 0
+void
+perfmon_derived_probe::emit_registrations_start (translator_output* o,
+ unsigned index)
+{
+ for (unsigned i=0; i<locations.size(); i++)
+ o->newline() << "enter_" << name << "_" << i << " ();";
+}
+
+
+void
+perfmon_derived_probe::emit_registrations_end (translator_output * o,
+ unsigned index)
+{
+}
+
+
+void
+perfmon_derived_probe::emit_deregistrations (translator_output * o)
+{
+}
+
+
+void
+perfmon_derived_probe::emit_probe_entries (translator_output * o)
+{
+ o->newline() << "#ifdef STP_TIMING";
+ // NB: This variable may be multiply (but identically) defined.
+ o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";";
+ o->newline() << "#endif";
+
+ for (unsigned i=0; i<locations.size(); i++)
+ {
+ probe_point *l = locations[i];
+ o->newline() << "/* location " << i << ": " << *l << " */";
+ o->newline() << "static void enter_" << name << "_" << i << " (void) {";
+
+ o->indent(1);
+ o->newline() << "const char* probe_point = "
+ << lex_cast_qstring(*l) << ";";
+
+ o->newline() << "static struct pfarg_ctx _pfm_context;";
+ o->newline() << "static void *_pfm_desc;";
+ o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;";
+ o->newline() << "static int _pfm_num_pmc_x;";
+ o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;";
+ o->newline() << "static int _pfm_num_pmd_x;";
+
+ emit_probe_prologue (o,
+ (mode == perfmon_count ?
+ "STAP_SESSION_STARTING" :
+ "STAP_SESSION_RUNNING"),
+ "probe_point");
+
+ // NB: locals are initialized by probe function itself
+ o->newline() << name << " (c);";
+
+ emit_probe_epilogue (o);
+
+ o->newline(-1) << "}\n";
+ }
+}
+#endif
+
+
+#if 0
+void no_pfm_event_error (string s)
+{
+ string msg(string("Cannot find event:" + s));
+ throw semantic_error(msg);
+}
+
+
+void no_pfm_mask_error (string s)
+{
+ string msg(string("Cannot find mask:" + s));
+ throw semantic_error(msg);
+}
+
+
+void
+split(const string& s, vector<string>& v, const string & separator)
+{
+ string::size_type last_pos = s.find_first_not_of(separator, 0);
+ string::size_type pos = s.find_first_of(separator, last_pos);
+
+ while (string::npos != pos || string::npos != last_pos) {
+ v.push_back(s.substr(last_pos, pos - last_pos));
+ last_pos = s.find_first_not_of(separator, pos);
+ pos = s.find_first_of(separator, last_pos);
+ }
+}
+
+
+void
+perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up)
+{
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ op->newline ();
+ up->emit_probe (probes[i]);
+ }
+}
+
+
+void
+perfmon_derived_probe_group::emit_module_init (translator_output* o)
+{
+ int ret;
+ pfmlib_input_param_t inp;
+ pfmlib_output_param_t outp;
+ pfarg_pmd_t pd[PFMLIB_MAX_PMDS];
+ pfarg_pmc_t pc[PFMLIB_MAX_PMCS];
+ pfarg_ctx_t ctx;
+ pfarg_load_t load_args;
+ pfmlib_options_t pfmlib_options;
+ unsigned int max_counters;
+
+ if ( probes.size() == 0)
+ return;
+ ret = pfm_initialize();
+ if (ret != PFMLIB_SUCCESS)
+ throw semantic_error("Unable to generate performance monitoring events (no libpfm)");
+
+ pfm_get_num_counters(&max_counters);
+
+ memset(&pfmlib_options, 0, sizeof(pfmlib_options));
+ pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
+ pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */
+ pfm_set_options(&pfmlib_options);
+
+ memset(pd, 0, sizeof(pd));
+ memset(pc, 0, sizeof(pc));
+ memset(&ctx, 0, sizeof(ctx));
+ memset(&load_args, 0, sizeof(load_args));
+
+ /*
+ * prepare parameters to library.
+ */
+ memset(&inp,0, sizeof(inp));
+ memset(&outp,0, sizeof(outp));
+
+ /* figure out the events */
+ for (unsigned i=0; i<probes.size(); ++i)
+ {
+ if (probes[i]->event == "cycles") {
+ if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS)
+ no_pfm_event_error(probes[i]->event);
+ } else if (probes[i]->event == "instructions") {
+ if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) !=
+ PFMLIB_SUCCESS)
+ no_pfm_event_error(probes[i]->event);
+ } else {
+ unsigned int event_id = 0;
+ unsigned int mask_id = 0;
+ vector<string> event_spec;
+ split(probes[i]->event, event_spec, ":");
+ int num = event_spec.size();
+ int masks = num - 1;
+
+ if (num == 0)
+ throw semantic_error("No events found");
+
+ /* setup event */
+ if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS)
+ no_pfm_event_error(event_spec[0]);
+ inp.pfp_events[i].event = event_id;
+
+ /* set up masks */
+ if (masks > PFMLIB_MAX_MASKS_PER_EVENT)
+ throw semantic_error("Too many unit masks specified");
+
+ for (int j=0; j < masks; j++) {
+ if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(),
+ &mask_id) != PFMLIB_SUCCESS)
+ no_pfm_mask_error(string(event_spec[j+1]));
+ inp.pfp_events[i].unit_masks[j] = mask_id;
+ }
+ inp.pfp_events[i].num_masks = masks;
+ }
+ }
+
+ /* number of counters in use */
+ inp.pfp_event_count = probes.size();
+
+ // XXX: no elimination of duplicated counters
+ if (inp.pfp_event_count>max_counters)
+ throw semantic_error("Too many performance monitoring events.");
+
+ /* count events both in kernel and user-space */
+ inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3;
+
+ /* XXX: some cases a perfmon register might be used of watch dog
+ this code doesn't handle that case */
+
+ /* figure out the pmcs for the events */
+ if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
+ throw semantic_error("Cannot configure events");
+
+ for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
+ pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
+ pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
+ }
+
+ /*
+ * There could be more pmc settings than pmd.
+ * Figure out the actual pmds to use.
+ */
+ for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) {
+ pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num;
+ for(; j < outp.pfp_pmc_count; j++)
+ if (outp.pfp_pmcs[j].reg_evt_idx != i) break;
+ }
+
+ // Output the be probes create function
+ o->newline() << "static int register_perfmon_probes (void) {";
+ o->newline(1) << "int rc = 0;";
+
+ o->newline() << "/* data for perfmon */";
+ o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";";
+ o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count
+ << "] = {";
+ /* output the needed bits for pmc here */
+ for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
+ o->newline() << "{.reg_num=" << pc[i].reg_num << ", "
+ << ".reg_value=" << lex_cast_hex<string>(pc[i].reg_value)
+ << "},";
+ }
+
+ o->newline() << "};";
+ o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";";
+ o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count
+ << "] = {";
+ /* output the needed bits for pmd here */
+ for (unsigned i=0; i < inp.pfp_event_count; i++) {
+ o->newline() << "{.reg_num=" << pd[i].reg_num << ", "
+ << ".reg_value=" << pd[i].reg_value << "},";
+ }
+ o->newline() << "};";
+ o->newline();
+
+ o->newline() << "_pfm_pmc_x=_pfm_pmc;";
+ o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;";
+ o->newline() << "_pfm_pmd_x=_pfm_pmd;";
+ o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;";
+
+ // call all the function bodies associated with perfcounters
+ for (unsigned i=0; i < probes.size (); i++)
+ probes[i]->emit_registrations_start (o,i);
+
+ /* generate call to turn on instrumentation */
+ o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;";
+ o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,";
+ o->newline(1) << "_pfm_pmc, _pfm_num_pmc,";
+ o->newline() << "_pfm_pmd, _pfm_num_pmd);";
+ o->newline(-1);
+
+ o->newline() << "return rc;";
+ o->newline(-1) << "}\n";
+
+ // Output the be probes destroy function
+ o->newline() << "static void unregister_perfmon_probes (void) {";
+ o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);";
+ o->newline(-1) << "}\n";
+}
+#endif
+
+
+void
+register_tapset_perfmon(systemtap_session& s)
+{
+ s.pattern_root->bind("perfmon")->bind_str("counter")
+ ->bind(new perfmon_builder());
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset-procfs.cxx b/tapset-procfs.cxx
new file mode 100644
index 00000000..3568c3d3
--- /dev/null
+++ b/tapset-procfs.cxx
@@ -0,0 +1,521 @@
+// tapset for procfs
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "translate.h"
+#include "util.h"
+
+#include <cstring>
+#include <string>
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+static string TOK_PROCFS("procfs");
+static string TOK_READ("read");
+static string TOK_WRITE("write");
+
+
+// ------------------------------------------------------------------------
+// procfs file derived probes
+// ------------------------------------------------------------------------
+
+
+struct procfs_derived_probe: public derived_probe
+{
+ string path;
+ bool write;
+ bool target_symbol_seen;
+
+ procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w);
+ void join_group (systemtap_session& s);
+};
+
+
+struct procfs_probe_set
+{
+ procfs_derived_probe* read_probe;
+ procfs_derived_probe* write_probe;
+
+ procfs_probe_set () : read_probe (NULL), write_probe (NULL) {}
+};
+
+
+struct procfs_derived_probe_group: public generic_dpg<procfs_derived_probe>
+{
+private:
+ map<string, procfs_probe_set*> probes_by_path;
+ typedef map<string, procfs_probe_set*>::iterator p_b_p_iterator;
+ bool has_read_probes;
+ bool has_write_probes;
+
+public:
+ procfs_derived_probe_group () :
+ has_read_probes(false), has_write_probes(false) {}
+
+ void enroll (procfs_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 procfs_var_expanding_visitor: public var_expanding_visitor
+{
+ procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
+ string path, bool write_probe):
+ sess (s), probe_name (pn), path (path), write_probe (write_probe),
+ target_symbol_seen (false) {}
+
+ systemtap_session& sess;
+ string probe_name;
+ string path;
+ bool write_probe;
+ bool target_symbol_seen;
+
+ void visit_target_symbol (target_symbol* e);
+};
+
+
+procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
+ probe_point* l, string ps, bool w):
+ derived_probe(p, l), path(ps), write(w), target_symbol_seen(false)
+{
+ // Expand local variables in the probe body
+ procfs_var_expanding_visitor v (s, name, path, write);
+ this->body = v.require (this->body);
+ target_symbol_seen = v.target_symbol_seen;
+}
+
+
+void
+procfs_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.procfs_derived_probes)
+ s.procfs_derived_probes = new procfs_derived_probe_group ();
+ s.procfs_derived_probes->enroll (this);
+}
+
+
+void
+procfs_derived_probe_group::enroll (procfs_derived_probe* p)
+{
+ procfs_probe_set *pset;
+
+ if (probes_by_path.count(p->path) == 0)
+ {
+ pset = new procfs_probe_set;
+ probes_by_path[p->path] = pset;
+ }
+ else
+ {
+ pset = probes_by_path[p->path];
+
+ // You can only specify 1 read and 1 write probe.
+ if (p->write && pset->write_probe != NULL)
+ throw semantic_error("only one write procfs probe can exist for procfs path \"" + p->path + "\"");
+ else if (! p->write && pset->read_probe != NULL)
+ throw semantic_error("only one read procfs probe can exist for procfs path \"" + p->path + "\"");
+
+ // XXX: multiple writes should be acceptable
+ }
+
+ if (p->write)
+ {
+ pset->write_probe = p;
+ has_write_probes = true;
+ }
+ else
+ {
+ pset->read_probe = p;
+ has_read_probes = true;
+ }
+}
+
+
+void
+procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes_by_path.empty())
+ return;
+
+ s.op->newline() << "/* ---- procfs probes ---- */";
+ s.op->newline() << "#include \"procfs.c\"";
+
+ // Emit the procfs probe data list
+ s.op->newline() << "static struct stap_procfs_probe {";
+ s.op->newline(1)<< "const char *path;";
+ s.op->newline() << "const char *read_pp;";
+ s.op->newline() << "void (*read_ph) (struct context*);";
+ s.op->newline() << "const char *write_pp;";
+ s.op->newline() << "void (*write_ph) (struct context*);";
+ s.op->newline(-1) << "} stap_procfs_probes[] = {";
+ s.op->indent(1);
+
+ for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
+ it++)
+ {
+ procfs_probe_set *pset = it->second;
+
+ s.op->newline() << "{";
+ s.op->line() << " .path=" << lex_cast_qstring (it->first) << ",";
+
+ if (pset->read_probe != NULL)
+ {
+ s.op->line() << " .read_pp="
+ << lex_cast_qstring (*pset->read_probe->sole_location())
+ << ",";
+ s.op->line() << " .read_ph=&" << pset->read_probe->name << ",";
+ }
+ else
+ {
+ s.op->line() << " .read_pp=NULL,";
+ s.op->line() << " .read_ph=NULL,";
+ }
+
+ if (pset->write_probe != NULL)
+ {
+ s.op->line() << " .write_pp="
+ << lex_cast_qstring (*pset->write_probe->sole_location())
+ << ",";
+ s.op->line() << " .write_ph=&" << pset->write_probe->name;
+ }
+ else
+ {
+ s.op->line() << " .write_pp=NULL,";
+ s.op->line() << " .write_ph=NULL";
+ }
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+
+ if (has_read_probes)
+ {
+ // Output routine to fill in 'page' with our data.
+ s.op->newline();
+
+ s.op->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {";
+
+ s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
+ s.op->newline() << "int bytes = 0;";
+ s.op->newline() << "string_t strdata = {'\\0'};";
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->read_pp");
+
+ s.op->newline() << "if (c->data == NULL)";
+ s.op->newline(1) << "c->data = &strdata;";
+ s.op->newline(-1) << "else {";
+
+ s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
+ s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ s.op->newline() << "_stp_exit ();";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "atomic_dec (& c->busy);";
+ s.op->newline() << "goto probe_epilogue;";
+ s.op->newline(-1) << "}";
+
+ // call probe function (which copies data into strdata)
+ s.op->newline() << "(*spp->read_ph) (c);";
+
+ // copy string data into 'page'
+ s.op->newline() << "c->data = NULL;";
+ s.op->newline() << "bytes = strnlen(strdata, MAXSTRINGLEN - 1);";
+ s.op->newline() << "if (off >= bytes)";
+ s.op->newline(1) << "*eof = 1;";
+ s.op->newline(-1) << "else {";
+ s.op->newline(1) << "bytes -= off;";
+ s.op->newline() << "if (bytes > count)";
+ s.op->newline(1) << "bytes = count;";
+ s.op->newline(-1) << "memcpy(page, strdata + off, bytes);";
+ s.op->newline() << "*start = page;";
+ s.op->newline(-1) << "}";
+
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline() << "return bytes;";
+
+ s.op->newline(-1) << "}";
+ }
+ if (has_write_probes)
+ {
+ s.op->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {";
+
+ s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
+ s.op->newline() << "string_t strdata = {'\\0'};";
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->write_pp");
+
+ s.op->newline() << "if (count > (MAXSTRINGLEN - 1))";
+ s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
+ s.op->newline(-1) << "_stp_copy_from_user(strdata, buffer, count);";
+
+ s.op->newline() << "if (c->data == NULL)";
+ s.op->newline(1) << "c->data = &strdata;";
+ s.op->newline(-1) << "else {";
+
+ s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
+ s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
+ s.op->newline() << "_stp_exit ();";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "atomic_dec (& c->busy);";
+ s.op->newline() << "goto probe_epilogue;";
+ s.op->newline(-1) << "}";
+
+ // call probe function (which copies data out of strdata)
+ s.op->newline() << "(*spp->write_ph) (c);";
+
+ s.op->newline() << "c->data = NULL;";
+ common_probe_entryfn_epilogue (s.op);
+
+ s.op->newline() << "return count;";
+ s.op->newline(-1) << "}";
+ }
+}
+
+
+void
+procfs_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes_by_path.empty())
+ return;
+
+ s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
+
+ s.op->newline() << "if (spp->read_pp)";
+ s.op->newline(1) << "probe_point = spp->read_pp;";
+ s.op->newline(-1) << "else";
+ s.op->newline(1) << "probe_point = spp->write_pp;";
+
+ s.op->newline(-1) << "rc = _stp_create_procfs(spp->path, i);";
+
+ s.op->newline() << "if (rc) {";
+ s.op->newline(1) << "_stp_close_procfs();";
+ s.op->newline() << "break;";
+ s.op->newline(-1) << "}";
+
+ if (has_read_probes)
+ {
+ s.op->newline() << "if (spp->read_pp)";
+ s.op->newline(1) << "_stp_procfs_files[i]->read_proc = &_stp_procfs_read;";
+ s.op->newline(-1) << "else";
+ s.op->newline(1) << "_stp_procfs_files[i]->read_proc = NULL;";
+ s.op->indent(-1);
+ }
+ else
+ s.op->newline() << "_stp_procfs_files[i]->read_proc = NULL;";
+
+ if (has_write_probes)
+ {
+ s.op->newline() << "if (spp->write_pp)";
+ s.op->newline(1) << "_stp_procfs_files[i]->write_proc = &_stp_procfs_write;";
+ s.op->newline(-1) << "else";
+ s.op->newline(1) << "_stp_procfs_files[i]->write_proc = NULL;";
+ s.op->indent(-1);
+ }
+ else
+ s.op->newline() << "_stp_procfs_files[i]->write_proc = NULL;";
+
+ s.op->newline() << "_stp_procfs_files[i]->data = spp;";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+
+void
+procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes_by_path.empty())
+ return;
+
+ s.op->newline() << "_stp_close_procfs();";
+}
+
+
+void
+procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
+{
+ assert(e->base_name.size() > 0 && e->base_name[0] == '$');
+
+ if (e->base_name != "$value")
+ throw semantic_error ("invalid target symbol for procfs probe, $value expected",
+ e->tok);
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("procfs target variable '$value' may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("procfs target variable '$value' may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid use of procfs target variable '$value'",
+ e->tok);
+ break;
+ }
+ }
+
+ bool lvalue = is_active_lvalue(e);
+ if (write_probe && lvalue)
+ throw semantic_error("procfs $value variable is read-only in a procfs write probe", e->tok);
+ else if (! write_probe && ! lvalue)
+ throw semantic_error("procfs $value variable cannot be read in a procfs read probe", 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(lvalue ? "_procfs_value_set" : "_procfs_value_get")
+ + "_" + lex_cast<string>(tick++));
+ string locvalue = "CONTEXT->data";
+
+ if (! lvalue)
+ ec->code = string("strlcpy (THIS->__retvalue, ") + locvalue
+ + string(", MAXSTRINGLEN); /* pure */");
+ else
+ ec->code = string("strlcpy (") + locvalue
+ + string(", THIS->value, MAXSTRINGLEN);");
+
+ fdecl->name = fname;
+ fdecl->body = ec;
+ fdecl->type = pe_string;
+
+ if (lvalue)
+ {
+ // Modify the fdecl so it carries a single pe_string formal
+ // argument called "value".
+
+ vardecl *v = new vardecl;
+ v->type = pe_string;
+ v->name = "value";
+ v->tok = e->tok;
+ fdecl->formal_args.push_back(v);
+ }
+ sess.functions[fdecl->name]=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
+
+ if (lvalue)
+ {
+ // Provide the functioncall to our parent, so that it can be
+ // used to substitute for the assignment node immediately above
+ // us.
+ assert(!target_symbol_setter_functioncalls.empty());
+ *(target_symbol_setter_functioncalls.top()) = n;
+ }
+
+ provide (n);
+}
+
+
+struct procfs_builder: public derived_probe_builder
+{
+ procfs_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results);
+};
+
+
+void
+procfs_builder::build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+{
+ string path;
+ bool has_procfs = get_param(parameters, TOK_PROCFS, path);
+ bool has_read = (parameters.find(TOK_READ) != parameters.end());
+ bool has_write = (parameters.find(TOK_WRITE) != parameters.end());
+
+ // If no procfs path, default to "command". The runtime will do
+ // this for us, but if we don't do it here, we'll think the
+ // following 2 probes are attached to different paths:
+ //
+ // probe procfs("command").read {}"
+ // probe procfs.write {}
+
+ if (! has_procfs)
+ path = "command";
+ // If we have a path, we need to validate it.
+ else
+ {
+ string::size_type start_pos, end_pos;
+ string component;
+ start_pos = 0;
+ while ((end_pos = path.find('/', start_pos)) != string::npos)
+ {
+ // Make sure it doesn't start with '/'.
+ if (end_pos == 0)
+ throw semantic_error ("procfs path cannot start with a '/'",
+ location->tok);
+
+ component = path.substr(start_pos, end_pos - start_pos);
+ // Make sure it isn't empty.
+ if (component.size() == 0)
+ throw semantic_error ("procfs path component cannot be empty",
+ location->tok);
+ // Make sure it isn't relative.
+ else if (component == "." || component == "..")
+ throw semantic_error ("procfs 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 ("procfs path cannot end with a '/'", location->tok);
+ // Make sure it isn't relative.
+ else if (component == "." || component == "..")
+ throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok);
+ }
+
+ if (!(has_read ^ has_write))
+ throw semantic_error ("need read/write component", location->tok);
+
+ finished_results.push_back(new procfs_derived_probe(sess, base, location,
+ path, has_write));
+}
+
+
+void
+register_tapset_procfs(systemtap_session& s)
+{
+ match_node* root = s.pattern_root;
+ derived_probe_builder *builder = new procfs_builder();
+
+ root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
+ root->bind_str(TOK_PROCFS)->bind(TOK_READ)->bind(builder);
+ root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
+ root->bind_str(TOK_PROCFS)->bind(TOK_WRITE)->bind(builder);
+}
+
+
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset-timers.cxx b/tapset-timers.cxx
new file mode 100644
index 00000000..d32a22a6
--- /dev/null
+++ b/tapset-timers.cxx
@@ -0,0 +1,626 @@
+// tapset for timers
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "translate.h"
+#include "util.h"
+
+#include <cstring>
+#include <string>
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+static string TOK_TIMER("timer");
+
+
+// ------------------------------------------------------------------------
+// timer derived probes
+// ------------------------------------------------------------------------
+
+
+struct timer_derived_probe: public derived_probe
+{
+ int64_t interval, randomize;
+ bool time_is_msecs; // NB: hrtimers get ms-based probes on modern kernels instead
+ timer_derived_probe (probe* p, probe_point* l,
+ int64_t i, int64_t r, bool ms=false);
+ virtual void join_group (systemtap_session& s);
+};
+
+
+struct timer_derived_probe_group: public generic_dpg<timer_derived_probe>
+{
+ void emit_interval (translator_output* o);
+public:
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+timer_derived_probe::timer_derived_probe (probe* p, probe_point* l,
+ int64_t i, int64_t r, bool ms):
+ derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms)
+{
+ if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints
+ throw semantic_error ("invalid interval for jiffies timer");
+ // randomize = 0 means no randomization
+ if (randomize < 0 || randomize > interval)
+ throw semantic_error ("invalid randomize for jiffies timer");
+
+ if (locations.size() != 1)
+ throw semantic_error ("expect single probe point");
+ // so we don't have to loop over them in the other functions
+}
+
+
+void
+timer_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.timer_derived_probes)
+ s.timer_derived_probes = new timer_derived_probe_group ();
+ s.timer_derived_probes->enroll (this);
+}
+
+
+void
+timer_derived_probe_group::emit_interval (translator_output* o)
+{
+ o->line() << "({";
+ o->newline(1) << "unsigned i = stp->intrv;";
+ o->newline() << "if (stp->rnd != 0)";
+ o->newline(1) << "i += _stp_random_pm(stp->rnd);";
+ o->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;";
+ o->newline(-1) << "})";
+}
+
+
+void
+timer_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "/* ---- timer probes ---- */";
+
+ s.op->newline() << "static struct stap_timer_probe {";
+ s.op->newline(1) << "struct timer_list timer_list;";
+ s.op->newline() << "const char *pp;";
+ s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "unsigned intrv, ms, rnd;";
+ s.op->newline(-1) << "} stap_timer_probes [" << probes.size() << "] = {";
+ s.op->indent(1);
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ s.op->newline () << "{";
+ s.op->line() << " .pp="
+ << lex_cast_qstring (*probes[i]->sole_location()) << ",";
+ s.op->line() << " .ph=&" << probes[i]->name << ",";
+ s.op->line() << " .intrv=" << probes[i]->interval << ",";
+ s.op->line() << " .ms=" << probes[i]->time_is_msecs << ",";
+ s.op->line() << " .rnd=" << probes[i]->randomize;
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline();
+
+ s.op->newline() << "static void enter_timer_probe (unsigned long val) {";
+ s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];";
+ s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
+ s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING))";
+ s.op->newline(1) << "mod_timer (& stp->timer_list, jiffies + ";
+ emit_interval (s.op);
+ s.op->line() << ");";
+ s.op->newline(-1) << "{";
+ s.op->indent(1);
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp");
+ s.op->newline() << "(*stp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+}
+
+
+void
+timer_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];";
+ s.op->newline() << "probe_point = stp->pp;";
+ s.op->newline() << "init_timer (& stp->timer_list);";
+ s.op->newline() << "stp->timer_list.function = & enter_timer_probe;";
+ s.op->newline() << "stp->timer_list.data = i;"; // NB: important!
+ // copy timer renew calculations from above :-(
+ s.op->newline() << "stp->timer_list.expires = jiffies + ";
+ emit_interval (s.op);
+ s.op->line() << ";";
+ s.op->newline() << "add_timer (& stp->timer_list);";
+ // note: no partial failure rollback is needed: add_timer cannot fail.
+ s.op->newline(-1) << "}"; // for loop
+}
+
+
+void
+timer_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
+ s.op->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);";
+ s.op->indent(-1);
+}
+
+
+
+// ------------------------------------------------------------------------
+// hrtimer derived probes
+// ------------------------------------------------------------------------
+// This is a new timer interface that provides more flexibility in specifying
+// intervals, and uses the hrtimer APIs when available for greater precision.
+// While hrtimers were added in 2.6.16, the API's weren't exported until
+// 2.6.17, so we must check this kernel version before attempting to use
+// hrtimers.
+//
+// * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
+
+
+struct hrtimer_derived_probe: public derived_probe
+{
+ // set a (generous) maximum of one day in ns
+ static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL;
+
+ // 100us seems like a reasonable minimum
+ static const int64_t min_ns_interval = 100000LL;
+
+ int64_t interval, randomize;
+
+ hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r,
+ int64_t scale):
+ derived_probe (p, l), interval (i), randomize (r)
+ {
+ if ((i < min_ns_interval) || (i > max_ns_interval))
+ throw semantic_error(string("interval value out of range (")
+ + lex_cast<string>(scale < min_ns_interval
+ ? min_ns_interval/scale : 1)
+ + ","
+ + lex_cast<string>(max_ns_interval/scale) + ")");
+
+ // randomize = 0 means no randomization
+ if ((r < 0) || (r > i))
+ throw semantic_error("randomization value out of range");
+ }
+
+ void join_group (systemtap_session& s);
+};
+
+
+struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
+{
+ void emit_interval (translator_output* o);
+public:
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+void
+hrtimer_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.hrtimer_derived_probes)
+ s.hrtimer_derived_probes = new hrtimer_derived_probe_group ();
+ s.hrtimer_derived_probes->enroll (this);
+}
+
+
+void
+hrtimer_derived_probe_group::emit_interval (translator_output* o)
+{
+ o->line() << "({";
+ o->newline(1) << "unsigned long nsecs;";
+ o->newline() << "int64_t i = stp->intrv;";
+ o->newline() << "if (stp->rnd != 0) {";
+ // XXX: why not use stp_random_pm instead of this?
+ o->newline(1) << "int64_t r;";
+ o->newline() << "get_random_bytes(&r, sizeof(r));";
+ // ensure that r is positive
+ o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;";
+ o->newline() << "r = _stp_mod64(NULL, r, (2*stp->rnd+1));";
+ o->newline() << "r -= stp->rnd;";
+ o->newline() << "i += r;";
+ o->newline(-1) << "}";
+ o->newline() << "if (unlikely(i < stap_hrtimer_resolution))";
+ o->newline(1) << "i = stap_hrtimer_resolution;";
+ o->indent(-1);
+ o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);";
+ o->newline() << "ktime_set(i, nsecs);";
+ o->newline(-1) << "})";
+}
+
+
+void
+hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "/* ---- hrtimer probes ---- */";
+
+ s.op->newline() << "static unsigned long stap_hrtimer_resolution;"; // init later
+ s.op->newline() << "static struct stap_hrtimer_probe {";
+ s.op->newline(1) << "struct hrtimer hrtimer;";
+ s.op->newline() << "const char *pp;";
+ s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "int64_t intrv, rnd;";
+ s.op->newline(-1) << "} stap_hrtimer_probes [" << probes.size() << "] = {";
+ s.op->indent(1);
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ s.op->newline () << "{";
+ s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location()) << ",";
+ s.op->line() << " .ph=&" << probes[i]->name << ",";
+ s.op->line() << " .intrv=" << probes[i]->interval << "LL,";
+ s.op->line() << " .rnd=" << probes[i]->randomize << "LL";
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline();
+
+ // autoconf: add get/set expires if missing (pre 2.6.28-rc1)
+ s.op->newline() << "#ifndef STAPCONF_HRTIMER_GETSET_EXPIRES";
+ s.op->newline() << "#define hrtimer_get_expires(timer) ((timer)->expires)";
+ s.op->newline() << "#define hrtimer_set_expires(timer, time) (void)((timer)->expires = (time))";
+ s.op->newline() << "#endif";
+
+ // autoconf: adapt to HRTIMER_REL -> HRTIMER_MODE_REL renaming near 2.6.21
+ s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
+ s.op->newline() << "#define HRTIMER_MODE_REL HRTIMER_REL";
+ s.op->newline() << "#endif";
+
+ // The function signature changed in 2.6.21.
+ s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
+ s.op->newline() << "static int ";
+ s.op->newline() << "#else";
+ s.op->newline() << "static enum hrtimer_restart ";
+ s.op->newline() << "#endif";
+ s.op->newline() << "enter_hrtimer_probe (struct hrtimer *timer) {";
+
+ s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
+ s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
+ s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
+ s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {";
+ // Compute next trigger time
+ s.op->newline(1) << "hrtimer_set_expires(timer, ktime_add (hrtimer_get_expires(timer),";
+ emit_interval (s.op);
+ s.op->line() << "));";
+ s.op->newline() << "rc = HRTIMER_RESTART;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "{";
+ s.op->indent(1);
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp");
+ s.op->newline() << "(*stp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline(-1) << "}";
+ s.op->newline() << "return rc;";
+ s.op->newline(-1) << "}";
+}
+
+
+void
+hrtimer_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "{";
+ s.op->newline(1) << "struct timespec res;";
+ s.op->newline() << "hrtimer_get_res (CLOCK_MONOTONIC, &res);";
+ s.op->newline() << "stap_hrtimer_resolution = timespec_to_ns (&res);";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
+ s.op->newline() << "probe_point = stp->pp;";
+ s.op->newline() << "hrtimer_init (& stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);";
+ s.op->newline() << "stp->hrtimer.function = & enter_hrtimer_probe;";
+ // There is no hrtimer field to identify *this* (i-th) probe handler
+ // callback. So instead we'll deduce it at entry time.
+ s.op->newline() << "(void) hrtimer_start (& stp->hrtimer, ";
+ emit_interval (s.op);
+ s.op->line() << ", HRTIMER_MODE_REL);";
+ // Note: no partial failure rollback is needed: hrtimer_start only
+ // "fails" if the timer was already active, which cannot be.
+ s.op->newline(-1) << "}"; // for loop
+}
+
+
+void
+hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
+ s.op->newline(1) << "hrtimer_cancel (& stap_hrtimer_probes[i].hrtimer);";
+ s.op->indent(-1);
+}
+
+
+
+// ------------------------------------------------------------------------
+// profile derived probes
+// ------------------------------------------------------------------------
+// On kernels < 2.6.10, this uses the register_profile_notifier API to
+// generate the timed events for profiling; on kernels >= 2.6.10 this
+// uses the register_timer_hook API. The latter doesn't currently allow
+// simultaneous users, so insertion will fail if the profiler is busy.
+// (Conflicting users may include OProfile, other SystemTap probes, etc.)
+
+
+struct profile_derived_probe: public derived_probe
+{
+ profile_derived_probe (systemtap_session &s, probe* p, probe_point* l);
+ void join_group (systemtap_session& s);
+};
+
+
+struct profile_derived_probe_group: public generic_dpg<profile_derived_probe>
+{
+public:
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+
+profile_derived_probe::profile_derived_probe (systemtap_session &, probe* p, probe_point* l):
+ derived_probe(p, l)
+{
+}
+
+
+void
+profile_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.profile_derived_probes)
+ s.profile_derived_probes = new profile_derived_probe_group ();
+ s.profile_derived_probes->enroll (this);
+}
+
+
+// timer.profile probe handlers are hooked up in an entertaining way
+// to the underlying kernel facility. The fact that 2.6.11+ era
+// "register_timer_hook" API allows only one consumer *system-wide*
+// will give a hint. We will have a single entry function (and thus
+// trivial registration / unregistration), and it will call all probe
+// handler functions in sequence.
+
+void
+profile_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ // kernels < 2.6.10: use register_profile_notifier API
+ // kernels >= 2.6.10: use register_timer_hook API
+ s.op->newline() << "/* ---- profile probes ---- */";
+
+ // This function calls all the profiling probe handlers in sequence.
+ // The only tricky thing is that the context will be reused amongst
+ // them. While a simple sequence of calls to the individual probe
+ // handlers is unlikely to go terribly wrong (with c->last_error
+ // being set causing an early return), but for extra assurance, we
+ // open-code the same logic here.
+
+ s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {";
+ s.op->indent(1);
+ string pp = lex_cast_qstring("timer.profile"); // hard-coded for convenience
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", pp);
+ s.op->newline() << "c->regs = regs;";
+
+ for (unsigned i=0; i<probes.size(); i++)
+ {
+ if (i > 0)
+ {
+ // Some lightweight inter-probe context resetting
+ // XXX: not quite right: MAXERRORS not respected
+ s.op->newline() << "c->actionremaining = MAXACTION;";
+ }
+ s.op->newline() << "if (c->last_error == NULL) " << probes[i]->name << " (c);";
+ }
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
+
+ s.op->newline() << "static int enter_profile_probes (struct notifier_block *self,"
+ << " unsigned long val, void *data) {";
+ s.op->newline(1) << "(void) self; (void) val;";
+ s.op->newline() << "enter_all_profile_probes ((struct pt_regs *) data);";
+ s.op->newline() << "return 0;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "struct notifier_block stap_profile_notifier = {"
+ << " .notifier_call = & enter_profile_probes };";
+
+ s.op->newline() << "#else";
+
+ s.op->newline() << "static int enter_profile_probes (struct pt_regs *regs) {";
+ s.op->newline(1) << "enter_all_profile_probes (regs);";
+ s.op->newline() << "return 0;";
+ s.op->newline(-1) << "}";
+
+ s.op->newline() << "#endif";
+}
+
+
+void
+profile_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience
+ s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
+ s.op->newline() << "rc = register_profile_notifier (& stap_profile_notifier);";
+ s.op->newline() << "#else";
+ s.op->newline() << "rc = register_timer_hook (& enter_profile_probes);";
+ s.op->newline() << "#endif";
+}
+
+
+void
+profile_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
+ s.op->newline(1) << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
+ s.op->newline() << "unregister_profile_notifier (& stap_profile_notifier);";
+ s.op->newline() << "#else";
+ s.op->newline() << "unregister_timer_hook (& enter_profile_probes);";
+ s.op->newline() << "#endif";
+ s.op->indent(-1);
+}
+
+
+
+// ------------------------------------------------------------------------
+// unified probe builder for timer probes
+// ------------------------------------------------------------------------
+
+
+struct timer_builder: public derived_probe_builder
+{
+ virtual void build(systemtap_session & sess,
+ probe * base, probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results);
+
+ static void register_patterns(systemtap_session& s);
+};
+
+void
+timer_builder::build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+{
+ int64_t scale=1, period, rand=0;
+
+ if (has_null_param(parameters, "profile"))
+ {
+ sess.unwindsym_modules.insert ("kernel");
+ finished_results.push_back
+ (new profile_derived_probe(sess, base, location));
+ return;
+ }
+
+ if (!get_param(parameters, "randomize", rand))
+ rand = 0;
+
+ if (get_param(parameters, "jiffies", period))
+ {
+ // always use basic timers for jiffies
+ finished_results.push_back
+ (new timer_derived_probe(base, location, period, rand, false));
+ return;
+ }
+ else if (get_param(parameters, "hz", period))
+ {
+ if (period <= 0)
+ throw semantic_error ("frequency must be greater than 0");
+ period = (1000000000 + period - 1)/period;
+ }
+ else if (get_param(parameters, "s", period) ||
+ get_param(parameters, "sec", period))
+ {
+ scale = 1000000000;
+ period *= scale;
+ rand *= scale;
+ }
+ else if (get_param(parameters, "ms", period) ||
+ get_param(parameters, "msec", period))
+ {
+ scale = 1000000;
+ period *= scale;
+ rand *= scale;
+ }
+ else if (get_param(parameters, "us", period) ||
+ get_param(parameters, "usec", period))
+ {
+ scale = 1000;
+ period *= scale;
+ rand *= scale;
+ }
+ else if (get_param(parameters, "ns", period) ||
+ get_param(parameters, "nsec", period))
+ {
+ // ok
+ }
+ else
+ throw semantic_error ("unrecognized timer variant");
+
+ // Redirect wallclock-time based probes to hrtimer code on recent
+ // enough kernels.
+ if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0)
+ {
+ // hrtimers didn't exist, so use the old-school timers
+ period = (period + 1000000 - 1)/1000000;
+ rand = (rand + 1000000 - 1)/1000000;
+
+ finished_results.push_back
+ (new timer_derived_probe(base, location, period, rand, true));
+ }
+ else
+ finished_results.push_back
+ (new hrtimer_derived_probe(base, location, period, rand, scale));
+}
+
+void
+register_tapset_timers(systemtap_session& s)
+{
+ match_node* root = s.pattern_root;
+ derived_probe_builder *builder = new timer_builder();
+
+ root = root->bind(TOK_TIMER);
+
+ root->bind_num("s")->bind(builder);
+ root->bind_num("s")->bind_num("randomize")->bind(builder);
+ root->bind_num("sec")->bind(builder);
+ root->bind_num("sec")->bind_num("randomize")->bind(builder);
+
+ root->bind_num("ms")->bind(builder);
+ root->bind_num("ms")->bind_num("randomize")->bind(builder);
+ root->bind_num("msec")->bind(builder);
+ root->bind_num("msec")->bind_num("randomize")->bind(builder);
+
+ root->bind_num("us")->bind(builder);
+ root->bind_num("us")->bind_num("randomize")->bind(builder);
+ root->bind_num("usec")->bind(builder);
+ root->bind_num("usec")->bind_num("randomize")->bind(builder);
+
+ root->bind_num("ns")->bind(builder);
+ root->bind_num("ns")->bind_num("randomize")->bind(builder);
+ root->bind_num("nsec")->bind(builder);
+ root->bind_num("nsec")->bind_num("randomize")->bind(builder);
+
+ root->bind_num("jiffies")->bind(builder);
+ root->bind_num("jiffies")->bind_num("randomize")->bind(builder);
+
+ root->bind_num("hz")->bind(builder);
+
+ root->bind("profile")->bind(builder);
+}
+
+
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
new file mode 100644
index 00000000..41a6f24f
--- /dev/null
+++ b/tapset-utrace.cxx
@@ -0,0 +1,1061 @@
+// utrace tapset
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "task_finder.h"
+#include "translate.h"
+#include "util.h"
+
+#include <cstring>
+#include <string>
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+static string TOK_PROCESS("process");
+static string TOK_BEGIN("begin");
+static string TOK_END("end");
+static string TOK_THREAD("thread");
+static string TOK_SYSCALL("syscall");
+static string TOK_RETURN("return");
+
+
+// ------------------------------------------------------------------------
+// utrace user-space probes
+// ------------------------------------------------------------------------
+
+// Note that these flags don't match up exactly with UTRACE_EVENT
+// flags (and that's OK).
+enum utrace_derived_probe_flags {
+ UDPF_NONE,
+ UDPF_BEGIN, // process begin
+ UDPF_END, // process end
+ UDPF_THREAD_BEGIN, // thread begin
+ UDPF_THREAD_END, // thread end
+ UDPF_SYSCALL, // syscall entry
+ UDPF_SYSCALL_RETURN, // syscall exit
+ UDPF_NFLAGS
+};
+
+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_visitor: public var_expanding_visitor
+{
+ utrace_var_expanding_visitor(systemtap_session& s, probe_point* l,
+ const string& pn,
+ enum utrace_derived_probe_flags f):
+ sess (s), base_loc (l), probe_name (pn), flags (f),
+ target_symbol_seen (false), add_block(NULL), add_probe(NULL) {}
+
+ systemtap_session& sess;
+ probe_point* base_loc;
+ string probe_name;
+ enum utrace_derived_probe_flags flags;
+ bool target_symbol_seen;
+ block *add_block;
+ probe *add_probe;
+ std::map<std::string, symbol *> return_ts_map;
+
+ void visit_target_symbol_arg (target_symbol* e);
+ void visit_target_symbol_context (target_symbol* e);
+ void visit_target_symbol_cached (target_symbol* e);
+ 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, new probe_point (*l) /* .components soon rewritten */ ),
+ has_path(hp), path(pn), pid(pd), flags(f),
+ target_symbol_seen(false)
+{
+ // Expand local variables in the probe body
+ utrace_var_expanding_visitor v (s, l, name, flags);
+ this->body = v.require (this->body);
+ target_symbol_seen = v.target_symbol_seen;
+
+ // 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 = 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.
+ if (v.add_probe)
+ {
+ stapfile *f = new stapfile;
+ f->probes.push_back(v.add_probe);
+ s.files.push_back(f);
+ }
+
+ // Reset the sole element of the "locations" vector as a
+ // "reverse-engineered" form of the incoming (q.base_loc) probe
+ // point. This allows a user to see what program etc.
+ // number any particular match of the wildcards.
+
+ vector<probe_point::component*> comps;
+ if (hp)
+ comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path)));
+ else if (pid != 0)
+ comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid)));
+ else
+ comps.push_back (new probe_point::component(TOK_PROCESS));
+
+ switch (flags)
+ {
+ case UDPF_THREAD_BEGIN:
+ comps.push_back (new probe_point::component(TOK_THREAD));
+ comps.push_back (new probe_point::component(TOK_BEGIN));
+ break;
+ case UDPF_THREAD_END:
+ comps.push_back (new probe_point::component(TOK_THREAD));
+ comps.push_back (new probe_point::component(TOK_END));
+ break;
+ case UDPF_SYSCALL:
+ comps.push_back (new probe_point::component(TOK_SYSCALL));
+ break;
+ case UDPF_SYSCALL_RETURN:
+ comps.push_back (new probe_point::component(TOK_SYSCALL));
+ comps.push_back (new probe_point::component(TOK_RETURN));
+ break;
+ case UDPF_BEGIN:
+ comps.push_back (new probe_point::component(TOK_BEGIN));
+ break;
+ case UDPF_END:
+ comps.push_back (new probe_point::component(TOK_END));
+ break;
+ default:
+ assert (0);
+ }
+
+ // Overwrite it.
+ this->sole_location()->components = comps;
+}
+
+
+void
+utrace_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.utrace_derived_probes)
+ {
+ s.utrace_derived_probes = new utrace_derived_probe_group ();
+ }
+ s.utrace_derived_probes->enroll (this);
+
+ enable_task_finder(s);
+}
+
+
+void
+utrace_var_expanding_visitor::visit_target_symbol_cached (target_symbol* e)
+{
+ // Get the full name of the target symbol.
+ stringstream ts_name_stream;
+ e->print(ts_name_stream);
+ string ts_name = ts_name_stream.str();
+
+ // Check and make sure we haven't already seen this target
+ // variable in this return probe. If we have, just return our
+ // last replacement.
+ map<string, symbol *>::iterator i = return_ts_map.find(ts_name);
+ if (i != return_ts_map.end())
+ {
+ provide (i->second);
+ return;
+ }
+
+ // We've got to do several things here to handle target
+ // variables in return probes.
+
+ // (1) Synthesize a global array which is the cache of the
+ // target variable value. We don't need a nesting level counter
+ // like the dwarf_var_expanding_visitor::visit_target_symbol()
+ // does since a particular thread can only be in one system
+ // calls at a time. The array will look like this:
+ //
+ // _utrace_tvar_{name}_{num}
+ string aname = (string("_utrace_tvar_")
+ + e->base_name.substr(1)
+ + "_" + lex_cast<string>(tick++));
+ vardecl* vd = new vardecl;
+ vd->name = aname;
+ vd->tok = e->tok;
+ sess.globals.push_back (vd);
+
+ // (2) Create a new code block we're going to insert at the
+ // beginning of this probe to get the cached value into a
+ // temporary variable. We'll replace the target variable
+ // reference with the temporary variable reference. The code
+ // will look like this:
+ //
+ // _utrace_tvar_tid = tid()
+ // _utrace_tvar_{name}_{num}_tmp
+ // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
+ // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
+
+ // (2a) Synthesize the tid temporary expression, which will look
+ // like this:
+ //
+ // _utrace_tvar_tid = tid()
+ symbol* tidsym = new symbol;
+ tidsym->name = string("_utrace_tvar_tid");
+ tidsym->tok = e->tok;
+
+ if (add_block == NULL)
+ {
+ add_block = new block;
+ add_block->tok = e->tok;
+
+ // Synthesize a functioncall to grab the thread id.
+ functioncall* fc = new functioncall;
+ fc->tok = e->tok;
+ fc->function = string("tid");
+
+ // Assign the tid to '_utrace_tvar_tid'.
+ assignment* a = new assignment;
+ a->tok = e->tok;
+ a->op = "=";
+ a->left = tidsym;
+ a->right = fc;
+
+ expr_statement* es = new expr_statement;
+ es->tok = e->tok;
+ es->value = a;
+ add_block->statements.push_back (es);
+ }
+
+ // (2b) Synthesize an array reference and assign it to a
+ // temporary variable (that we'll use as replacement for the
+ // target variable reference). It will look like this:
+ //
+ // _utrace_tvar_{name}_{num}_tmp
+ // = _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
+
+ arrayindex* ai_tvar = new arrayindex;
+ ai_tvar->tok = e->tok;
+
+ symbol* sym = new symbol;
+ sym->name = aname;
+ sym->tok = e->tok;
+ ai_tvar->base = sym;
+
+ ai_tvar->indexes.push_back(tidsym);
+
+ symbol* tmpsym = new symbol;
+ tmpsym->name = aname + "_tmp";
+ tmpsym->tok = e->tok;
+
+ assignment* a = new assignment;
+ a->tok = e->tok;
+ a->op = "=";
+ a->left = tmpsym;
+ a->right = ai_tvar;
+
+ expr_statement* es = new expr_statement;
+ es->tok = e->tok;
+ es->value = a;
+
+ add_block->statements.push_back (es);
+
+ // (2c) Delete the array value. It will look like this:
+ //
+ // delete _utrace_tvar_{name}_{num}[_utrace_tvar_tid]
+
+ delete_statement* ds = new delete_statement;
+ ds->tok = e->tok;
+ ds->value = ai_tvar;
+ add_block->statements.push_back (ds);
+
+ // (3) We need an entry probe that saves the value for us in the
+ // global array we created. Create the entry probe, which will
+ // look like this:
+ //
+ // probe process(PATH_OR_PID).syscall {
+ // _utrace_tvar_tid = tid()
+ // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param}
+ // }
+ //
+ // Why the temporary for tid()? If we end up caching more
+ // than one target variable, we can reuse the temporary instead
+ // of calling tid() multiple times.
+
+ if (add_probe == NULL)
+ {
+ add_probe = new probe;
+ add_probe->tok = e->tok;
+
+ // We need the name of the current probe point, minus the
+ // ".return". Create a new probe point, copying all the
+ // components, stopping when we see the ".return"
+ // component.
+ probe_point* pp = new probe_point;
+ for (unsigned c = 0; c < base_loc->components.size(); c++)
+ {
+ if (base_loc->components[c]->functor == "return")
+ break;
+ else
+ pp->components.push_back(base_loc->components[c]);
+ }
+ pp->tok = e->tok;
+ pp->optional = base_loc->optional;
+ add_probe->locations.push_back(pp);
+
+ add_probe->body = new block;
+ add_probe->body->tok = e->tok;
+
+ // Synthesize a functioncall to grab the thread id.
+ functioncall* fc = new functioncall;
+ fc->tok = e->tok;
+ fc->function = string("tid");
+
+ // Assign the tid to '_utrace_tvar_tid'.
+ assignment* a = new assignment;
+ a->tok = e->tok;
+ a->op = "=";
+ a->left = tidsym;
+ a->right = fc;
+
+ expr_statement* es = new expr_statement;
+ es->tok = e->tok;
+ es->value = a;
+ add_probe->body = new block(add_probe->body, es);
+
+ vardecl* vd = new vardecl;
+ vd->tok = e->tok;
+ vd->name = tidsym->name;
+ vd->type = pe_long;
+ vd->set_arity(0);
+ add_probe->locals.push_back(vd);
+ }
+
+ // Save the value, like this:
+ //
+ // _utrace_tvar_{name}_{num}[_utrace_tvar_tid] = ${param}
+ a = new assignment;
+ a->tok = e->tok;
+ a->op = "=";
+ a->left = ai_tvar;
+ a->right = e;
+
+ es = new expr_statement;
+ es->tok = e->tok;
+ es->value = a;
+
+ add_probe->body = new block(add_probe->body, es);
+
+ // (4) Provide the '_utrace_tvar_{name}_{num}_tmp' variable to
+ // our parent so it can be used as a substitute for the target
+ // symbol.
+ provide (tmpsym);
+
+ // (5) Remember this replacement since we might be able to reuse
+ // it later if the same return probe references this target
+ // symbol again.
+ return_ts_map[ts_name] = tmpsym;
+ return;
+}
+
+
+void
+utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
+{
+ string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
+ int argnum = lex_cast<int>(argnum_s);
+
+ if (flags != UDPF_SYSCALL)
+ throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN.", 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 '$argN' may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("utrace target variable '$argN' may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid use of utrace target variable '$argN'",
+ e->tok);
+ break;
+ }
+ }
+
+ // FIXME: max argnument number should not be hardcoded.
+ if (argnum < 1 || argnum > 6)
+ throw semantic_error ("invalid syscall argument number (1-6)", e->tok);
+
+ bool lvalue = is_active_lvalue(e);
+ if (lvalue)
+ throw semantic_error("utrace '$argN' variable is read-only", e->tok);
+
+ // Remember that we've seen a target variable.
+ target_symbol_seen = true;
+
+ // We're going to substitute a synthesized '_utrace_syscall_arg'
+ // function call for the '$argN' reference.
+ functioncall* n = new functioncall;
+ n->tok = e->tok;
+ n->function = "_utrace_syscall_arg";
+ n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
+
+ literal_number *num = new literal_number(argnum - 1);
+ num->tok = e->tok;
+ n->args.push_back(num);
+
+ provide (n);
+}
+
+void
+utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
+{
+ string sname = e->base_name;
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("utrace target variable '" + sname + "' may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("utrace target variable '" + sname + "' may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid use of utrace target variable '" + sname + "'",
+ e->tok);
+ break;
+ }
+ }
+
+ bool lvalue = is_active_lvalue(e);
+ if (lvalue)
+ throw semantic_error("utrace '" + sname + "' variable is read-only", e->tok);
+
+ string fname;
+ if (sname == "$return")
+ {
+ if (flags != UDPF_SYSCALL_RETURN)
+ throw semantic_error ("only \"process(PATH_OR_PID).syscall.return\" support $return.", e->tok);
+ fname = "_utrace_syscall_return";
+ }
+ else if (sname == "$syscall")
+ {
+ // If we've got a syscall entry probe, we can just call the
+ // right function.
+ if (flags == UDPF_SYSCALL) {
+ fname = "_utrace_syscall_nr";
+ }
+ // If we're in a syscal return probe, we can't really access
+ // $syscall. So, similar to what
+ // dwarf_var_expanding_visitor::visit_target_symbol() does,
+ // we'll create an syscall entry probe to cache $syscall, then
+ // we'll access the cached value in the syscall return probe.
+ else {
+ visit_target_symbol_cached (e);
+
+ // Remember that we've seen a target variable.
+ target_symbol_seen = true;
+ return;
+ }
+ }
+ else
+ {
+ throw semantic_error ("unknown target variable", e->tok);
+ }
+
+ // Remember that we've seen a target variable.
+ target_symbol_seen = true;
+
+ // We're going to substitute a synthesized '_utrace_syscall_nr'
+ // function call for the '$syscall' reference.
+ 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 (n);
+}
+
+void
+utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
+{
+ assert(e->base_name.size() > 0 && e->base_name[0] == '$');
+
+ if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
+ throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols",
+ e->tok);
+
+ if (e->base_name.substr(0,4) == "$arg")
+ visit_target_symbol_arg(e);
+ else if (e->base_name == "$syscall" || e->base_name == "$return")
+ visit_target_symbol_context(e);
+ else
+ throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected",
+ e->tok);
+}
+
+
+struct utrace_builder: public derived_probe_builder
+{
+ utrace_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t 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;
+
+ if (has_null_param (parameters, TOK_THREAD))
+ {
+ if (has_null_param (parameters, TOK_BEGIN))
+ flags = UDPF_THREAD_BEGIN;
+ else if (has_null_param (parameters, TOK_END))
+ flags = UDPF_THREAD_END;
+ }
+ else if (has_null_param (parameters, TOK_SYSCALL))
+ {
+ if (has_null_param (parameters, TOK_RETURN))
+ flags = UDPF_SYSCALL_RETURN;
+ else
+ flags = UDPF_SYSCALL;
+ }
+ else if (has_null_param (parameters, TOK_BEGIN))
+ flags = UDPF_BEGIN;
+ else if (has_null_param (parameters, TOK_END))
+ flags = UDPF_END;
+
+ // If we didn't get a path or pid, this means to probe everything.
+ // Convert this to a pid-based probe.
+ if (! has_path && ! has_pid)
+ {
+ has_path = false;
+ path.clear();
+ has_pid = true;
+ pid = 0;
+ }
+ else if (has_path)
+ {
+ path = find_executable (path);
+ sess.unwindsym_modules.insert (path);
+ }
+ else if (has_pid)
+ {
+ // We can't probe 'init' (pid 1). XXX: where does this limitation come from?
+ if (pid < 2)
+ throw semantic_error ("process pid must be greater than 1",
+ location->tok);
+
+ // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere?
+ }
+
+ 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() << " .mmap_callback=NULL,";
+ s.op->line() << " .munmap_callback=NULL,";
+ s.op->line() << " .mprotect_callback=NULL,";
+ s.op->line() << " },";
+ s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
+ s.op->line() << " .ph=&" << p->name << ",";
+
+ // Handle flags
+ switch (p->flags)
+ {
+ // Notice that we'll just call the probe directly when we get
+ // notified, since the task_finder layer stops the thread for us.
+ case UDPF_BEGIN: // process begin
+ s.op->line() << " .flags=(UDPF_BEGIN),";
+ break;
+ case UDPF_THREAD_BEGIN: // thread begin
+ s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
+ break;
+
+ // Notice we're not setting up a .ops/.report_death handler for
+ // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call
+ // the probe directly when we get notified.
+ case UDPF_END: // process end
+ s.op->line() << " .flags=(UDPF_END),";
+ break;
+ case UDPF_THREAD_END: // thread end
+ s.op->line() << " .flags=(UDPF_THREAD_END),";
+ break;
+
+ // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death
+ // handler isn't strictly necessary. However, it helps to keep
+ // our attaches/detaches symmetrical. Since the task_finder layer
+ // stops the thread, that works around bug 6841.
+ case UDPF_SYSCALL:
+ s.op->line() << " .flags=(UDPF_SYSCALL),";
+ s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
+ s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
+ break;
+ case UDPF_SYSCALL_RETURN:
+ s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
+ s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
+ s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
+ break;
+
+ case UDPF_NONE:
+ s.op->line() << " .flags=(UDPF_NONE),";
+ s.op->line() << " .ops={ },";
+ s.op->line() << " .events=0,";
+ break;
+ default:
+ throw semantic_error ("bad utrace probe flag");
+ 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() << "enum utrace_derived_probe_flags {";
+ s.op->indent(1);
+ s.op->newline() << "UDPF_NONE,";
+ s.op->newline() << "UDPF_BEGIN,";
+ s.op->newline() << "UDPF_END,";
+ s.op->newline() << "UDPF_THREAD_BEGIN,";
+ s.op->newline() << "UDPF_THREAD_END,";
+ s.op->newline() << "UDPF_SYSCALL,";
+ s.op->newline() << "UDPF_SYSCALL_RETURN,";
+ s.op->newline() << "UDPF_NFLAGS";
+ s.op->newline(-1) << "};";
+
+ s.op->newline() << "struct stap_utrace_probe {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target tgt;";
+ s.op->newline() << "const char *pp;";
+ s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "enum utrace_derived_probe_flags flags;";
+ s.op->newline() << "struct utrace_engine_ops ops;";
+ s.op->newline() << "unsigned long events;";
+ s.op->newline() << "int engine_attached;";
+ s.op->newline(-1) << "};";
+
+
+ // Output handler function for UDPF_BEGIN, UDPF_THREAD_BEGIN,
+ // UDPF_END, and UDPF_THREAD_END
+ if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
+ || flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
+ {
+ s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
+ s.op->indent(1);
+
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "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] || flags_seen[UDPF_SYSCALL_RETURN])
+ {
+ s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
+ s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
+ s.op->newline() << "#else";
+ s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
+ s.op->newline() << "#endif";
+
+ 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", "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() << "if ((atomic_read (&session_state) != STAP_SESSION_STARTING) && (atomic_read (&session_state) != STAP_SESSION_RUNNING)) {";
+ s.op->indent(1);
+ s.op->newline() << "debug_task_finder_detach();";
+ s.op->newline() << "return UTRACE_DETACH;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "return UTRACE_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 stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
+ 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 receiving a UTRACE_EVENT(CLONE) event, we can't call the
+ // begin/thread.begin probe directly. So, we'll just attach an
+ // engine that waits for the thread to quiesce. When the thread
+ // quiesces, then call the probe.
+ if (flags_seen[UDPF_BEGIN])
+ {
+ s.op->newline() << "case UDPF_BEGIN:";
+ s.op->indent(1);
+ s.op->newline() << "if (process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+ if (flags_seen[UDPF_THREAD_BEGIN])
+ {
+ s.op->newline() << "case UDPF_THREAD_BEGIN:";
+ s.op->indent(1);
+ s.op->newline() << "if (! process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ // For end/thread_end probes, do nothing at registration time.
+ // We'll handle these in the 'register_p == 0' case.
+ if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
+ {
+ s.op->newline() << "case UDPF_END:";
+ s.op->newline() << "case UDPF_THREAD_END:";
+ s.op->indent(1);
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ // Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events.
+ if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
+ {
+ s.op->newline() << "case UDPF_SYSCALL:";
+ s.op->newline() << "case UDPF_SYSCALL_RETURN:";
+ s.op->indent(1);
+ s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
+ s.op->newline() << "if (rc == 0) {";
+ s.op->indent(1);
+ s.op->newline() << "p->engine_attached = 1;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ s.op->newline() << "default:";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+
+ // Since this engine could be attached to multiple threads, don't
+ // call stap_utrace_detach_ops() here, only call
+ // stap_utrace_detach() as necessary.
+ s.op->newline() << "else {";
+ s.op->indent(1);
+ s.op->newline() << "switch (p->flags) {";
+ s.op->indent(1);
+ // For end probes, go ahead and call the probe directly.
+ if (flags_seen[UDPF_END])
+ {
+ s.op->newline() << "case UDPF_END:";
+ s.op->indent(1);
+ s.op->newline() << "if (process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+ if (flags_seen[UDPF_THREAD_END])
+ {
+ s.op->newline() << "case UDPF_THREAD_END:";
+ s.op->indent(1);
+ s.op->newline() << "if (! process_p) {";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ // For begin/thread_begin probes, we don't need to do anything.
+ if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
+ {
+ s.op->newline() << "case UDPF_BEGIN:";
+ s.op->newline() << "case UDPF_THREAD_BEGIN:";
+ s.op->indent(1);
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
+ {
+ s.op->newline() << "case UDPF_SYSCALL:";
+ s.op->newline() << "case UDPF_SYSCALL_RETURN:";
+ s.op->indent(1);
+ s.op->newline() << "stap_utrace_detach(tsk, &p->ops);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ }
+
+ s.op->newline() << "default:";
+ s.op->indent(1);
+ s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
+ s.op->newline() << "break;";
+ s.op->indent(-1);
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "return rc;";
+ s.op->newline(-1) << "}";
+
+ // Emit vma callbacks.
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "static struct stap_task_finder_target stap_utrace_vmcbs[] = {";
+ s.op->indent(1);
+ if (! probes_by_path.empty())
+ {
+ for (p_b_path_iterator it = probes_by_path.begin();
+ it != probes_by_path.end(); it++)
+ emit_vma_callback_probe_decl (s, it->first, (int64_t)0);
+ }
+ if (! probes_by_pid.empty())
+ {
+ for (p_b_pid_iterator it = probes_by_pid.begin();
+ it != probes_by_pid.end(); it++)
+ emit_vma_callback_probe_decl (s, "", it->first);
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline() << "#endif";
+
+ s.op->newline() << "static 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() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "_stp_sym_init();";
+ s.op->newline() << "/* ---- utrace vma callbacks ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_vmcbs); i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target *r = &stap_utrace_vmcbs[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(r);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#endif";
+
+ s.op->newline() << "/* ---- utrace probes ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_utrace_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<ARRAY_SIZE(stap_utrace_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) << "}";
+}
+
+
+void
+register_tapset_utrace(systemtap_session& s)
+{
+ match_node* root = s.pattern_root;
+ derived_probe_builder *builder = new utrace_builder();
+
+ vector<match_node*> roots;
+ roots.push_back(root->bind(TOK_PROCESS));
+ roots.push_back(root->bind_str(TOK_PROCESS));
+ roots.push_back(root->bind_num(TOK_PROCESS));
+
+ for (unsigned i = 0; i < roots.size(); ++i)
+ {
+ roots[i]->bind(TOK_BEGIN)->bind(builder);
+ roots[i]->bind(TOK_END)->bind(builder);
+ roots[i]->bind(TOK_THREAD)->bind(TOK_BEGIN)->bind(builder);
+ roots[i]->bind(TOK_THREAD)->bind(TOK_END)->bind(builder);
+ roots[i]->bind(TOK_SYSCALL)->bind(builder);
+ roots[i]->bind(TOK_SYSCALL)->bind(TOK_RETURN)->bind(builder);
+ }
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapset/DEVGUIDE b/tapset/DEVGUIDE
index e6bc3fb8..693521a8 100644
--- a/tapset/DEVGUIDE
+++ b/tapset/DEVGUIDE
@@ -59,8 +59,8 @@ For example, process execs can occur in either the do_execve() or the
compat_do_execve() functions. The following alias inserts probes at the
beginning of those functions:
-probe process.exec = kernel.function("do_execve"),
- kernel.function("compat_do_execve") {
+probe kprocess.exec = kernel.function("do_execve"),
+ kernel.function("compat_do_execve") {
< probe body >
}
@@ -87,7 +87,7 @@ process is retrieved by calling task_pid() and passing it the task_struct
pointer. In this case, the auxiliary function is an embedded C function
that's defined in the task tapset (task.stp).
-probe process.create = kernel.function("copy_process").return {
+probe kprocess.create = kernel.function("copy_process").return {
task = $return
new_pid = task_pid(task)
}
diff --git a/tapset/ansi.stp b/tapset/ansi.stp
new file mode 100644
index 00000000..0152fb37
--- /dev/null
+++ b/tapset/ansi.stp
@@ -0,0 +1,70 @@
+# ANSI escape sequences tapset
+# Copyright (C) 2009 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# Based on some previous work done by Masami Hiramatsu for stapgames.
+# Reference: http://en.wikipedia.org/wiki/ANSI_escape_code
+#
+
+function ansi_clear_screen() {
+ print("\033[1;1H\033[J")
+}
+
+# Foreground colors | Background colors
+# Black 30 | Black 40
+# Blue 34 | Red 41
+# Green 32 | Green 42
+# Cyan 36 | Yellow 43
+# Red 31 | Blue 44
+# Purple 35 | Magenta 45
+# Brown 33 | Cyan 46
+# Light Gray 37 | White 47
+function ansi_set_color(fg:long) {
+ printf("\033[%dm", fg)
+}
+
+function ansi_set_color2(fg:long, bg:long) {
+ printf("\033[%d;%dm", bg, fg)
+}
+
+# All attributes off 0
+# Intensity: Bold 1
+# Underline: Single 4
+# Blink: Slow 5
+# Blink: Rapid 6
+# Image: Negative 7
+function ansi_set_color3(fg:long, bg:long, attr:long) {
+ attr_str = attr ? sprintf(";%dm", attr) : "m"
+ printf("\033[%d;%d%s", bg, fg, attr_str)
+}
+
+function ansi_reset_color() {
+ ansi_set_color3(0, 0, 0)
+}
+
+function ansi_new_line() {
+ printf("\12")
+}
+
+function ansi_cursor_move(x:long, y:long) {
+ printf("\033[%d;%dH", y, x)
+}
+
+function ansi_cursor_hide() {
+ print("\033[>5I")
+}
+
+function ansi_cursor_save() {
+ print("\033[s")
+}
+
+function ansi_cursor_restore() {
+ print("\033[u")
+}
+
+function ansi_cursor_show() {
+ print("\033[>5h")
+}
diff --git a/tapset/aux_syscalls.stp b/tapset/aux_syscalls.stp
index d2e43903..9cb7a3df 100644
--- a/tapset/aux_syscalls.stp
+++ b/tapset/aux_syscalls.stp
@@ -60,10 +60,10 @@ function _struct_timezone_u:string(uaddr:long)
%}
%{
- // Needed for the following four functions
- // _struct_utimbuf_actime, _struct_utimbuf_modtime,
- // _struct_compat_utimbuf_actime, _struct_compat_utimbuf_modtime
- #include <linux/utime.h>
+// Needed for the following four functions
+// _struct_utimbuf_actime, _struct_utimbuf_modtime,
+// _struct_compat_utimbuf_actime, _struct_compat_utimbuf_modtime
+#include <linux/utime.h>
%}
// Returns the value of the actime field of a utimbuf in user space
@@ -322,17 +322,11 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
}
else if ((sa->sa_family == AF_PACKET)&&(len == sizeof(struct sockaddr_ll)))
{
- /* FIXME. This needs tested */
struct sockaddr_ll *sll = (struct sockaddr_ll *)buf;
-#if defined(__powerpc__) || defined(__ia64__) || defined(__s390x__)
- snprintf(str, strlen, "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%lx}",
- (int)sll->sll_protocol, sll->sll_ifindex, (int)sll->sll_hatype, (int)sll->sll_pkttype,
- (int)sll->sll_halen, *(uint64_t *)sll->sll_addr);
-#else
snprintf(str, strlen, "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
(int)sll->sll_protocol, sll->sll_ifindex, (int)sll->sll_hatype, (int)sll->sll_pkttype,
- (int)sll->sll_halen, *(uint64_t *)sll->sll_addr);
-#endif
+ (int)sll->sll_halen,
+ (long long)(*(uint64_t *)sll->sll_addr));
}
else
{
diff --git a/tapset/context-symbols.stp b/tapset/context-symbols.stp
index 46eab841..e4406d9b 100644
--- a/tapset/context-symbols.stp
+++ b/tapset/context-symbols.stp
@@ -6,20 +6,25 @@
// 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.
-
+// <tapsetdescription>
+// Context functions provide additional information about where an event occurred. These functions can
+//provide information such as a backtrace to where the event occured and the current register values for the
+//processor.
+// </tapsetdescription>
%{
#ifndef STP_NEED_SYMBOL_DATA
#define STP_NEED_SYMBOL_DATA 1
#endif
%}
-// weirdness with print_stack, argument appears in build as undescribed
+
/**
- * sfunction print_stack - Print out stack from string
- * @stk: String with list of hexidecimal addresses. (FIXME)
+ * sfunction print_stack - Print out stack from string.
+ * @stk: String with list of hexidecimal addresses.
*
* Perform a symbolic lookup of the addresses in the given string,
- * which is assumed to be the result of a prior call to
+ * which is assumed to be the result of a prior call to
* <command>backtrace()</command>.
+ *
* Print one line per address, including the address, the
* name of the function containing the address, and an estimate of
* its position within that function. Return nothing.
@@ -36,9 +41,7 @@ function print_stack(stk:string) %{
%}
/**
- * sfunction probefunc - Function probed
- *
- * Return the probe point's function name, if known.
+ * sfunction probefunc - Return the probe point's function name, if known.
*/
function probefunc:string () %{ /* pure */
char *ptr, *start;
@@ -63,7 +66,7 @@ function probefunc:string () %{ /* pure */
#else
((unsigned long)REG_IP(CONTEXT->regs) >= (unsigned long)PAGE_OFFSET)) {
#endif
- _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, REG_IP(CONTEXT->regs));
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, REG_IP(CONTEXT->regs), current, 0);
if (THIS->__retvalue[0] == '.') /* powerpc symbol has a dot*/
strlcpy(THIS->__retvalue,THIS->__retvalue + 1,MAXSTRINGLEN);
} else {
@@ -72,9 +75,7 @@ function probefunc:string () %{ /* pure */
%}
/**
- * sfunction probemod - Module probed
- *
- * Return the probe point's module name, if known.
+ * sfunction probemod - Return the probe point's module name, if known.
*/
function probemod:string () %{ /* pure */
char *ptr, *start;
@@ -88,8 +89,59 @@ function probemod:string () %{ /* pure */
while (*ptr != '"' && --len && *ptr)
*dst++ = *ptr++;
*dst = 0;
- } else {
- /* XXX: need a PC- and symbol-table-based fallback. */
- THIS->__retvalue[0] = '\0';
- }
+ } else if (CONTEXT->regs) {
+ struct _stp_module *m;
+ m = _stp_mod_sec_lookup (REG_IP(CONTEXT->regs), current, NULL);
+ if (m && m->name)
+ strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN);
+ else
+ strlcpy (THIS->__retvalue, "<unknown>", MAXSTRINGLEN);
+ } else
+ strlcpy (THIS->__retvalue, "<unknown>", MAXSTRINGLEN);
+%}
+
+/**
+ * sfunction modname - Return the kernel module name loaded at the address.
+ * @addr: The address.
+ *
+ * Description: Returns the module name associated with the given
+ * address if known. If not known it will return the string "<unknown>".
+ * If the address was not in a kernel module, but in the kernel itself,
+ * then the string "kernel" will be returned.
+ */
+function modname:string (addr: long) %{ /* pure */
+ struct _stp_module *m;
+ m = _stp_mod_sec_lookup (THIS->addr, current, NULL);
+ if (m && m->name)
+ strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN);
+ else
+ strlcpy (THIS->__retvalue, "<unknown>", MAXSTRINGLEN);
+%}
+
+/**
+ * sfunction symname - Return the symbol associated with the given address.
+ * @addr: The address to translate.
+ *
+ * Description: Returns the (function) symbol name associated with the
+ * given address if known. If not known it will return the hex string
+ * representation of addr.
+ */
+function symname:string (addr: long) %{ /* pure */
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, THIS->addr,
+ NULL, 0);
+%}
+
+/**
+ * sfunction symdata - Return the symbol and module offset for the address.
+ * @addr: The address to translate.
+ *
+ * Description: Returns the (function) symbol name associated with the
+ * given address if known, plus the module name (between brackets) and
+ * the offset inside the module, plus the size of the symbol function.
+ * If any element is not known it will be ommitted and if the symbol name
+ * is unknown it will return the hex string for the given address.
+ */
+function symdata:string (addr: long) %{ /* pure */
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, THIS->addr,
+ NULL, 1);
%}
diff --git a/tapset/context-unwind.stp b/tapset/context-unwind.stp
index a0836ed6..d6654d25 100644
--- a/tapset/context-unwind.stp
+++ b/tapset/context-unwind.stp
@@ -6,7 +6,11 @@
// 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.
-
+// <tapsetdescription>
+// Context functions provide additional information about where an event occurred. These functions can
+//provide information such as a backtrace to where the event occured and the current register values for the
+//processor.
+// </tapsetdescription>
%{
#ifndef STP_NEED_UNWIND_DATA
#define STP_NEED_UNWIND_DATA 1
@@ -19,12 +23,12 @@
/**
* sfunction print_backtrace - Print stack back trace
*
- * Equivalent to <command>print_stack(backtrace())</command>,
+ * Equivalent to <command>print_stack(backtrace())</command>,
* except that deeper stack nesting may be supported. Return nothing.
*/
function print_backtrace () %{
if (CONTEXT->regs) {
- _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE);
+ _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE, NULL);
} else {
_stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point);
}
@@ -33,12 +37,12 @@ function print_backtrace () %{
/**
* sfunction backtrace - Hex backtrace of current stack
*
- * Return a string of hex addresses that are a backtrace of the
- * stack. It may be truncated due to maximum string length.
+ * Return a string of hex addresses that are a backtrace of the
+ * stack. Output may be truncated as per maximum string length.
*/
function backtrace:string () %{ /* pure */
if (CONTEXT->regs)
- _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE);
+ _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN, CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE, NULL);
else
strlcpy (THIS->__retvalue, "", MAXSTRINGLEN);
%}
@@ -46,21 +50,19 @@ function backtrace:string () %{ /* pure */
/**
* sfunction caller - Return name and address of calling function
*
- * Return the address and name of the calling function.
+ * Return the address and name of the calling function.
+ * This is equivalent to calling:
+ * sprintf("%s 0x%x", symname(caller_addr(), caller_addr()))
* <emphasis>Works only for return probes at this time.</emphasis>
*/
-function caller:string() %{ /* pure */
- if (CONTEXT->pi)
- _stp_symbol_snprint( THIS->__retvalue, MAXSTRINGLEN,
- (unsigned long)_stp_ret_addr_r(CONTEXT->pi));
- else
- strlcpy(THIS->__retvalue,"unknown",MAXSTRINGLEN);
-%}
+function caller:string() {
+ return sprintf("%s 0x%x", symname(caller_addr()), caller_addr());
+}
/**
* sfunction caller_addr - Return caller address
*
- * Return the address of the calling function.
+ * Return the address of the calling function.
* <emphasis> Works only for return probes at this time.</emphasis>
*/
function caller_addr:long () %{ /* pure */
diff --git a/tapset/context.stp b/tapset/context.stp
index 7fd961c8..5d855f80 100644
--- a/tapset/context.stp
+++ b/tapset/context.stp
@@ -6,6 +6,21 @@
// 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.
+// <tapsetdescription>
+// Context functions provide additional information about where an event occurred. These functions can
+//provide information such as a backtrace to where the event occured and the current register values for the
+//processor.
+// </tapsetdescription>
+
+%{
+#include <asm/processor.h>
+
+#if defined(__powerpc64__)
+#if !defined(task_pt_regs)
+#define task_pt_regs(tsk) ((struct pt_regs *)(tsk)->thread.regs)
+#endif
+#endif
+%}
/**
* sfunction print_regs - Print a register dump.
@@ -17,37 +32,28 @@ function print_regs () %{
%}
/**
- * sfunction execname - Execname of current processes
- *
- * Return the name of the current process.
+ * sfunction execname - Returns the execname of a target process (or group of processes).
*/
function execname:string () %{ /* pure */
strlcpy (THIS->__retvalue, current->comm, MAXSTRINGLEN);
%}
/**
- * sfunction pid - Process ID of current process
- *
- *
- * Return the id of the current process.
+ * sfunction pid - Returns the ID of a target process.
*/
function pid:long () %{ /* pure */
THIS->__retvalue = current->tgid;
%}
/**
- * sfunction tid - Thread ID of current process
- *
- * Return the id of the current thread.
+ * sfunction tid - Returns the thread ID of a target process.
*/
function tid:long () %{ /* pure */
THIS->__retvalue = current->pid;
%}
/**
- * sfunction ppid - Parent Process ID of current process
- *
- * Return the id of the parent process.
+ * sfunction ppid - Returns the process ID of a target process's parent process.
*/
function ppid:long () %{ /* pure */
#if defined(STAPCONF_REAL_PARENT)
@@ -58,9 +64,19 @@ function ppid:long () %{ /* pure */
%}
/**
- * sfunction pexecname - Execname of the parent process.
- *
- * Return the name of the parent process.
+ * sfunction sid - Returns the session ID of the current process.
+ *
+ * The session ID of a process is the process group ID of the session
+ * leader. Session ID is stored in the signal_struct since Kernel 2.6.0.
+ */
+function sid:long () %{ /* pure */
+ struct signal_struct *ss = kread( &(current->signal) );
+ THIS->__retvalue = kread ( &(ss->session) );
+ CATCH_DEREF_FAULT();
+%}
+
+/**
+ * sfunction pexecname - Returns the execname of a target process's parent process.
*/
function pexecname:string () %{ /* pure */
#if defined(STAPCONF_REAL_PARENT)
@@ -71,9 +87,7 @@ function pexecname:string () %{ /* pure */
%}
/**
- * sfunction gid - Group ID of current process
- *
- * Return the gid of the current process.
+ * sfunction gid - Returns the group ID of a target process.
*/
function gid:long () %{ /* pure */
#ifdef STAPCONF_TASK_UID
@@ -84,9 +98,7 @@ function gid:long () %{ /* pure */
%}
/**
- * sfunction egid - Effective gid of the current process.
- *
- * Return the effective gid of the current process.
+ * sfunction egid - Returns the effective gid of a target process.
*/
function egid:long () %{ /* pure */
#ifdef STAPCONF_TASK_UID
@@ -97,9 +109,7 @@ function egid:long () %{ /* pure */
%}
/**
- * sfunction uid -User ID of the current process.
- *
- * Return the uid of the current process.
+ * sfunction uid - Returns the user ID of a target process.
*/
function uid:long () %{ /* pure */
#ifdef STAPCONF_TASK_UID
@@ -110,9 +120,7 @@ function uid:long () %{ /* pure */
%}
/**
- * sfunction euid - Effective User ID of the current process.
- *
- * Return the effective uid of the current process.
+ * sfunction euid - Return the effective uid of a target process.
*/
function euid:long () %{ /* pure */
#ifdef STAPCONF_TASK_UID
@@ -128,26 +136,24 @@ function cpuid:long () %{ /* pure */
%}
/**
- * sfunction cpu - The current cpu number.
- *
- * Return the current cpu number.
+ * sfunction cpu - Returns the current cpu number.
*/
function cpu:long () %{ /* pure */
THIS->__retvalue = smp_processor_id();
%}
/**
- * sfunction pp - Current probe point
- *
- * Return the probe point associated with the currently running
- * probe handler, including alias and wildcard expansion effects.
+ * sfunction pp - Return the probe point associated with the currently running probe handler,
+ * including alias and wildcard expansion effects
+ * Context:
+ * The current probe point.
*/
function pp:string () %{ /* pure */
strlcpy (THIS->__retvalue, CONTEXT->probe_point, MAXSTRINGLEN);
%}
/**
- * sfunction registers_valid - Register information valid
+ * sfunction registers_valid - Determines validity of <command>register()</command> and <command>u_register()</command> in current context.
*
* Return 1 if register() and u_register() can be used
* in the current context, or 0 otherwise.
@@ -159,7 +165,7 @@ function registers_valid:long () %{ /* pure */
%}
/**
- * sfunction user_mode - User Mode
+ * sfunction user_mode - Determines if probe point occurs in user-mode.
*
* Return 1 if the probe point occurred in user-mode.
*/
@@ -176,7 +182,7 @@ function user_mode:long () %{ /* pure */ /* currently a user-mode address? */
%}
/**
- * sfunction is_return - Is return probe
+ * sfunction is_return - Determines if probe point is a return probe.
*
* Return 1 if the probe point is a return probe.
* <emphasis>Deprecated.</emphasis>
@@ -189,9 +195,7 @@ function is_return:long () %{ /* pure */
%}
/**
- * sfunction target - Target pid
- *
- * Return the pid of the target process.
+ * sfunction target - Return the process ID of the target process.
*/
function target:long () %{ /* pure */
THIS->__retvalue = _stp_target;
@@ -220,18 +224,16 @@ function stp_pid:long () %{ /* pure */
%}
/**
- * sfunction stack_size - Size of kernel stack
- *
- * Return the size of the kernel stack.
+ * sfunction stack_size - Return the size of the kernel stack.
*/
function stack_size:long () %{ /* pure */
THIS->__retvalue = THREAD_SIZE;
%}
/**
- * sfunction stack_used - Current amount of kernel stack used
+ * sfunction stack_used - Returns the amount of kernel stack used.
*
- * Return how many bytes are currently used in the kernel stack.
+ * Determines how many bytes are currently used in the kernel stack.
*/
function stack_used:long () %{ /* pure */
char a;
@@ -239,12 +241,34 @@ function stack_used:long () %{ /* pure */
%}
/**
- * sfunction stack_unused - Amount of kernel stack currently available
+ * sfunction stack_unused - Returns the amount of kernel stack currently available.
*
- * Return how many bytes are currently available in the kernel stack.
+ * Determines how many bytes are currently available in the kernel stack.
*/
function stack_unused:long () %{ /* pure */
char a;
THIS->__retvalue = (long)&a & (THREAD_SIZE-1);
%}
+/**
+ * sfunction uaddr - User space address of current running task. EXPERIMENTAL.
+ *
+ * Description: Returns the address in userspace that the current
+ * task was at when the probe occured. When the current running task
+ * isn't a user space thread, or the address cannot be found, zero
+ * is returned. Can be used to see where the current task is combined
+ * with usymname() or symdata(). Often the task will be in the VDSO
+ * where it entered the kernel. FIXME - need VDSO tracking support #10080.
+ */
+function uaddr:long () %{ /* pure */
+ int64_t addr = 0;
+ if (current->mm)
+ {
+ struct pt_regs *uregs;
+ uregs = task_pt_regs(current);
+ if (uregs)
+ addr = (int64_t) REG_IP(uregs);
+ }
+ THIS->__retvalue = addr;
+%}
+
diff --git a/tapset/conversions.stp b/tapset/conversions.stp
index 70725e9d..31b16821 100644
--- a/tapset/conversions.stp
+++ b/tapset/conversions.stp
@@ -120,6 +120,8 @@ function user_string_n2:string (addr:long, n:long, err_msg:string) %{ /* pure */
(char __user *) (uintptr_t) THIS->addr,
len) < 0)
strlcpy(THIS->__retvalue, THIS->err_msg, MAXSTRINGLEN);
+ else
+ THIS->__retvalue[len - 1] = '\0';
%}
function user_string_n_warn:string (addr:long, n:long) %{ /* pure */
@@ -137,7 +139,8 @@ function user_string_n_warn:string (addr:long, n:long) %{ /* pure */
(void *) (uintptr_t) THIS->addr);
_stp_warn(CONTEXT->error_buffer);
strlcpy (THIS->__retvalue, "<unknown>", MAXSTRINGLEN);
- }
+ } else
+ THIS->__retvalue[len - 1] = '\0';
%}
function user_string_n_quoted:string (addr:long, n:long) %{ /* pure */
diff --git a/tapset/errno.stp b/tapset/errno.stp
index eda9bff1..011ff7e2 100644
--- a/tapset/errno.stp
+++ b/tapset/errno.stp
@@ -345,12 +345,20 @@ static const int Maxerrno = sizeof(errlist)/sizeof(char *);
function errno_str:string (err:long) %{ /* pure */
long e = THIS->err;
- if (e < 0 && e > -Maxerrno && errlist[-e])
- strlcpy (THIS->__retvalue, errlist[-e], MAXSTRINGLEN);
- else if (e > 0 && e < Maxerrno && errlist[e])
+ e = (e > 0 ? e : -e);
+ if (e > 0 && e < Maxerrno && errlist[e])
strlcpy (THIS->__retvalue, errlist[e], MAXSTRINGLEN);
%}
+function errno_p:long (err:long) %{ /* pure */
+ long e = THIS->err;
+ e = (e > 0 ? e : -e);
+ if (e > 0 && e < Maxerrno && errlist[e])
+ THIS->__retvalue = e;
+ else
+ THIS->__retvalue = 0;
+%}
+
%{
static long _stp_returnval(struct pt_regs *regs) {
if (regs) {
diff --git a/tapset/i686/registers.stp b/tapset/i686/registers.stp
index a6e5694e..997376dc 100644
--- a/tapset/i686/registers.stp
+++ b/tapset/i686/registers.stp
@@ -1,25 +1,39 @@
global _reg_offsets, _stp_regs_registered, _sp_offset, _ss_offset
+function test_x86_gs:long() %{ /* pure */
+#ifdef STAPCONF_X86_GS
+ THIS->__retvalue = 1;
+#else
+ THIS->__retvalue = 0;
+#endif
+%}
+
function _stp_register_regs() {
+
/* Same order as pt_regs */
- _reg_offsets["ebx"] = 0 _reg_offsets["bx"] = 0
- _reg_offsets["ecx"] = 4 _reg_offsets["cx"] = 4
- _reg_offsets["edx"] = 8 _reg_offsets["dx"] = 8
- _reg_offsets["esi"] = 12 _reg_offsets["si"] = 12
- _reg_offsets["edi"] = 16 _reg_offsets["di"] = 16
- _reg_offsets["ebp"] = 20 _reg_offsets["bp"] = 20
- _reg_offsets["eax"] = 24 _reg_offsets["ax"] = 24
- _reg_offsets["xds"] = 28 _reg_offsets["ds"] = 28
- _reg_offsets["xes"] = 32 _reg_offsets["es"] = 32
- _reg_offsets["xfs"] = 36 _reg_offsets["fs"] = 36
- _reg_offsets["orig_eax"] = 40 _reg_offsets["orig_ax"] = 40
- _reg_offsets["eip"] = 44 _reg_offsets["ip"] = 44
- _reg_offsets["xcs"] = 48 _reg_offsets["cs"] = 48
- _reg_offsets["eflags"] = 52 _reg_offsets["flags"] = 52
- _reg_offsets["esp"] = 56 _reg_offsets["sp"] = 56
- _reg_offsets["xss"] = 60 _reg_offsets["ss"] = 60
- _sp_offset = 56
- _ss_offset = 60
+ _reg_offsets["ebx"] = 0 _reg_offsets["bx"] = 0
+ _reg_offsets["ecx"] = 4 _reg_offsets["cx"] = 4
+ _reg_offsets["edx"] = 8 _reg_offsets["dx"] = 8
+ _reg_offsets["esi"] = 12 _reg_offsets["si"] = 12
+ _reg_offsets["edi"] = 16 _reg_offsets["di"] = 16
+ _reg_offsets["ebp"] = 20 _reg_offsets["bp"] = 20
+ _reg_offsets["eax"] = 24 _reg_offsets["ax"] = 24
+ _reg_offsets["xds"] = 28 _reg_offsets["ds"] = 28
+ _reg_offsets["xes"] = 32 _reg_offsets["es"] = 32
+ _reg_offsets["xfs"] = 36 _reg_offsets["fs"] = 36
+ gs_incr = 0
+if (test_x86_gs()) {
+ gs_incr = 4
+ _reg_offsets["xgs"] = 40 _reg_offsets["gs"] = 40
+}
+ _reg_offsets["orig_eax"] = 40 + gs_incr _reg_offsets["orig_ax"] = 40 + gs_incr
+ _reg_offsets["eip"] = 44 + gs_incr _reg_offsets["ip"] = 44 + gs_incr
+ _reg_offsets["xcs"] = 48 + gs_incr _reg_offsets["cs"] = 48 + gs_incr
+ _reg_offsets["eflags"] = 52 + gs_incr _reg_offsets["flags"] = 52 + gs_incr
+ _reg_offsets["esp"] = 56 + gs_incr _reg_offsets["sp"] = 56 + gs_incr
+ _reg_offsets["xss"] = 60 + gs_incr _reg_offsets["ss"] = 60 + gs_incr
+ _sp_offset = 56 + gs_incr
+ _ss_offset = 60 + gs_incr
_stp_regs_registered = 1
}
diff --git a/tapset/i686/syscalls.stp b/tapset/i686/syscalls.stp
index 8e69f622..2a89c19d 100644
--- a/tapset/i686/syscalls.stp
+++ b/tapset/i686/syscalls.stp
@@ -119,7 +119,7 @@ probe syscall.set_zone_reclaim.return =
#
probe syscall.sigaltstack = kernel.function("sys_sigaltstack") {
name = "sigaltstack"
- ussp = %( kernel_vr < "2.6.25" %? $ebx %: $bx %)
+ ussp = %( kernel_vr < "2.6.25" %? $ebx %: %( kernel_vr < "2.6.29" %? $bx %: $regs->bx %) %)
argstr = sprintf("%p", ussp)
}
probe syscall.sigaltstack.return = kernel.function("sys_sigaltstack").return {
diff --git a/tapset/ioscheduler.stp b/tapset/ioscheduler.stp
index d7a71aca..a79ae752 100644
--- a/tapset/ioscheduler.stp
+++ b/tapset/ioscheduler.stp
@@ -5,15 +5,17 @@
// 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.
-
+// <tapsetdescription>
+// This family of probe points is used to probe IO scheduler activities.
+// </tapsetdescription>
%{
#include <linux/blkdev.h>
#include <linux/elevator.h>
%}
/**
- * probe ioscheduler.elv_next_request - Retrieve request from request queue
- * @elevator_name: The elevator name
+ * probe ioscheduler.elv_next_request - Fires when a request is retrieved from the request queue
+ * @elevator_name: The type of I/O elevator currently enabled
*/
probe ioscheduler.elv_next_request
= kernel.function("elv_next_request")
@@ -26,7 +28,7 @@ probe ioscheduler.elv_next_request
}
/**
- * probe ioscheduler.elv_next_request.return - Return from retrieving a request
+ * probe ioscheduler.elv_next_request.return - Fires when a request retrieval issues a return signal
* @req: Address of the request
* @req_flags: Request flags
* @disk_major: Disk major number of the request
@@ -58,14 +60,14 @@ probe ioscheduler.elv_next_request.return
}
/**
- * probe ioscheduler.elv_add_request - Add a request into request queue
- * @elevator_name: The elevator name
+ * probe ioscheduler.elv_add_request - A request was added to the request queue
+ * @elevator_name: The type of I/O elevator currently enabled
* @req: Address of the request
* @req_flags: Request flags
* @disk_major: Disk major number of the request
* @disk_minor: Disk minor number of the request
*/
-/* when a request is added to the request queue */
+// when a request is added to the request queue
probe ioscheduler.elv_add_request
= kernel.function("__elv_add_request")
{
@@ -96,8 +98,8 @@ probe ioscheduler.elv_add_request
}
/**
- * probe ioscheduler.elv_completed_request - Request is completed
- * @elevator_name: The elevator name
+ * probe ioscheduler.elv_completed_request - Fires when a request is completed
+ * @elevator_name: The type of I/O elevator currently enabled
* @req: Address of the request
* @req_flags: Request flags
* @disk_major: Disk major number of the request
diff --git a/tapset/ip.stp b/tapset/ip.stp
new file mode 100644
index 00000000..299d88d2
--- /dev/null
+++ b/tapset/ip.stp
@@ -0,0 +1,78 @@
+// IP tapset
+// Copyright (C) 2009, IBM Inc.
+// Author : Breno Leitao <leitao@linux.vnet.ibm.com>
+//
+// This file is free software. You can redistribute it and/or modify it under
+// the terms of the GNU General Public License (GPL), version 2.
+//
+// Based on previous work done by Arnaldo Carvalho de Melo <acme@redhat.com>
+
+%{
+#include <linux/skbuff.h>
+%}
+
+/**
+ * sfunction ip_ntop - returns a string representation from an integer IP number
+ * @addr: the ip represented as an integer
+ */
+function ip_ntop:string (addr:long)
+%{
+ __be32 ip;
+
+ ip = THIS->addr;
+ snprintf(THIS->__retvalue, MAXSTRINGLEN, NIPQUAD_FMT, NIPQUAD(ip));
+%}
+
+/* return the source IP address for a given sock */
+function __ip_sock_saddr:long (sock:long)
+{
+ return @cast(sock, "inet_sock")->saddr
+}
+
+/* return the destination IP address for a given sock */
+function __ip_sock_daddr:long (sock:long)
+{
+ return @cast(sock, "inet_sock")->daddr
+}
+
+/* Get the IP header for recent (> 2.6.21) kernels */
+function __get_skb_iphdr_new:long(skb:long)
+%{ /* pure */
+ struct sk_buff *skb;
+ skb = (struct sk_buff *)(long)THIS->skb;
+ /* as done by skb_network_header() */
+ #ifdef NET_SKBUFF_DATA_USES_OFFSET
+ THIS->__retvalue = (long)(kread(&(skb->head)) + kread(&(skb->network_header)));
+ #else
+ THIS->__retvalue = (long)kread(&(skb->network_header));
+ #endif
+ CATCH_DEREF_FAULT();
+%}
+
+/* Get the IP header from a sk_buff struct */
+function __get_skb_iphdr:long(skb:long){
+%( kernel_v < "2.6.21" %?
+ iphdr = @cast(skb, "sk_buff")->nh->raw
+ return iphdr
+%:
+ return __get_skb_iphdr_new(skb)
+%)
+}
+
+/* return the source next layer protocol for a given sk_buff structure */
+function __ip_skb_proto:long (iphdr)
+{
+ return @cast(iphdr, "iphdr")->protocol
+}
+
+/* return the source IP address for a given sk_buff structure */
+function __ip_skb_saddr:long (iphdr)
+{
+ return @cast(iphdr, "iphdr")->saddr
+}
+
+/* return the destination IP address for a given skb */
+function __ip_skb_daddr:long (iphdr)
+{
+ return @cast(iphdr, "iphdr")->daddr
+}
diff --git a/tapset/process.stp b/tapset/kprocess.stp
index ca49aa67..316e03ce 100644
--- a/tapset/process.stp
+++ b/tapset/kprocess.stp
@@ -1,11 +1,13 @@
-// process tapset
+// kernel process tapset
// Copyright (C) 2006 Intel Corporation.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
-
+// <tapsetdescription>
+// This family of probe points is used to probe process-related activities.
+// </tapsetdescription>
function _IS_ERR:long(ptr:long) %{ /* pure */
THIS->__retvalue = IS_ERR((const void *)(long)THIS->ptr);
@@ -13,7 +15,7 @@ function _IS_ERR:long(ptr:long) %{ /* pure */
/**
- * probe process.create - Fires whenever a new process is successfully created
+ * probe kprocess.create - Fires whenever a new process is successfully created
* @new_pid: The PID of the newly created process
*
* Context:
@@ -22,7 +24,7 @@ function _IS_ERR:long(ptr:long) %{ /* pure */
* Fires whenever a new process is successfully created, either as a result of
* <command>fork</command> (or one of its syscall variants), or a new kernel thread.
*/
-probe process.create = kernel.function("copy_process").return {
+probe kprocess.create = kernel.function("copy_process").return {
task = $return
if (_IS_ERR(task)) next
new_pid = task_pid(task)
@@ -30,7 +32,7 @@ probe process.create = kernel.function("copy_process").return {
/**
- * probe process.start - Starting new process
+ * probe kprocess.start - Starting new process
*
* Context:
* Newly created process.
@@ -38,11 +40,11 @@ probe process.create = kernel.function("copy_process").return {
* Fires immediately before a new process begins execution.
*
*/
-probe process.start = kernel.function("schedule_tail") { }
+probe kprocess.start = kernel.function("schedule_tail") { }
/**
- * probe process.exec - Attempt to exec to a new program
+ * probe kprocess.exec - Attempt to exec to a new program
* @filename: The path to the new executable
*
* Context:
@@ -50,7 +52,7 @@ probe process.start = kernel.function("schedule_tail") { }
*
* Fires whenever a process attempts to exec to a new program.
*/
-probe process.exec =
+probe kprocess.exec =
kernel.function("do_execve"),
kernel.function("compat_do_execve") ?
{
@@ -59,7 +61,7 @@ probe process.exec =
/**
- * probe process.exec_complete - Return from exec to a new program
+ * probe kprocess.exec_complete - Return from exec to a new program
* @errno: The error number resulting from the exec
* @success: A boolean indicating whether the exec was successful
*
@@ -69,7 +71,7 @@ probe process.exec =
*
* Fires at the completion of an exec call.
*/
-probe process.exec_complete =
+probe kprocess.exec_complete =
kernel.function("do_execve").return,
kernel.function("compat_do_execve").return ?
{
@@ -79,23 +81,23 @@ probe process.exec_complete =
/**
- * probe process.exit - Exit from process
+ * probe kprocess.exit - Exit from process
* @code: The exit code of the process
*
* Context:
* The process which is terminating.
*
* Fires when a process terminates. This will always be followed by a
- * process.release, though the latter may be delayed if the process waits in a
+ * kprocess.release, though the latter may be delayed if the process waits in a
* zombie state.
*/
-probe process.exit = kernel.function("do_exit") {
+probe kprocess.exit = kernel.function("do_exit") {
code = $code
}
/**
- * probe process.release - Process released
+ * probe kprocess.release - Process released
* @task: A task handle to the process being released
* @pid: PID of the process being released
*
@@ -104,10 +106,10 @@ probe process.exit = kernel.function("do_exit") {
* termination, else the context of the process itself.
*
* Fires when a process is released from the kernel. This always follows a
- * process.exit, though it may be delayed somewhat if the process waits in a
+ * kprocess.exit, though it may be delayed somewhat if the process waits in a
* zombie state.
*/
-probe process.release = kernel.function("release_task") {
+probe kprocess.release = kernel.function("release_task") {
task = $p
pid = $p->pid;
}
diff --git a/tapset/memory.stp b/tapset/memory.stp
index 961cca38..83875aa4 100644
--- a/tapset/memory.stp
+++ b/tapset/memory.stp
@@ -6,6 +6,9 @@
// 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.
+// <tapsetdescription>
+// This family of probe points is used to probe memory-related events.
+// </tapsetdescription>
%{
#include <linux/mm.h>
%}
@@ -53,7 +56,7 @@ function vm_fault_contains:long (value:long, test:long)
/**
* probe vm.pagefault - Records that a page fault occurred.
* @address: The address of the faulting memory access; i.e. the address that caused the page fault.
- * @write_access: Indicates whether this was a write or read access; <command>1</command> indicates a write,
+ * @write_access: Indicates whether this was a write or read access; <command>1</command> indicates a write,
* while <command>0</command> indicates a read.
*
* Context: The process which triggered the fault
@@ -97,7 +100,7 @@ function addr_to_node:long(addr:long) %{ /* pure */
}
%}
-/* Return whether a page to be copied is a zero page. */
+// Return whether a page to be copied is a zero page.
function _IS_ZERO_PAGE:long(from:long, vaddr:long) %{ /* pure */
THIS->__retvalue = (THIS->from == (long) ZERO_PAGE(THIS->vaddr));
%}
@@ -110,8 +113,8 @@ function _IS_ZERO_PAGE:long(from:long, vaddr:long) %{ /* pure */
* Context:
* The context is the process attempting the write.
*
- * Fires when a process attempts to write to a shared page.
- * If a copy is necessary, this will be followed by a
+ * Fires when a process attempts to write to a shared page.
+ * If a copy is necessary, this will be followed by a
* <command>vm.write_shared_copy</command>.
*/
probe vm.write_shared = kernel.function("do_wp_page") {
@@ -119,7 +122,7 @@ probe vm.write_shared = kernel.function("do_wp_page") {
}
/**
- * probe vm.write_shared_copy- Page copy for shared page write.
+ * probe vm.write_shared_copy - Page copy for shared page write.
* @address: The address of the shared write.
* @zero: Boolean indicating whether it is a zero page
* (can do a clear instead of a copy).
diff --git a/tapset/networking.stp b/tapset/networking.stp
index a147441a..f6d78536 100644
--- a/tapset/networking.stp
+++ b/tapset/networking.stp
@@ -5,7 +5,9 @@
// 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.
-
+// <tapsetdescription>
+// This family of probe points is used to probe the activities of the network device.
+// </tapsetdescription>
/**
* probe netdev.receive - Data recieved from network device.
* @dev_name: The name of the device. e.g: eth0, ath1.
@@ -49,7 +51,7 @@
///
/// </variablelist>
///</para>
-/* Main device receive routine, be called when packet arrives on network device */
+// Main device receive routine, be called when packet arrives on network device
probe netdev.receive
= kernel.function("netif_receive_skb")
{
@@ -67,7 +69,7 @@ probe netdev.receive
* @truesize: The size of the the data to be transmitted.
*
*/
-/* Queue a buffer for transmission to a network device */
+// Queue a buffer for transmission to a network device
probe netdev.transmit
= kernel.function("dev_queue_xmit")
{
diff --git a/tapset/s390x/syscalls.stp b/tapset/s390x/syscalls.stp
index 07cb0577..17988ace 100644
--- a/tapset/s390x/syscalls.stp
+++ b/tapset/s390x/syscalls.stp
@@ -45,19 +45,21 @@ probe syscall.ipc.return = kernel.function("sys_ipc").return ? {
# long old_mmap(struct mmap_arg_struct __user *arg)
# long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
#
-probe syscall.mmap = kernel.function("old_mmap"),
- kernel.function("old32_mmap")
+probe syscall.mmap = kernel.function("old_mmap") ?,
+ kernel.function("old32_mmap") ?,
+ kernel.function("SyS_s390_old_mmap") ?
{
name = "mmap"
- if (probefunc() == "old_mmap")
+ if ((probefunc() == "old_mmap") || (probefunc() == "SyS_s390_old_mmap"))
argstr = get_mmap_args($arg)
else
argstr = get_32mmap_args($arg)
}
-probe syscall.mmap.return = kernel.function("old_mmap").return,
- kernel.function("old32_mmap").return
+probe syscall.mmap.return = kernel.function("old_mmap").return ?,
+ kernel.function("old32_mmap").return ?,
+ kernel.function("SyS_s390_old_mmap").return ?
{
name = "mmap"
retstr = returnstr(2)
@@ -69,19 +71,21 @@ probe syscall.mmap.return = kernel.function("old_mmap").return,
# long sys_mmap2(struct mmap_arg_struct __user *arg)
# long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
#
-probe syscall.mmap2 = kernel.function("sys_mmap2"),
- kernel.function("sys32_mmap2")
+probe syscall.mmap2 = kernel.function("sys_mmap2") ?,
+ kernel.function("sys32_mmap2") ?,
+ kernel.function("SyS_mmap2") ?
{
name = "mmap2"
- if (probefunc() == "sys_mmap2")
+ if ((probefunc() == "sys_mmap2") || (probefunc() == "SyS_mmap2"))
argstr = get_mmap_args($arg)
else
argstr = get_32mmap_args($arg)
}
-probe syscall.mmap2.return = kernel.function("sys_mmap2").return,
- kernel.function("sys32_mmap2").return
+probe syscall.mmap2.return = kernel.function("sys_mmap2").return ?,
+ kernel.function("sys32_mmap2").return ?,
+ kernel.function("SyS_mmap2").return ?
{
name = "mmap2"
retstr = returnstr(2)
diff --git a/tapset/scsi.stp b/tapset/scsi.stp
index 6d332e8b..e1457739 100644
--- a/tapset/scsi.stp
+++ b/tapset/scsi.stp
@@ -5,7 +5,9 @@
// 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.
-
+// <tapsetdescription>
+// This family of probe points is used to probe SCSI activities.
+// </tapsetdescription>
%{
#include <linux/types.h>
#include <scsi/scsi_cmnd.h>
@@ -21,7 +23,7 @@
* @disk_minor: The minor number of the disk (-1 if no information)
* @device_state: The current state of the device.
*/
-/* FIXME describe the device_state */
+// FIXME describe the device_state
probe scsi.ioentry
= module("scsi_mod").function("scsi_prep_fn@drivers/scsi/scsi_lib.c")?,
kernel.function("scsi_prep_fn@drivers/scsi/scsi_lib.c")?
@@ -44,9 +46,9 @@ probe scsi.ioentry
* @lun: The lun number
* @dev_id: The scsi device id
* @device_state: The current state of the device.
- * @data_direction: The data_direction specifies whether this command is from/to
- * the device. 0 (DMA_BIDIRECTIONAL), 1 (DMA_TO_DEVICE),
- * 2 (DMA_FROM_DEVICE), 3 (DMA_NONE)
+ * @data_direction: The data_direction specifies whether this command is from/to the device.
+ * 0 (DMA_BIDIRECTIONAL), 1 (DMA_TO_DEVICE),
+ * 2 (DMA_FROM_DEVICE), 3 (DMA_NONE)
* @request_buffer: The request buffer address
* @req_bufflen: The request buffer length
*/
@@ -79,7 +81,7 @@ probe scsi.iodispatching
* @dev_id: The scsi device id
* @device_state: The current state of the device
* @data_direction: The data_direction specifies whether this command is
- * from/to the device.
+ * from/to the device.
*/
probe scsi.iodone
= module("scsi_mod").function("scsi_done@drivers/scsi/scsi.c")?,
@@ -104,10 +106,10 @@ probe scsi.iodone
* @dev_id: The scsi device id
* @device_state: The current state of the device
* @data_direction: The data_direction specifies whether this command is from/to
- * the device
+ * the device
* @goodbytes: The bytes completed.
*/
-/* mid-layer processes the completed IO */
+// mid-layer processes the completed IO
probe scsi.iocompleted
= module("scsi_mod").function("scsi_io_completion@drivers/scsi/scsi_lib.c")?,
kernel.function("scsi_io_completion@drivers/scsi/scsi_lib.c")?
diff --git a/tapset/signal.stp b/tapset/signal.stp
index 8fb6fe57..e8470a9c 100644
--- a/tapset/signal.stp
+++ b/tapset/signal.stp
@@ -8,16 +8,17 @@
// Public License (GPL); either version 2, or (at your option) any
// later version.
//
-// Note : Since there are so many signals sent to processes at any give
-// point, it's better to filter the information according to the
-// requirements. For example, filter only for a particular signal
-// (if sig==2) or filter only for a particular process
-// (if pid_name==stap).
//
-
+// <tapsetdescription>
+// This family of probe points is used to probe signal activities.
+// Since there are so many signals sent to processes at any given
+// point, it is advisable to filter the information according to the
+// requirements. For example, filter only for a particular signal
+// (if sig==2) or for a particular process (if pid_name==stap).
+// </tapsetdescription>
/**
- * probe signal.send- Fires when a system call or kernel function sends a signal to a process.
+ * probe signal.send - Signal being sent to a process
* Arguments:
* @sig: The number of the signal
* @sig_name: A string representation of the signal
@@ -27,9 +28,10 @@
* @task: A task handle to the signal recipient
* @sinfo: The address of <command>siginfo</command> struct
* @shared: Indicates whether the signal is shared by the thread group
- * @send2queue- Indicates whether the signal is sent to an existing <command>sigqueue</command>
+ * @send2queue: Indicates whether the signal is sent to an existing
+ * <command>sigqueue</command>
* @name: The name of the function used to send out the signal
- *
+ *
* Context:
* The signal's sender.
*
@@ -114,42 +116,41 @@ probe _signal.send.part3 = kernel.function("send_sigqueue")
}
/**
- * probe signal.send.return - Fires when a signal sent to a process returns.
+ * probe signal.send.return - Signal being sent to a process completed
* @retstr: The return value to either <command>__group_send_sig_info</command>,
- * <command>specific_send_sig_info</command>, or <command>send_sigqueue</command>.
- * Refer to the Description of this probe for more information about the return
- * values of each function call.
+ * <command>specific_send_sig_info</command>,
+ * or <command>send_sigqueue</command>
* @shared: Indicates whether the sent signal is shared by the thread group.
- * @send2queue: Indicates whether the sent signal was sent to an existing <command>sigqueue</command>
- * @name: The name of the function used to send out the signal.
- *
+ * @send2queue: Indicates whether the sent signal was sent to an
+ * existing <command>sigqueue</command>
+ * @name: The name of the function used to send out the signal
+ *
* Context:
* The signal's sender. <remark>(correct?)</remark>
- *
+ *
* Possible <command>__group_send_sig_info</command> and
* <command>specific_send_sig_info</command> return values are as follows;
*
- * <command>0</command> - The signal is sucessfully sent to a process,
+ * <command>0</command> -- The signal is sucessfully sent to a process,
* which means that
* <1> the signal was ignored by the receiving process,
* <2> this is a non-RT signal and the system already has one queued, and
* <3> the signal was successfully added to the <command>sigqueue</command> of the receiving process.
*
- * <command>-EAGAIN</command> - The <command>sigqueue</command> of the receiving process is
+ * <command>-EAGAIN</command> -- The <command>sigqueue</command> of the receiving process is
* overflowing, the signal was RT, and the signal was sent by a user using something other
- * than <command>kill()</command>
- *
+ * than <command>kill()</command>.
+ *
* Possible <command>send_group_sigqueue</command> and
* <command>send_sigqueue</command> return values are as follows;
- *
- * <command>0</command> - The signal was either sucessfully added into the
+ *
+ * <command>0</command> -- The signal was either sucessfully added into the
* <command>sigqueue</command> of the receiving process, or a <command>SI_TIMER</command> entry is already
* queued (in which case, the overrun count will be simply incremented).
*
- * <command>1</command> - The signal was ignored by the receiving process.
- *
+ * <command>1</command> -- The signal was ignored by the receiving process.
*
- * <command>-1</command> - (<command>send_sigqueue</command> only) The task was marked
+ * <command>-1</command> -- (<command>send_sigqueue</command> only) The task was marked
* <command>exiting</command>, allowing * <command>posix_timer_event</command> to redirect it to the group
* leader.
*
@@ -232,7 +233,7 @@ probe _signal.send.part3.return = kernel.function("send_sigqueue").return
}
/**
- * probe signal.checkperm - Fires when a permission check is performed on a sent signal
+ * probe signal.checkperm - Check being performed on a sent signal
* @sig: The number of the signal
* @sig_name: A string representation of the signal
* @sig_pid: The PID of the process receiving the signal
@@ -240,7 +241,8 @@ probe _signal.send.part3.return = kernel.function("send_sigqueue").return
* @si_code: Indicates the signal type
* @task: A task handle to the signal recipient
* @sinfo: The address of the <command>siginfo</command> structure
- * @name: Name of the probe point; default value is <command>signal.checkperm</command>
+ * @name: Name of the probe point; default value is
+ * <command>signal.checkperm</command>
*/
probe signal.checkperm = kernel.function("check_kill_permission")
{
@@ -261,6 +263,12 @@ probe signal.checkperm = kernel.function("check_kill_permission")
si_code="SI_USER or SI_TIMER or SI_ASYNCIO"
}
+/**
+ * probe signal.checkperm.return - Check performed on a sent signal completed
+ * @name: Name of the probe point; default value is
+ * <command>signal.checkperm</command>
+ * @retstr: Return value as a string
+ */
probe signal.checkperm.return = kernel.function("check_kill_permission").return
{
name = "signal.checkperm"
@@ -269,15 +277,15 @@ probe signal.checkperm.return = kernel.function("check_kill_permission").return
/**
- * probe signal.wakeup - Wakes up a sleeping process, making it ready for new active signals
- * @sig_pid: The PID of the process you wish to wake
- * @pid_name: Name of the process you wish to wake
- * @resume: Indicates whether to wake up a task in a <command>STOPPED</command> or
- * <command>TRACED</command> state
+ * probe signal.wakeup - Sleeping process being wakened for signal
+ * @sig_pid: The PID of the process to wake
+ * @pid_name: Name of the process to wake
+ * @resume: Indicates whether to wake up a task in a
+ * <command>STOPPED</command> or <command>TRACED</command> state
* @state_mask: A string representation indicating the mask
- * of task states you wish to wake. Possible values are <command>TASK_INTERRUPTIBLE</command>,
- * <command>TASK_STOPPED</command>, <command>TASK_TRACED</command>,
- * and <command>TASK_INTERRUPTIBLE</command>.
+ * of task states to wake. Possible values are
+ * <command>TASK_INTERRUPTIBLE</command>, <command>TASK_STOPPED</command>,
+ * <command>TASK_TRACED</command>, and <command>TASK_INTERRUPTIBLE</command>.
*/
probe signal.wakeup = kernel.function("signal_wake_up")
{
@@ -293,8 +301,7 @@ probe signal.wakeup = kernel.function("signal_wake_up")
/**
- * probe signal.check_ignored - Fires when a system call or kernel function checks whether a
- * signal was ignored or not
+ * probe signal.check_ignored - Checking to see signal is ignored
* @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @sig: The number of the signal
@@ -308,6 +315,12 @@ probe signal.check_ignored = kernel.function("sig_ignored")
sig_name = _signal_name($sig)
}
+/**
+ * probe signal.check_ignored.return - Check to see signal is ignored completed
+ * @name: Name of the probe point; default value is
+ * <command>signal.checkperm</command>
+ * @retstr: Return value as a string
+ */
probe signal.check_ignored.return = kernel.function("sig_ignored").return ?
{
name = "sig_ignored"
@@ -333,8 +346,7 @@ probe signal.handle_stop = kernel.function("handle_stop_signal")
/**
- * probe signal.force_segv - Fires when a system call, kernel function, or process sent a
- * <command>SIGSEGV</command> as a result of problems it encountered while handling a received signal
+ * probe signal.force_segv - Forcing send of <command>SIGSEGV</command>
* @sig_pid: The PID of the process receiving the signal
* @pid_name: Name of the process receiving the signal
* @sig: The number of the signal
@@ -360,6 +372,12 @@ probe _signal.force_segv.part2 = kernel.function("force_sigsegv_info") ?
sig_name = _signal_name($sig)
}
+/**
+ * probe signal.force_segv.return - Forcing send of <command>SIGSEGV</command> complete
+ * @name: Name of the probe point; default value is
+ * <command>force_sigsegv</command>
+ * @retstr: Return value as a string
+ */
probe signal.force_segv.return =
kernel.function("force_sigsegv").return,
kernel.function("force_sigsegv_info").return ?
@@ -370,9 +388,8 @@ probe signal.force_segv.return =
/**
- * probe signal.syskill - Fires when the kernel function <command>sys_kill</command>
- * sends a kill signal to a process
- * @pid: The PID of the process receiving the kill signal
+ * probe signal.syskill - Sending kill signal to a process
+ * @pid: The PID of the process receiving the signal
* @sig: The specific signal sent to the process
*/
probe signal.syskill = syscall.kill
@@ -380,33 +397,43 @@ probe signal.syskill = syscall.kill
sig_name = _signal_name($sig)
}
+/**
+ * probe signal.syskill.return - Sending kill signal completed
+ */
probe signal.syskill.return = syscall.kill.return
{
}
+
/**
- * probe signal.sys_tkill - Fires when <command>tkill</command> sends a kill signal
- * to a process that is part of a thread group
+ * probe signal.sys_tkill - Sending a kill signal to a thread
* @pid: The PID of the process receiving the kill signal
* @sig: The specific signal sent to the process
+ * @sig_name: The specific signal sent to the process
+ *
* The <command>tkill</command> call is analogous to <command>kill(2)</command>,
* except that it also allows a process within a specific thread group to
- * be targetted. Such processes are targetted through their unique thread IDs (TID).
+ * be targetted. Such processes are targetted through their unique
+ * thread IDs (TID).
*/
probe signal.systkill = syscall.tkill
{
sig_name = _signal_name($sig)
}
+/**
+ * probe signal.systkill.return - Sending kill signal to a thread completed
+ */
probe signal.systkill.return = syscall.tkill.return
{
}
/**
- * probe signal.sys_tgkill - Fires when the kernel function <command>tgkill</command>
- * sends a kill signal to a specific thread group
+ * probe signal.sys_tgkill - Sending kill signal to a thread group
* @pid: The PID of the thread receiving the kill signal
* @tgid: The thread group ID of the thread receiving the kill signal
* @sig: The specific kill signal sent to the process
+ * @sig_name: A string representation of the signal
+ *
* The <command>tgkill</command> call is similar to <command>tkill</command>,
* except that it also allows the caller to specify the thread group ID of
* the thread to be signalled. This protects against TID reuse.
@@ -416,12 +443,15 @@ probe signal.systgkill = syscall.tgkill
sig_name = _signal_name($sig)
}
+/**
+ * probe signal.sys_tgkill.return - Sending kill signal to a thread group completed
+ */
probe signal.systgkill.return = syscall.tgkill.return
{
}
/**
- * probe signal.send_sig_queue - Fires when a signal is queued to a process
+ * probe signal.send_sig_queue - Queuing a signal to a process
* @sig: The queued signal
* @sig_name: A string representation of the signal
* @sig_pid: The PID of the process to which the signal is queued
@@ -439,6 +469,10 @@ probe signal.send_sig_queue =
sigqueue_addr = $q
}
+/**
+ * probe signal.send_sig_queue.return - Queuing a signal to a process completed
+ * @retstr: Return value as a string
+ */
probe signal.send_sig_queue.return =
kernel.function("send_sigqueue").return,
kernel.function("send_group_sigqueue").return ?
@@ -448,25 +482,25 @@ probe signal.send_sig_queue.return =
/**
- * probe signal.pending - Fires when the <command>SIGPENDING</command> system call is used;
- * this normally occurs when the <command>do_sigpending</command> kernel function is executed
- * @sigset_add: The address of the user-space signal set (<command>sigset_t</command>)
- * @sigset_size: The size of the user-space signal set.
- *
- * Synopsis:
- * <programlisting>long do_sigpending(void __user *set, unsigned long sigsetsize)</programlisting>
+ * probe signal.pending - Examining pending signal
+ * @sigset_add: The address of the user-space signal set
+ * (<command>sigset_t</command>)
+ * @sigset_size: The size of the user-space signal set
*
* This probe is used to examine a set of signals pending for delivery
- * to a specific thread.
+ * to a specific thread. This normally occurs when the
+ * <command>do_sigpending</command> kernel function is executed.
*/
-// long do_sigpending(void __user *set, unsigned long sigsetsize)
-
probe signal.pending = kernel.function("do_sigpending")
{
sigset_add=$set
sigset_size=$sigsetsize
}
+/**
+ * probe signal.pending.return - Examination of pending signal completed
+ * @retstr: Return value as a string
+ */
probe signal.pending.return = kernel.function("do_sigpending").return
{
retstr = returnstr(1)
@@ -474,22 +508,17 @@ probe signal.pending.return = kernel.function("do_sigpending").return
/**
- * probe signal.handle - Fires when the signal handler is invoked
+ * probe signal.handle - Signal handler being invoked
* @sig: The signal number that invoked the signal handler
* @sinfo: The address of the <command>siginfo</command> table
- * @sig_code: The <command>si_code</command> value of the <command>siginfo</command> signal
- * @ka_addr: The address of the <command>k_sigaction</command> table associated with the signal
+ * @sig_code: The <command>si_code</command> value of the
+ * <command>siginfo</command> signal
+ * @ka_addr: The address of the <command>k_sigaction</command> table
+ * associated with the signal
* @oldset_addr: The address of the bitmask array of blocked signals
* @regs: The address of the kernel-mode stack area
* @sig_mode: Indicates whether the signal was a user-mode or kernel-mode signal
- *
- * Synopsis:
- * <programlisting>static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
- * sigset_t *oldset, struct pt_regs * regs)</programlisting>
*/
-//static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
-// sigset_t *oldset, struct pt_regs * regs)
-
probe signal.handle = kernel.function("handle_signal")
{
sig = $sig
@@ -508,6 +537,10 @@ probe signal.handle = kernel.function("handle_signal")
sig_mode = "Kernel Mode Signal"
}
+/**
+ * probe signal.handle.return - Signal handler invocation completed
+ * @retstr: Return value as a string
+ */
probe signal.handle.return = kernel.function("handle_signal").return ?
{
retstr = returnstr(1)
@@ -515,11 +548,12 @@ probe signal.handle.return = kernel.function("handle_signal").return ?
/**
- * probe signal.do_action - Initiates a trace when a thread is about to examine
- * and change a signal action
+ * probe signal.do_action - Examining or changing a signal action
* @sig: The signal to be examined/changed
- * @sigact_addr: The address of the new <command>sigaction</command> struct associated with the signal
- * @oldsigact_addr: The address of the old <command>sigaction</command> struct associated with the signal
+ * @sigact_addr: The address of the new <command>sigaction</command>
+ * struct associated with the signal
+ * @oldsigact_addr: The address of the old <command>sigaction</command>
+ * struct associated with the signal
* @sa_handler: The new handler of the signal
* @sa_mask: The new mask of the signal
*/
@@ -535,6 +569,10 @@ probe signal.do_action = kernel.function("do_sigaction")
}
}
+/**
+ * probe signal.do_action.return - Examining or changing a signal action completed
+ * @retstr: Return value as a string
+ */
probe signal.do_action.return = kernel.function("do_sigaction").return
{
retstr = returnstr(1)
@@ -554,16 +592,17 @@ function __get_action_mask:long(act:long) %{ /* pure */
/**
- * probe signal.procmask - Initiates a trace when a thread is about to examine and change blocked signals
+ * probe signal.procmask - Examining or changing blocked signals
* @how: Indicates how to change the blocked signals; possible values are
* <command>SIG_BLOCK=0</command> (for blocking signals),
* <command>SIG_UNBLOCK=1</command> (for unblocking signals), and
* <command>SIG_SETMASK=2</command> for setting the signal mask.
- * @sigset_addr: The address of the signal set (<command>sigset_t</command>) to be implemented
- * @oldsigset_addr: The old address of the signal set (<command>sigset_t</command>)
- * @sigset: The actual value to be set for <command>sigset_t</command> <remark>(correct?)</remark>
- * Synopsis:
- * <programlisting>int sigprocmask(int how, sigset_t *set, sigset_t *oldset)</programlisting>
+ * @sigset_addr: The address of the signal set (<command>sigset_t</command>)
+ * to be implemented
+ * @oldsigset_addr: The old address of the signal set
+ * (<command>sigset_t</command>)
+ * @sigset: The actual value to be set for <command>sigset_t</command>
+ * <remark>(correct?)</remark>
*/
probe signal.procmask = kernel.function("sigprocmask")
{
@@ -591,16 +630,13 @@ probe signal.procmask.return = kernel.function("sigprocmask").return
/**
- * probe signal.flush - Fires when all pending signals for a task are flushed
+ * probe signal.flush - Flusing all pending signals for a task
* @task: The task handler of the process performing the flush
- * @sig_pid: The PID of the process associated with the task performing the flush
- * @pid_name: The name of the process associated with the task performing the flush
- *
- * Synopsis:
- * <programlisting>void flush_signals(struct task_struct *t)</programlisting>
+ * @sig_pid: The PID of the process associated with the task
+ * performing the flush
+ * @pid_name: The name of the process associated with the task
+ * performing the flush
*/
-//void flush_signals(struct task_struct *t)
-
probe signal.flush = kernel.function("flush_signals")
{
task = $t
diff --git a/tapset/socket.stp b/tapset/socket.stp
index 3271d4f7..de778d7c 100644
--- a/tapset/socket.stp
+++ b/tapset/socket.stp
@@ -5,7 +5,9 @@
// 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.
-
+// <tapsetdescription>
+// This family of probe points is used to probe socket activities.
+// </tapsetdescription>
%{
#include <net/sock.h>
#include <asm/bitops.h>
@@ -65,8 +67,8 @@ probe socket.receive = socket.recvmsg.return,
### FUNCTION SPECIFIC SEND/RECEIVE PROBES ###
-/*
- * probe socket.sendmsg - Message being sent on socket
+/**
+ * probe socket.sendmsg - Message is currently being sent on a socket.
* @name: Name of this probe
* @size: Message size in bytes
* @protocol: Protocol value
@@ -93,7 +95,7 @@ probe socket.sendmsg = kernel.function ("sock_sendmsg")
}
/**
- * probe socket.sendmsg.return - Return from Message being sent on socket
+ * probe socket.sendmsg.return - Return from <command>socket.sendmsg</command>.
* @name: Name of this probe
* @size: Size of message sent (in bytes) or error code if success = 0
* @protocol: Protocol value
@@ -149,7 +151,7 @@ probe socket.recvmsg = kernel.function ("sock_recvmsg")
type = $sock->type
}
-/*
+/**
* probe socket.recvmsg.return - Return from Message being received on socket
* @name: Name of this probe
* @size: Size of message received (in bytes) or error code if success = 0
@@ -196,14 +198,14 @@ probe socket.recvmsg.return = kernel.function ("sock_recvmsg").return
* Fires at the beginning of sending a message on a socket
* via the sock_aio_write() function
*/
-/*
- * 2.6.9~2.6.15:
- * static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t size, loff_t pos);
- * 2.6.16~2.6.18:
- * static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t count, loff_t pos);
- * 2.6.19~2.6.26:
- * static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos);
- */
+//
+// 2.6.9~2.6.15:
+// static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t size, loff_t pos);
+// 2.6.16~2.6.18:
+// static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t count, loff_t pos);
+// 2.6.19~2.6.26:
+// static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos);
+
probe socket.aio_write = kernel.function ("sock_aio_write")
{
name = "socket.aio_write"
@@ -270,14 +272,14 @@ probe socket.aio_write.return = kernel.function ("sock_aio_write").return
* Fires at the beginning of receiving a message on a socket
* via the sock_aio_read() function
*/
-/*
- * 2.6.9~2.6.15:
- * static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t size, loff_t pos);
- * 2.6.16~2.6.18:
- * static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t count, loff_t pos);
- * 2.6.19~2.6.26:
- * static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos);
- */
+//
+// 2.6.9~2.6.15:
+// static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t size, loff_t pos);
+// 2.6.16~2.6.18:
+// static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, size_t count, loff_t pos);
+// 2.6.19~2.6.26:
+// static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos);
+
probe socket.aio_read = kernel.function ("sock_aio_read")
{
name = "socket.aio_read"
@@ -541,18 +543,18 @@ probe socket.close.return = kernel.function ("sock_release").return
####### PROTOCOL HELPER FUNCTIONS ########
-/*
- * sock_prot_num2str
- * Given a protocol number, return a string representation.
+/**
+ * sfunction sock_prot_num2str - Given a protocol number, return a string representation.
+ * @proto: The protocol number.
*/
function sock_prot_num2str:string (proto:long)
{
return (proto in _prot_num2str ? _prot_num2str[proto] : "UNDEF")
}
-/*
- * sock_prot_str2num
- * Given a protocol name (string), return the corresponding protocol number.
+/**
+ * sfunction sock_prot_str2num - Given a protocol name (string), return the corresponding protocol number.
+ * @proto: The protocol name.
*/
function sock_prot_str2num:long (proto:string)
{
@@ -561,19 +563,19 @@ function sock_prot_str2num:long (proto:string)
######### PROTOCOL FAMILY HELPER FUNCTIONS ###########
-/*
- * sock_fam_num2str
- * Given a protocol family number, return a string representation.
+/**
+ * sfunction sock_fam_num2str - Given a protocol family number, return a string representation.
+ * @family: The family number.
*/
function sock_fam_num2str:string (family:long)
{
return (family in _fam_num2str ? _fam_num2str[family] : "UNDEF")
}
-/*
- * sock_fam_str2num
- * Given a protocol family name (string), return the corresponding
+/**
+ * sfunction sock_fam_str2num - Given a protocol family name (string), return the corresponding
* protocol family number.
+ * @family: The family name.
*/
function sock_fam_str2num:long (family:string)
{
@@ -582,18 +584,18 @@ function sock_fam_str2num:long (family:string)
######### SOCKET STATE HELPER FUNCTIONS ##########
-/*
- * sock_state_num2str
- * Given a socket state number, return a string representation.
+/**
+ * sfunction sock_state_num2str - Given a socket state number, return a string representation.
+ * @state: The state number.
*/
function sock_state_num2str:string (state:long)
{
return (state in _state_num2str ? _state_num2str[state] : "UNDEF")
}
-/*
- * sock_state_str2num
- * Given a socket state string, return the corresponding state number.
+/**
+ * sfunction sock_state_str2num - Given a socket state string, return the corresponding state number.
+ * @state: The state name.
*/
function sock_state_str2num:long (state:string)
{
diff --git a/tapset/string.stp b/tapset/string.stp
index 2f43aecc..35ee9fa2 100644
--- a/tapset/string.stp
+++ b/tapset/string.stp
@@ -25,6 +25,18 @@ function substr:string(str:string,start:long, length:long) %{ /* pure */
strlcpy(THIS->__retvalue, THIS->str + THIS->start, length);
%}
+/** @addtogroup library
+* @code function stringat:string(str:string, pos:long) @endcode
+* @param str string
+* @param pos the given position. 0 = start of the string
+* @return Returns the char in given position of string.
+*/
+function stringat:long(str:string, pos:long) %{ /* pure */
+ if (THIS->pos >= 0 && THIS->pos < strlen(THIS->str))
+ THIS->__retvalue = THIS->str[THIS->pos];
+ else
+ THIS->__retvalue = 0;
+%}
/** @addtogroup library
* @code isinstr:long(s1:string,s2:string) @endcode
diff --git a/tapset/syscalls.stp b/tapset/syscalls.stp
index 256174d3..a215dc12 100644
--- a/tapset/syscalls.stp
+++ b/tapset/syscalls.stp
@@ -733,7 +733,7 @@ probe syscall.faccessat.return = kernel.function("SyS_faccessat").return !,
probe syscall.fadvise64 = kernel.function("SyS_fadvise64") !,
kernel.function("sys_fadvise64") ? {
name = "fadvise64"
- fs = $fd
+ fd = $fd
offset = $offset
len = $len
advice = $advice
@@ -751,7 +751,7 @@ probe syscall.fadvise64.return = kernel.function("SyS_fadvise64").return !,
probe syscall.fadvise64_64 = kernel.function("SyS_fadvise64_64") !,
kernel.function("sys_fadvise64_64") ? {
name = "fadvise64_64"
- fs = $fd
+ fd = $fd
offset = $offset
len = $len
advice = $advice
@@ -771,7 +771,7 @@ probe syscall.fadvise64_64.return = kernel.function("SyS_fadvise64_64").return !
probe syscall.fadvise64 = kernel.function("SyS_fadvise64") !,
kernel.function("sys_fadvise64") {
name = "fadvise64"
- fs = 0
+ fd = 0
offset = 0
len = 0
advice = 0
@@ -789,7 +789,7 @@ probe syscall.fadvise64.return = kernel.function("SyS_fadvise64").return !,
probe syscall.fadvise64_64 = kernel.function("SyS_fadvise64_64") !,
kernel.function("sys_fadvise64_64") {
name = "fadvise64_64"
- fs = 0
+ fd = 0
offset = 0
len = 0
advice = 0
diff --git a/tapset/task.stp b/tapset/task.stp
index 07337156..f1a10b0a 100644
--- a/tapset/task.stp
+++ b/tapset/task.stp
@@ -63,6 +63,30 @@ function task_pid:long (task:long)
}
+// Return the task of the given process id
+function pid2task:long (pid:long) %{ /* pure */
+ struct task_struct *t = NULL;
+ pid_t t_pid = (pid_t)(long)THIS->pid;
+ rcu_read_lock();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ t = find_task_by_vpid (t_pid);
+#else
+ t = find_task_by_pid (t_pid);
+#endif
+ rcu_read_unlock();
+ THIS->__retvalue = (long)t;
+ CATCH_DEREF_FAULT();
+%}
+
+// Return the name of the given process id
+function pid2execname:string (pid:long) {
+ tsk = pid2task(pid)
+ if (tsk)
+ return task_execname(tsk)
+ return ""
+}
+
+
// Return the thread id of the given task
function task_tid:long (task:long)
{
diff --git a/tapset/tcp.stp b/tapset/tcp.stp
index 995d6abc..2c5dce7e 100644
--- a/tapset/tcp.stp
+++ b/tapset/tcp.stp
@@ -7,12 +7,15 @@
// 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.
-
+// <tapsetdescription>
+// This family of probe points is used to probe events that occur in the TCP layer,
+// </tapsetdescription>
%{
#include <linux/version.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/ip.h>
+#include <linux/skbuff.h>
%}
// Get retransmission timeout in usecs. RTO is initialized from default
@@ -71,6 +74,80 @@ function tcp_ts_get_info_state:long(sock:long)
CATCH_DEREF_FAULT();
%}
+/* return the TCP destination port for a given sock */
+function __tcp_sock_dport:long (sock:long){
+ return @cast(sock, "inet_sock")->dport
+}
+
+/* returns the TCP header for recent (<2.6.21) kernel */
+function __get_skb_tcphdr_new:long(skb:long)
+%{ /* pure */
+ struct sk_buff *skb;
+ skb = (struct sk_buff *)(long)THIS->skb;
+ /* as done by skb_transport_header() */
+ #ifdef NET_SKBUFF_DATA_USES_OFFSET
+ THIS->__retvalue = (long)(kread(&(skb->head)) + kread(&(skb->transport_header)));
+ #else
+ THIS->__retvalue = (long)kread(&(skb->transport_header));
+ #endif
+ CATCH_DEREF_FAULT();
+%}
+
+/* returns the TCP header for a given sk_buff structure */
+function __get_skb_tcphdr:long(skb:long){
+%( kernel_v < "2.6.21" %?
+ tcphdr = @cast(skb, "sk_buff")->h->raw
+ return tcphdr
+%:
+ return __get_skb_tcphdr_new(skb)
+%)
+}
+
+/* returns TCP URG flag for a given sk_buff structure */
+function __tcp_skb_urg:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->urg
+}
+
+/* returns TCP ACK flag for a given sk_buff structure */
+function __tcp_skb_ack:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->ack
+}
+
+/* returns TCP PSH flag for a given sk_buff structure */
+function __tcp_skb_psh:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->psh
+}
+
+/* returns TCP RST flag for a given sk_buff structure */
+function __tcp_skb_rst:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->rst
+}
+
+/* returns TCP SYN flag for a given sk_buff structure */
+function __tcp_skb_syn:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->syn
+}
+
+/* returns TCP FIN flag for a given sk_buff structure */
+function __tcp_skb_fin:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->fin
+}
+
+/* returns TCP source port for a given sk_buff structure */
+function __tcp_skb_sport:long (tcphdr){
+ return ntohs(@cast(tcphdr, "tcphdr")->source)
+}
+
+/* returns TCP destination port for a given sk_buff structure */
+function __tcp_skb_dport:long (tcphdr){
+ return @cast(tcphdr, "tcphdr")->dest
+}
+
+/* return the TCP source port for a given sock */
+function __tcp_sock_sport:long (sock:long){
+ return @cast(sock, "inet_sock")->sport
+}
+
global sockstate[13], sockstate_init_p
function tcp_sockstate_str:string (state:long) {
if (! sockstate_init_p) {
@@ -180,6 +257,10 @@ probe tcp.sendmsg.return = kernel.function("tcp_sendmsg").return {
* @name: Name of this probe
* @sock: Network socket
* @size: Number of bytes to be received
+ * @saddr: A string representing the source IP address
+ * @daddr: A string representing the destination IP address
+ * @sport: TCP source port
+ * @dport: TCP destination port
* Context:
* The process which receives a tcp message
*/
@@ -187,12 +268,20 @@ probe tcp.recvmsg = kernel.function("tcp_recvmsg") {
name = "tcp.recvmsg"
sock = $sk
size = $len
+ saddr = ip_ntop(__ip_sock_saddr($sk))
+ daddr = ip_ntop(__ip_sock_daddr($sk))
+ sport = __tcp_sock_sport($sk)
+ dport = __tcp_sock_dport($sk)
}
/**
* probe tcp.recvmsg.return - Receiving TCP message complete
* @name: Name of this probe
* @size: Number of bytes received or error code if an error occurred.
+ * @saddr: A string representing the source IP address
+ * @daddr: A string representing the destination IP address
+ * @sport: TCP source port
+ * @dport: TCP destination port
*
* Context:
* The process which receives a tcp message
@@ -200,6 +289,10 @@ probe tcp.recvmsg = kernel.function("tcp_recvmsg") {
probe tcp.recvmsg.return = kernel.function("tcp_recvmsg").return {
name = "tcp.recvmsg"
size = $return
+ saddr = ip_ntop(__ip_sock_saddr($sk))
+ daddr = ip_ntop(__ip_sock_daddr($sk))
+ sport = __tcp_sock_sport($sk)
+ dport = __tcp_sock_dport($sk)
}
/**
@@ -207,6 +300,10 @@ probe tcp.recvmsg.return = kernel.function("tcp_recvmsg").return {
* @name: Name of this probe
* @sock: Network socket
* @flags: TCP flags (e.g. FIN, etc)
+ * @saddr: A string representing the source IP address
+ * @daddr: A string representing the destination IP address
+ * @sport: TCP source port
+ * @dport: TCP destination port
*
* Context:
* The process which disconnects tcp
@@ -215,6 +312,10 @@ probe tcp.disconnect = kernel.function("tcp_disconnect") {
name = "tcp.disconnect"
sock = $sk
flags = $flags
+ saddr = ip_ntop(__ip_sock_saddr($sk))
+ daddr = ip_ntop(__ip_sock_daddr($sk))
+ sport = __tcp_sock_sport($sk)
+ dport = __tcp_sock_dport($sk)
}
/**
@@ -264,3 +365,32 @@ probe tcp.setsockopt.return = kernel.function("tcp_setsockopt").return {
ret = $return
}
+/**
+ * probe tcp.receive - Called when a TCP packet is received
+ * @saddr: A string representing the source IP address
+ * @daddr: A string representing the destination IP address
+ * @sport: TCP source port
+ * @dport: TCP destination port
+ * @urg: TCP URG flag
+ * @ack: TCP ACK flag
+ * @psh: TCP PSH flag
+ * @rst: TCP RST flag
+ * @syn: TCP SYN flag
+ * @fin: TCP FIN flag
+ */
+probe tcp.receive = kernel.function("tcp_v4_rcv") {
+ iphdr = __get_skb_iphdr($skb)
+ saddr = ip_ntop(__ip_skb_saddr(iphdr))
+ daddr = ip_ntop(__ip_skb_daddr(iphdr))
+ protocol = __ip_skb_proto(iphdr)
+
+ tcphdr = __get_skb_tcphdr($skb)
+ dport = __tcp_skb_dport(tcphdr)
+ sport = __tcp_skb_sport(tcphdr)
+ urg = __tcp_skb_urg(tcphdr)
+ ack = __tcp_skb_ack(tcphdr)
+ psh = __tcp_skb_psh(tcphdr)
+ rst = __tcp_skb_rst(tcphdr)
+ syn = __tcp_skb_syn(tcphdr)
+ fin = __tcp_skb_fin(tcphdr)
+}
diff --git a/tapset/timestamp.stp b/tapset/timestamp.stp
index ce8f7558..0b9d350a 100644
--- a/tapset/timestamp.stp
+++ b/tapset/timestamp.stp
@@ -6,7 +6,11 @@
// 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.
-
+// <tapsetdescription>
+// Each timestamp function returns a value to indicate when a function is executed. These
+//returned values can then be used to indicate when an event occurred, provide an ordering for events,
+//or compute the amount of time elapsed between two time stamps.
+// </tapsetdescription>
/**
* sfunction get_cycles - Processor cycle count.
*
diff --git a/tapset/ucontext-symbols.stp b/tapset/ucontext-symbols.stp
new file mode 100644
index 00000000..5502f5cd
--- /dev/null
+++ b/tapset/ucontext-symbols.stp
@@ -0,0 +1,75 @@
+// User context symbols tapset
+// Copyright (C) 2009 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.
+
+// <tapsetdescription>
+// User context symbol functions provide additional information about
+// addresses from an application. These functions can provide
+// information about the user space map (library) that the event occured or
+// the function symbol of an address.
+// </tapsetdescription>
+
+%{
+#ifndef STP_NEED_SYMBOL_DATA
+#define STP_NEED_SYMBOL_DATA 1
+#endif
+#ifndef STP_NEED_VMA_TRACKER
+#define STP_NEED_VMA_TRACKER 1
+#endif
+%}
+
+/**
+ * sfunction usymname - Return the symbol of an address in the current task. EXPERIMENTAL!
+ * @addr: The address to translate.
+ *
+ * Description: Returns the (function) symbol name associated with the
+ * given address if known. If not known it will return the hex string
+ * representation of addr.
+ */
+function usymname:string (addr: long) %{ /* pure */
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, THIS->addr,
+ current, 0);
+%}
+
+/**
+ * sfunction usymdata - Return the symbol and module offset of an address. EXPERIMENTAL!
+ * @addr: The address to translate.
+ *
+ * Description: Returns the (function) symbol name associated with the
+ * given address in the current task if known, plus the module name
+ * (between brackets) and the offset inside the module (shared library),
+ * plus the size of the symbol function. If any element is not known it
+ * will be ommitted and if the symbol name is unknown it will return the
+ * hex string for the given address.
+ */
+function usymdata:string (addr: long) %{ /* pure */
+ _stp_symbol_snprint(THIS->__retvalue, MAXSTRINGLEN, THIS->addr,
+ current, 1);
+%}
+
+/**
+ * sfunction print_ustack - Print out stack for the current task from string. EXPERIMENTAL!
+ * @stk: String with list of hexidecimal addresses for the current task.
+ *
+ * Perform a symbolic lookup of the addresses in the given string,
+ * which is assumed to be the result of a prior call to
+ * <command>ubacktrace()</command> for the current task.
+ *
+ * Print one line per address, including the address, the
+ * name of the function containing the address, and an estimate of
+ * its position within that function. Return nothing.
+ */
+function print_ustack(stk:string) %{
+ char *ptr = THIS->stk;
+ char *tok = strsep(&ptr, " ");
+ while (tok && *tok) {
+ _stp_print_char(' ');
+ _stp_usymbol_print (simple_strtol(tok, NULL, 16), current);
+ _stp_print_char('\n');
+ tok = strsep(&ptr, " ");
+ }
+%}
diff --git a/tapset/ucontext-unwind.stp b/tapset/ucontext-unwind.stp
new file mode 100644
index 00000000..0801f1c9
--- /dev/null
+++ b/tapset/ucontext-unwind.stp
@@ -0,0 +1,52 @@
+// User context unwind tapset
+// Copyright (C) 2009 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+%{
+#ifndef STP_NEED_UNWIND_DATA
+#define STP_NEED_UNWIND_DATA 1
+#endif
+#ifndef STP_NEED_SYMBOL_DATA
+#define STP_NEED_SYMBOL_DATA 1
+#endif
+#ifndef STP_NEED_VMA_TRACKER
+#define STP_NEED_VMA_TRACKER 1
+#endif
+%}
+
+/**
+ * sfunction print_ubacktrace - Print stack back trace for current task. EXPERIMENTAL!
+ *
+ * Equivalent to <command>print_ustack(ubacktrace())</command>,
+ * except that deeper stack nesting may be supported. Return nothing.
+ */
+function print_ubacktrace () %{
+ if (CONTEXT->regs) {
+ _stp_stack_print(CONTEXT->regs, 1, CONTEXT->pi, MAXTRACE,
+ current);
+ } else {
+ _stp_printf("Systemtap probe: %s\n", CONTEXT->probe_point);
+ }
+%}
+
+/**
+ * sfunction ubacktrace - Hex backtrace of current task stack. EXPERIMENTAL!
+ *
+ * Return a string of hex addresses that are a backtrace of the
+ * stack of the current task. Output may be truncated as per maximum
+ * string length. Returns empty string when current probe point cannot
+ * determine user backtrace.
+ */
+
+function ubacktrace:string () %{ /* pure */
+ if (CONTEXT->regs)
+ _stp_stack_snprint (THIS->__retvalue, MAXSTRINGLEN,
+ CONTEXT->regs, 0, CONTEXT->pi, MAXTRACE,
+ current);
+ else
+ strlcpy (THIS->__retvalue, "", MAXSTRINGLEN);
+%}
diff --git a/tapset/udp.stp b/tapset/udp.stp
index 707cf77d..2255074a 100644
--- a/tapset/udp.stp
+++ b/tapset/udp.stp
@@ -5,7 +5,9 @@
// 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.
-
+// <tapsetdescription>
+// This family of probe points is used to probe events that occur in the UDP layer.
+// </tapsetdescription>
%{
#include <linux/version.h>
#include <net/sock.h>
@@ -15,12 +17,12 @@
/**
* probe udp.sendmsg - Fires whenever a process sends a UDP message
- * @name: Name of this probe
- * @sock: Network socket
- * @size: Number of bytes to send
+ * @name: The name of this probe
+ * @sock: Network socket used by the process
+ * @size: Number of bytes sent by the process
*
* Context:
- * The process which sends a udp message
+ * The process which sent a UDP message
*/
probe udp.sendmsg = kernel.function("udp_sendmsg") {
name = "udp.sendmsg"
@@ -30,11 +32,11 @@ probe udp.sendmsg = kernel.function("udp_sendmsg") {
/**
* probe udp.sendmsg.return - Fires whenever an attempt to send a UDP message is completed
- * @name: Name of this probe
- * @size: Number of bytes sent
+ * @name: The name of this probe
+ * @size: Number of bytes sent by the process
*
* Context:
- * The process which sends a udp message
+ * The process which sent a UDP message
*/
probe udp.sendmsg.return = kernel.function("udp_sendmsg").return {
name = "udp.sendmsg"
@@ -43,12 +45,12 @@ probe udp.sendmsg.return = kernel.function("udp_sendmsg").return {
/**
* probe udp.recvmsg - Fires whenever a UDP message is received
- * @name: Name of this probe
- * @sock: Network socket
- * @size: Number of bytes received
+ * @name: The name of this probe
+ * @sock: Network socket used by the process
+ * @size: Number of bytes received by the process
*
* Context:
- * The process which receives a udp message
+ * The process which received a UDP message
*/
probe udp.recvmsg = kernel.function("udp_recvmsg") {
name = "udp.recvmsg"
@@ -57,12 +59,12 @@ probe udp.recvmsg = kernel.function("udp_recvmsg") {
}
/**
- * probe udp.recvmsg.return - An attempt to receive a UDP message received has been completed
- * @name: Name of this probe
- * @size: Number of bytes received
+ * probe udp.recvmsg.return - Fires whenever an attempt to receive a UDP message received is completed
+ * @name: The name of this probe
+ * @size: Number of bytes received by the process
*
* Context:
- * The process which receives a udp message
+ * The process which received a UDP message
*/
probe udp.recvmsg.return = kernel.function("udp_recvmsg").return {
name = "udp.recvmsg"
@@ -70,13 +72,13 @@ probe udp.recvmsg.return = kernel.function("udp_recvmsg").return {
}
/**
- * probe udp.disconnect - A process requests for UPD to be UDP disconnected
- * @name: Name of this probe
- * @sock: Network socket
+ * probe udp.disconnect - Fires when a process requests for a UDP disconnection
+ * @name: The name of this probe
+ * @sock: Network socket used by the process
* @flags: Flags (e.g. FIN, etc)
*
* Context:
- * The process which disconnects UDP
+ * The process which requests a UDP disconnection
*/
probe udp.disconnect = kernel.function("udp_disconnect") {
name = "udp.disconnect"
@@ -86,11 +88,11 @@ probe udp.disconnect = kernel.function("udp_disconnect") {
/**
* probe udp.disconnect.return - UDP has been disconnected successfully
- * @name: Name of this probe
+ * @name: The name of this probe
* @ret: Error code (0: no error)
*
* Context:
- * The process which disconnects udp
+ * The process which requested a UDP disconnection
*/
probe udp.disconnect.return = kernel.function("udp_disconnect").return {
name = "udp.disconnect"
diff --git a/tapset/utrace.stp b/tapset/utrace.stp
index 34cb32c5..0d26ed5f 100644
--- a/tapset/utrace.stp
+++ b/tapset/utrace.stp
@@ -1,18 +1,26 @@
/* utrace-only subset of register accessors */
-
%{
#include "syscall.h"
%}
-function _utrace_syscall_nr:long () %{
- THIS->__retvalue = __stp_user_syscall_nr(CONTEXT->regs); /* pure */
+function _utrace_syscall_nr:long () %{ /* pure */
+ THIS->__retvalue = syscall_get_nr(current, CONTEXT->regs);
%}
-function _utrace_syscall_arg:long (n:long) %{
- THIS->__retvalue = *__stp_user_syscall_arg(current, CONTEXT->regs, (int)THIS->n); /* pure */
+function _utrace_syscall_arg:long (n:long) %{ /* pure */
+ unsigned long arg = 0;
+ syscall_get_arguments(current, CONTEXT->regs, (int)THIS->n, 1, &arg);
+ THIS->__retvalue = arg;
%}
-function _utrace_syscall_return:long () %{
- THIS->__retvalue = *__stp_user_syscall_return_value(current, CONTEXT->regs); /* pure */
+function _utrace_syscall_return:long () %{ /* pure */
+ /*
+ * Here's the reason for the "unsigned long" cast. Since all
+ * values inside systemtap are 64-bit numbers, return values were
+ * getting sign extended. This caused return values to not match
+ * up with the same values passes as arguments.
+ */
+ THIS->__retvalue = (unsigned long)syscall_get_return_value(current,
+ CONTEXT->regs);
%}
diff --git a/tapsets.cxx b/tapsets.cxx
index b02e2cce..d7e9ab4f 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -12,12 +12,14 @@
#include "staptree.h"
#include "elaborate.h"
#include "tapsets.h"
+#include "task_finder.h"
#include "translate.h"
#include "session.h"
#include "util.h"
#include "buildrun.h"
#include "dwarf_wrappers.h"
#include "auto_free.h"
+#include "hash.h"
#include <cstdlib>
#include <algorithm>
@@ -57,109 +59,16 @@ extern "C" {
}
-#ifdef PERFMON
-#include <perfmon/pfmlib.h>
-#include <perfmon/perfmon.h>
-#endif
-
using namespace std;
using namespace __gnu_cxx;
-// ------------------------------------------------------------------------
-// Generic derived_probe_group: contains an ordinary vector of the
-// given type. It provides only the enrollment function.
-
-template <class DP> struct generic_dpg: public derived_probe_group
-{
-protected:
- vector <DP*> probes;
-public:
- generic_dpg () {}
- void enroll (DP* probe) { probes.push_back (probe); }
-};
-
-
-
-// ------------------------------------------------------------------------
-// begin/end/error probes are run right during registration / deregistration
-// ------------------------------------------------------------------------
-
-static string TOK_BEGIN("begin");
-static string TOK_END("end");
-static string TOK_ERROR("error");
-
-enum be_t { BEGIN, END, ERROR };
-
-struct be_derived_probe: public derived_probe
-{
- be_t type;
- int64_t priority;
-
- be_derived_probe (probe* p, probe_point* l, be_t t, int64_t pr):
- derived_probe (p, l), type (t), priority (pr) {}
-
- void join_group (systemtap_session& s);
-
- static inline bool comp(be_derived_probe const *a,
- be_derived_probe const *b)
- {
- // This allows the BEGIN/END/ERROR probes to intermingle.
- // But that's OK - they're always treversed with a nested
- // "if (type==FOO)" conditional.
- return a->priority < b->priority;
- }
-
- bool needs_global_locks () { return false; }
- // begin/end probes don't need locks around global variables, since
- // they aren't run concurrently with any other probes
-};
-
-
-struct be_derived_probe_group: public generic_dpg<be_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-struct be_builder: public derived_probe_builder
-{
- be_t type;
-
- be_builder(be_t t) : type(t) {}
-
- virtual void build(systemtap_session &,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
- {
- int64_t priority;
- if ((type == BEGIN && !get_param(parameters, TOK_BEGIN, priority)) ||
- (type == END && !get_param(parameters, TOK_END, priority)) ||
- (type == ERROR && !get_param(parameters, TOK_ERROR, priority)))
- priority = 0;
- finished_results.push_back(
- new be_derived_probe(base, location, type, priority));
- }
-};
-
-
-void
-be_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.be_derived_probes)
- s.be_derived_probes = new be_derived_probe_group ();
- s.be_derived_probes->enroll (this);
-}
// ------------------------------------------------------------------------
void
common_probe_entryfn_prologue (translator_output* o, string statestr,
string new_pp,
- bool overload_processing = true)
+ bool overload_processing)
{
o->newline() << "struct context* __restrict__ c;";
o->newline() << "#if !INTERRUPTIBLE";
@@ -173,15 +82,6 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
o->newline() << "cycles_t cycles_atstart = get_cycles ();";
o->newline() << "#endif";
-#if 0 /* XXX: PERFMON */
- o->newline() << "static struct pfarg_ctx _pfm_context;";
- o->newline() << "static void *_pfm_desc;";
- o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;";
- o->newline() << "static int _pfm_num_pmc_x;";
- o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;";
- o->newline() << "static int _pfm_num_pmd_x;";
-#endif
-
o->newline() << "#if INTERRUPTIBLE";
o->newline() << "preempt_disable ();";
o->newline() << "#else";
@@ -206,7 +106,9 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
o->newline() << "c = per_cpu_ptr (contexts, smp_processor_id());";
o->newline() << "if (atomic_inc_return (& c->busy) != 1) {";
- o->newline(1) << "atomic_inc (& skipped_count);";
+ o->newline(1) << "#if !INTERRUPTIBLE";
+ o->newline() << "atomic_inc (& skipped_count);";
+ o->newline() << "#endif";
o->newline() << "#ifdef STP_TIMING";
o->newline() << "atomic_inc (& skipped_count_reentrant);";
o->newline() << "#ifdef DEBUG_REENTRANCY";
@@ -258,7 +160,7 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
void
common_probe_entryfn_epilogue (translator_output* o,
- bool overload_processing = true)
+ bool overload_processing)
{
if (overload_processing)
o->newline() << "#if defined(STP_TIMING) || defined(STP_OVERLOAD)";
@@ -344,124 +246,6 @@ common_probe_entryfn_epilogue (translator_output* o,
// ------------------------------------------------------------------------
-void
-be_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "/* ---- begin/end probes ---- */";
- s.op->newline() << "static void enter_begin_probe (void (*fn)(struct context*), const char* pp) {";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_STARTING", "pp", false);
- s.op->newline() << "(*fn) (c);";
- common_probe_entryfn_epilogue (s.op, false);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static void enter_end_probe (void (*fn)(struct context*), const char* pp) {";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_STOPPING", "pp", false);
- s.op->newline() << "(*fn) (c);";
- common_probe_entryfn_epilogue (s.op, false);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static void enter_error_probe (void (*fn)(struct context*), const char* pp) {";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_ERROR", "pp", false);
- s.op->newline() << "(*fn) (c);";
- common_probe_entryfn_epilogue (s.op, false);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static struct stap_be_probe {";
- s.op->newline(1) << "void (*ph)(struct context*);";
- s.op->newline() << "const char* pp;";
- s.op->newline() << "int type;";
- s.op->newline(-1) << "} stap_be_probes[] = {";
- s.op->indent(1);
-
- // NB: We emit the table in sorted order here, so we don't have to
- // store the priority numbers as integers and sort at run time.
-
- sort(probes.begin(), probes.end(), be_derived_probe::comp);
-
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .pp="
- << lex_cast_qstring (*probes[i]->sole_location()) << ",";
- s.op->line() << " .ph=&" << probes[i]->name << ",";
- s.op->line() << " .type=" << probes[i]->type;
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
-}
-
-void
-be_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
- s.op->newline() << "if (stp->type != " << BEGIN << ") continue;";
- s.op->newline() << "enter_begin_probe (stp->ph, stp->pp);";
- s.op->newline() << "/* rc = 0; */";
- // NB: begin probes that cause errors do not constitute registration
- // failures. An error message will probably get printed and if
- // MAXERRORS was left at 1, we'll get an stp_exit. The
- // error-handling probes will be run during the ordinary
- // unregistration phase.
- s.op->newline(-1) << "}";
-}
-
-void
-be_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
- s.op->newline() << "if (stp->type != " << END << ") continue;";
- s.op->newline() << "enter_end_probe (stp->ph, stp->pp);";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_be_probe* stp = & stap_be_probes [i];";
- s.op->newline() << "if (stp->type != " << ERROR << ") continue;";
- s.op->newline() << "enter_error_probe (stp->ph, stp->pp);";
- s.op->newline(-1) << "}";
-}
-
-
-
-// ------------------------------------------------------------------------
-// never probes are never run
-// ------------------------------------------------------------------------
-
-static string TOK_NEVER("never");
-
-struct never_derived_probe: public derived_probe
-{
- never_derived_probe (probe* p): derived_probe (p) {}
- never_derived_probe (probe* p, probe_point* l): derived_probe (p, l) {}
- void join_group (systemtap_session&) { /* thus no probe_group */ }
-};
-
-
-struct never_builder: public derived_probe_builder
-{
- never_builder() {}
- virtual void build(systemtap_session &,
- probe * base,
- probe_point * location,
- literal_map_t const &,
- vector<derived_probe *> & finished_results)
- {
- finished_results.push_back(new never_derived_probe(base, location));
- }
-};
-
-
-
// ------------------------------------------------------------------------
// Dwarf derived probes. "We apologize for the inconvience."
// ------------------------------------------------------------------------
@@ -600,7 +384,8 @@ typedef tr1::unordered_map<string,Dwarf_Die> cu_function_cache_t;
typedef tr1::unordered_map<string,cu_function_cache_t*> mod_cu_function_cache_t; // module:cu -> function -> die
#else
struct stringhash {
- size_t operator() (const string& s) const { hash<const char*> h; return h(s.c_str()); }
+ // __gnu_cxx:: is needed because our own hash.h has an ambiguous hash<> decl too.
+ size_t operator() (const string& s) const { __gnu_cxx::hash<const char*> h; return h(s.c_str()); }
};
typedef hash_map<string,Dwarf_Die,stringhash> cu_function_cache_t;
@@ -664,6 +449,15 @@ enum line_t { ABSOLUTE, RELATIVE, RANGE, WILDCARD };
typedef vector<inline_instance_info> inline_instance_map_t;
typedef vector<func_info> func_info_map_t;
+
+// PR 9941 introduces the need for a predicate
+
+int dwfl_report_offline_predicate (const char* modname, const char* filename)
+{
+ if (pending_interrupts) { return -1; }
+ return 1;
+}
+
struct dwflpp
{
systemtap_session & sess;
@@ -942,7 +736,7 @@ struct dwflpp
int rc = dwfl_linux_kernel_report_offline (dwfl,
elfutils_kernel_path.c_str(),
- NULL);
+ &dwfl_report_offline_predicate);
if (debuginfo_needed)
dwfl_assert (string("missing ") + sess.architecture +
@@ -1036,7 +830,10 @@ struct dwflpp
off = dwfl_getmodules (dwfl, callback, data, off);
}
while (off > 0);
- dwfl_assert("dwfl_getmodules", off == 0);
+ // Don't complain if we exited dwfl_getmodules early.
+ // This could be a $target variable error that will be
+ // reported soon anyway.
+ // dwfl_assert("dwfl_getmodules", off == 0);
// PR6864 XXX: For dwarfless case (if .../vmlinux is missing), then the
// "kernel" module is not reported in the loop above. However, we
@@ -1332,82 +1129,14 @@ struct dwflpp
}
void
- iterate_over_cu_labels (string label_val, Dwarf_Die *cu, void *data,
- void (* callback)(const string &,
- const char *,
- int,
- Dwarf_Die *,
- Dwarf_Addr,
- dwarf_query *))
- {
- dwarf_query * q __attribute__ ((unused)) = static_cast<dwarf_query *>(data) ;
-
- get_module_dwarf();
-
- const char * sym = label_val.c_str();
- Dwarf_Die die;
- int res = dwarf_child (cu, &die);
- if (res != 0)
- return; // die without children, bail out.
-
- static string function_name;
- do
- {
- Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem);
- int tag = dwarf_tag(&die);
- const char *name = dwarf_formstring (attr);
- if (tag == DW_TAG_subprogram && name != 0)
- {
- function_name = name;
- }
- else if (tag == DW_TAG_label && name != 0
- && ((strncmp(name, sym, strlen(sym)) == 0)
- || (name_has_wildcard (sym)
- && function_name_matches_pattern (name, sym))))
- {
- const char *file = dwarf_decl_file (&die);
- // Get the line number for this label
- Dwarf_Attribute attr;
- dwarf_attr (&die,DW_AT_decl_line, &attr);
- Dwarf_Sword dline;
- dwarf_formsdata (&attr, &dline);
- Dwarf_Addr stmt_addr;
- if (dwarf_lowpc (&die, &stmt_addr) != 0)
- {
- // There is no lowpc so figure out the address
- // Get the real die for this cu
- Dwarf_Die cudie;
- dwarf_diecu (cu, &cudie, NULL, NULL);
- size_t nlines = 0;
- // Get the line for this label
- Dwarf_Line **aline;
- dwarf_getsrc_file (module_dwarf, file, (int)dline, 0, &aline, &nlines);
- // Get the address
- for (size_t i = 0; i < nlines; i++)
- {
- dwarf_lineaddr (*aline, &stmt_addr);
- if ((dwarf_haspc (&die, stmt_addr)))
- break;
- }
- }
-
- Dwarf_Die *scopes;
- int nscopes = 0;
- nscopes = dwarf_getscopes_die (&die, &scopes);
- if (nscopes > 1)
- callback(function_name.c_str(), file,
- (int)dline, &scopes[1], stmt_addr, q);
- }
- if (dwarf_haschildren (&die) && tag != DW_TAG_structure_type
- && tag != DW_TAG_union_type)
- {
- iterate_over_cu_labels (label_val, &die, q, callback);
- }
- }
- while (dwarf_siblingof (&die, &die) == 0);
- }
-
+ iterate_over_labels (Dwarf_Die *begin_die,
+ void *data,
+ void (* callback)(const string &,
+ const char *,
+ int,
+ Dwarf_Die *,
+ Dwarf_Addr,
+ dwarf_query *));
void collect_srcfiles_matching (string const & pattern,
set<char const *> & filtered_srcfiles)
@@ -1695,15 +1424,25 @@ struct dwflpp
// relocatable module probing code will need to have.
Dwfl_Module *mod = dwfl_addrmodule (dwfl, address);
dwfl_assert ("dwfl_addrmodule", mod);
+ const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL);
int n = dwfl_module_relocations (mod);
dwfl_assert ("dwfl_module_relocations", n >= 0);
- int i = dwfl_module_relocate_address (mod, &address);
+ Dwarf_Addr reloc_address = address;
+ int i = dwfl_module_relocate_address (mod, &reloc_address);
dwfl_assert ("dwfl_module_relocate_address", i >= 0);
- const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL);
dwfl_assert ("dwfl_module_info", modname);
const char *secname = dwfl_module_relocation_info (mod, i, NULL);
+ if (sess.verbose > 2)
+ {
+ clog << "emit dwarf addr 0x" << hex << address << dec
+ << " => module " << modname
+ << " section " << (secname ?: "null")
+ << " relocaddr 0x" << hex << reloc_address << dec
+ << endl;
+ }
+
if (n > 0 && !(n == 1 && secname == NULL))
{
dwfl_assert ("dwfl_module_relocation_info", secname);
@@ -1713,7 +1452,7 @@ struct dwflpp
// module, for a kernel module (or other ET_REL module object).
obstack_printf (pool, "({ static unsigned long addr = 0; ");
obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
- modname, secname, address);
+ modname, secname, reloc_address);
obstack_printf (pool, "addr; })");
}
else if (n == 1 && module_name == TOK_KERNEL && secname[0] == '\0')
@@ -1724,7 +1463,7 @@ struct dwflpp
secname = "_stext";
obstack_printf (pool, "({ static unsigned long addr = 0; ");
obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
- modname, secname, address);
+ modname, secname, address); // PR10000 NB: not reloc_address
obstack_printf (pool, "addr; })");
}
else
@@ -1779,6 +1518,7 @@ struct dwflpp
find_variable_and_frame_base (Dwarf_Die *scope_die,
Dwarf_Addr pc,
string const & local,
+ const target_symbol *e,
Dwarf_Die *vardie,
Dwarf_Attribute *fb_attr_mem)
{
@@ -1806,7 +1546,8 @@ struct dwflpp
+ (dwarf_diename(scope_die) ?: "<unknown>")
+ "(" + (dwarf_diename(cu) ?: "<unknown>")
+ ")"))
- + " while searching for local '" + local + "'");
+ + " while searching for local '" + local + "'",
+ e->tok);
}
int declaring_scope = dwarf_getscopevar (scopes, nscopes,
@@ -1824,7 +1565,8 @@ struct dwflpp
+ (dwarf_diename(scope_die) ?: "<unknown>")
+ "(" + (dwarf_diename(cu) ?: "<unknown>")
+ ")"))
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
+ + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")),
+ e->tok);
}
for (int inner = 0; inner < nscopes; ++inner)
@@ -1851,7 +1593,8 @@ struct dwflpp
translate_location(struct obstack *pool,
Dwarf_Attribute *attr, Dwarf_Addr pc,
Dwarf_Attribute *fb_attr,
- struct location **tail)
+ struct location **tail,
+ const target_symbol *e)
{
Dwarf_Op *expr;
size_t len;
@@ -1870,12 +1613,13 @@ struct dwflpp
/* Fall through. */
case 0: /* Shouldn't happen. */
- throw semantic_error ("not accessible at this address");
+ throw semantic_error ("not accessible at this address", e->tok);
default: /* Shouldn't happen. */
case -1:
throw semantic_error (string ("dwarf_getlocation_addr failed") +
- string (dwarf_errmsg (-1)));
+ string (dwarf_errmsg (-1)),
+ e->tok);
}
return c_translate_location (pool, &loc2c_error, this,
@@ -1923,63 +1667,124 @@ struct dwflpp
while (dwarf_tag (die) == DW_TAG_member)
{
const char *member = dwarf_diename_integrate (die) ;
-
- if ( member != NULL )
-
- o << " " << member;
+ if ( member != NULL )
+ o << " " << member;
else
- {
- Dwarf_Die temp_die = *die;
- Dwarf_Attribute temp_attr ;
-
- if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
- {
- clog<<"\n Error in obtaining type attribute for "
- <<(dwarf_diename(&temp_die)?:"<anonymous>");
- return ;
- }
+ {
+ Dwarf_Die temp_die = *die;
+ Dwarf_Attribute temp_attr ;
- if ( ! dwarf_formref_die (&temp_attr,&temp_die))
- {
- clog<<"\n Error in decoding type attribute for "
- <<(dwarf_diename(&temp_die)?:"<anonymous>");
- return ;
- }
- print_members(&temp_die,o);
+ if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
+ {
+ clog << "\n Error in obtaining type attribute for "
+ << (dwarf_diename(&temp_die)?:"<anonymous>");
+ return;
+ }
- }
+ if (!dwarf_formref_die (&temp_attr, &temp_die))
+ {
+ clog << "\n Error in decoding type attribute for "
+ << (dwarf_diename(&temp_die)?:"<anonymous>");
+ return;
+ }
+
+ print_members(&temp_die,o);
+ }
if (dwarf_siblingof (die, &die_mem) != 0)
break;
}
}
+ bool
+ find_struct_member(const string& member,
+ Dwarf_Die *parentdie,
+ const target_symbol *e,
+ Dwarf_Die *memberdie,
+ vector<Dwarf_Attribute>& locs)
+ {
+ Dwarf_Attribute attr;
+ Dwarf_Die die = *parentdie;
+
+ switch (dwarf_child (&die, &die))
+ {
+ case 0: /* First child found. */
+ break;
+ case 1: /* No children. */
+ return false;
+ case -1: /* Error. */
+ default: /* Shouldn't happen */
+ throw semantic_error (string (dwarf_tag(&die) == DW_TAG_union_type ? "union" : "struct")
+ + string (dwarf_diename_integrate (&die) ?: "<anonymous>")
+ + string (dwarf_errmsg (-1)),
+ e->tok);
+ }
+
+ do
+ {
+ if (dwarf_tag(&die) != DW_TAG_member)
+ continue;
+
+ const char *name = dwarf_diename_integrate(&die);
+ if (name == NULL)
+ {
+ // need to recurse for anonymous structs/unions
+ Dwarf_Die subdie;
+
+ if (!dwarf_attr_integrate (&die, DW_AT_type, &attr) ||
+ !dwarf_formref_die (&attr, &subdie))
+ continue;
+
+ if (find_struct_member(member, &subdie, e, memberdie, locs))
+ goto success;
+ }
+ else if (name == member)
+ {
+ *memberdie = die;
+ goto success;
+ }
+ }
+ while (dwarf_siblingof (&die, &die) == 0);
+
+ return false;
+
+success:
+ /* As we unwind the recursion, we need to build the chain of
+ * locations that got to the final answer. */
+ if (dwarf_attr_integrate (&die, DW_AT_data_member_location, &attr))
+ locs.insert(locs.begin(), attr);
+
+ /* Union members don't usually have a location,
+ * but just use the containing union's location. */
+ else if (dwarf_tag(parentdie) != DW_TAG_union_type)
+ throw semantic_error ("no location for field '" + member
+ + "': " + string(dwarf_errmsg (-1)),
+ e->tok);
+
+ return true;
+ }
+
Dwarf_Die *
translate_components(struct obstack *pool,
struct location **tail,
Dwarf_Addr pc,
- vector<pair<target_symbol::component_type,
- std::string> > const & components,
+ const target_symbol *e,
Dwarf_Die *vardie,
Dwarf_Die *die_mem,
Dwarf_Attribute *attr_mem)
{
- Dwarf_Die *die = die_mem;
- Dwarf_Die struct_die;
- Dwarf_Attribute temp_attr;
+ Dwarf_Die *die = NULL;
unsigned i = 0;
if (vardie)
*die_mem = *vardie;
- static unsigned int func_call_level ;
- static unsigned int dwarf_error_flag ; // indicates current error is dwarf error
- static unsigned int dwarf_error_count ; // keeps track of no of dwarf errors
- static semantic_error saved_dwarf_error("");
+ if (e->components.empty())
+ return die_mem;
- while (i < components.size())
+ while (i < e->components.size())
{
/* XXX: This would be desirable, but we don't get the target_symbol token,
and printing that gives us the file:line number too early anyway. */
@@ -1990,6 +1795,7 @@ struct dwflpp
obstack_printf (pool, "c->last_stmt = %s;", lex_cast_qstring(piece).c_str());
#endif
+ die = die ? dwarf_formref_die (attr_mem, die_mem) : die_mem;
const int typetag = dwarf_tag (die);
switch (typetag)
{
@@ -2000,8 +1806,8 @@ struct dwflpp
break;
case DW_TAG_pointer_type:
- if (components[i].first == target_symbol::comp_literal_array_index)
- throw semantic_error ("cannot index pointer");
+ if (e->components[i].first == target_symbol::comp_literal_array_index)
+ throw semantic_error ("cannot index pointer", e->tok);
// XXX: of course, we should support this the same way C does,
// by explicit pointer arithmetic etc. PR4166.
@@ -2009,138 +1815,84 @@ struct dwflpp
break;
case DW_TAG_array_type:
- if (components[i].first == target_symbol::comp_literal_array_index)
+ if (e->components[i].first == target_symbol::comp_literal_array_index)
{
c_translate_array (pool, 1, 0 /* PR9768 */, die, tail,
- NULL, lex_cast<Dwarf_Word>(components[i].second));
+ NULL, lex_cast<Dwarf_Word>(e->components[i].second));
++i;
}
else
throw semantic_error("bad field '"
- + components[i].second
- + "' for array type");
+ + e->components[i].second
+ + "' for array type",
+ e->tok);
break;
case DW_TAG_structure_type:
case DW_TAG_union_type:
- struct_die = *die;
if (dwarf_hasattr(die, DW_AT_declaration))
{
Dwarf_Die *tmpdie = dwflpp::declaration_resolve(dwarf_diename(die));
if (tmpdie == NULL)
throw semantic_error ("unresolved struct "
- + string (dwarf_diename_integrate (die) ?: "<anonymous>"));
+ + string (dwarf_diename_integrate (die) ?: "<anonymous>"),
+ e->tok);
*die_mem = *tmpdie;
}
- switch (dwarf_child (die, die_mem))
+
{
- case 1: /* No children. */
- return NULL;
- case -1: /* Error. */
- default: /* Shouldn't happen */
- throw semantic_error (string (typetag == DW_TAG_union_type ? "union" : "struct")
- + string (dwarf_diename_integrate (die) ?: "<anonymous>")
- + string (dwarf_errmsg (-1)));
- break;
+ vector<Dwarf_Attribute> locs;
+ if (!find_struct_member(e->components[i].second, die, e, die, locs))
+ {
+ string alternatives;
+ stringstream members;
+ print_members(die, members);
+ if (members.str().size() != 0)
+ alternatives = " (alternatives:" + members.str();
+ throw semantic_error("unable to find member '" +
+ e->components[i].second + "' for struct "
+ + string(dwarf_diename_integrate(die) ?: "<unknown>")
+ + alternatives,
+ e->tok);
+ }
- case 0:
- break;
+ for (unsigned j = 0; j < locs.size(); ++j)
+ translate_location (pool, &locs[j], pc, NULL, tail, e);
}
- while (dwarf_tag (die) != DW_TAG_member
- || ({ const char *member = dwarf_diename_integrate (die);
- member == NULL || string(member) != components[i].second; }))
- {
- if ( dwarf_diename (die) == NULL ) // handling Anonymous structs/unions
- {
- Dwarf_Die temp_die = *die;
- Dwarf_Die temp_die_2;
-
- try
- {
- if (!dwarf_attr_integrate (&temp_die, DW_AT_type, &temp_attr))
- {
- dwarf_error_flag ++ ;
- dwarf_error_count ++;
- throw semantic_error(" Error in obtaining type attribute for "+ string(dwarf_diename(&temp_die)?:"<anonymous>"));
- }
-
- if ( !dwarf_formref_die (&temp_attr, &temp_die))
- {
- dwarf_error_flag ++ ;
- dwarf_error_count ++;
- throw semantic_error(" Error in decoding DW_AT_type attribute for " + string(dwarf_diename(&temp_die)?:"<anonymous>"));
- }
-
- func_call_level ++ ;
-
- Dwarf_Die *result_die = translate_components(pool, tail, pc, components, &temp_die, &temp_die_2, &temp_attr );
-
- func_call_level -- ;
-
- if (result_die != NULL)
- {
- memcpy(die_mem, &temp_die_2, sizeof(Dwarf_Die));
- memcpy(attr_mem, &temp_attr, sizeof(Dwarf_Attribute));
- return die_mem;
- }
- }
- catch (const semantic_error& e)
- {
- if ( !dwarf_error_flag ) //not a dwarf error
- throw;
- else
- {
- dwarf_error_flag = 0 ;
- saved_dwarf_error = e ;
- }
- }
- }
- if (dwarf_siblingof (die, die_mem) != 0)
- {
- if ( func_call_level == 0 && dwarf_error_count ) // this is parent call & a dwarf error has been reported in a branch somewhere
- throw semantic_error( saved_dwarf_error );
- else
- return NULL;
- }
- }
-
- if (dwarf_attr_integrate (die, DW_AT_data_member_location,
- attr_mem) == NULL)
- {
- /* Union members don't usually have a location,
- but just use the containing union's location. */
- if (typetag != DW_TAG_union_type)
- throw semantic_error ("no location for field '"
- + components[i].second
- + "' :" + string(dwarf_errmsg (-1)));
- }
- else
- translate_location (pool, attr_mem, pc, NULL, tail);
++i;
break;
+ case DW_TAG_enumeration_type:
+ throw semantic_error ("field '"
+ + e->components[i].second
+ + "' vs. enum type "
+ + string(dwarf_diename_integrate (die) ?: "<anonymous type>"),
+ e->tok);
+ break;
case DW_TAG_base_type:
throw semantic_error ("field '"
- + components[i].second
+ + e->components[i].second
+ "' vs. base type "
- + string(dwarf_diename_integrate (die) ?: "<anonymous type>"));
+ + string(dwarf_diename_integrate (die) ?: "<anonymous type>"),
+ e->tok);
break;
case -1:
- throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1)));
+ throw semantic_error ("cannot find type: " + string(dwarf_errmsg (-1)),
+ e->tok);
break;
default:
throw semantic_error (string(dwarf_diename_integrate (die) ?: "<anonymous type>")
+ ": unexpected type tag "
- + lex_cast<string>(dwarf_tag (die)));
+ + lex_cast<string>(dwarf_tag (die)),
+ e->tok);
break;
}
/* Now iterate on the type in DIE's attribute. */
if (dwarf_attr_integrate (die, DW_AT_type, attr_mem) == NULL)
- throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)));
- die = dwarf_formref_die (attr_mem, die_mem);
+ throw semantic_error ("cannot get type of field: " + string(dwarf_errmsg (-1)), e->tok);
}
return die;
}
@@ -2148,23 +1900,23 @@ struct dwflpp
Dwarf_Die *
resolve_unqualified_inner_typedie (Dwarf_Die *typedie_mem,
- Dwarf_Attribute *attr_mem)
+ Dwarf_Attribute *attr_mem,
+ const target_symbol *e)
{
- ;
Dwarf_Die *typedie;
int typetag = 0;
while (1)
{
typedie = dwarf_formref_die (attr_mem, typedie_mem);
if (typedie == NULL)
- throw semantic_error ("cannot get type: " + string(dwarf_errmsg (-1)));
+ throw semantic_error ("cannot get type: " + string(dwarf_errmsg (-1)), e->tok);
typetag = dwarf_tag (typedie);
if (typetag != DW_TAG_typedef &&
typetag != DW_TAG_const_type &&
typetag != DW_TAG_volatile_type)
break;
if (dwarf_attr_integrate (typedie, DW_AT_type, attr_mem) == NULL)
- throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1)));
+ throw semantic_error ("cannot get type of pointee: " + string(dwarf_errmsg (-1)), e->tok);
}
return typedie;
}
@@ -2177,6 +1929,7 @@ struct dwflpp
Dwarf_Die *die,
Dwarf_Attribute *attr_mem,
bool lvalue,
+ const target_symbol *e,
string &,
string &,
exp_type & ty)
@@ -2190,7 +1943,7 @@ struct dwflpp
char const *dname;
string diestr;
- typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem);
+ typedie = resolve_unqualified_inner_typedie (&typedie_mem, attr_mem, e);
typetag = dwarf_tag (typedie);
/* Then switch behavior depending on the type of fetch/store we
@@ -2203,7 +1956,7 @@ struct dwflpp
diestr = (dname != NULL) ? dname : "<unknown>";
throw semantic_error ("unsupported type tag "
+ lex_cast<string>(typetag)
- + " for " + diestr);
+ + " for " + diestr, e->tok);
break;
case DW_TAG_structure_type:
@@ -2211,7 +1964,7 @@ struct dwflpp
dname = dwarf_diename(die);
diestr = (dname != NULL) ? dname : "<unknown>";
throw semantic_error ("struct/union '" + diestr
- + "' is being accessed instead of a member of the struct/union");
+ + "' is being accessed instead of a member of the struct/union", e->tok);
break;
case DW_TAG_enumeration_type:
@@ -2230,7 +1983,7 @@ struct dwflpp
{
// clog << "bad type1 " << encoding << " diestr" << endl;
throw semantic_error ("unsupported type (mystery encoding " + lex_cast<string>(encoding) + ")" +
- " for " + diestr);
+ " for " + diestr, e->tok);
}
if (encoding == DW_ATE_float
@@ -2239,7 +1992,7 @@ struct dwflpp
{
// clog << "bad type " << encoding << " diestr" << endl;
throw semantic_error ("unsupported type (encoding " + lex_cast<string>(encoding) + ")" +
- " for " + diestr);
+ " for " + diestr, e->tok);
}
}
@@ -2261,7 +2014,7 @@ struct dwflpp
Dwarf_Word pointee_encoding;
Dwarf_Word pointee_byte_size = 0;
- pointee_typedie = resolve_unqualified_inner_typedie (&pointee_typedie_mem, attr_mem);
+ pointee_typedie = resolve_unqualified_inner_typedie (&pointee_typedie_mem, attr_mem, e);
if (dwarf_attr_integrate (pointee_typedie, DW_AT_byte_size, attr_mem))
dwarf_formudata (attr_mem, &pointee_byte_size);
@@ -2273,7 +2026,7 @@ struct dwflpp
{
ty = pe_long;
if (typetag == DW_TAG_array_type)
- throw semantic_error ("cannot write to array address");
+ throw semantic_error ("cannot write to array address", e->tok);
assert (typetag == DW_TAG_pointer_type);
c_translate_pointer_store (pool, 1, 0 /* PR9768 */, typedie, tail,
"THIS->value");
@@ -2338,15 +2091,14 @@ struct dwflpp
literal_stmt_for_local (Dwarf_Die *scope_die,
Dwarf_Addr pc,
string const & local,
- vector<pair<target_symbol::component_type,
- std::string> > const & components,
+ const target_symbol *e,
bool lvalue,
exp_type & ty)
{
Dwarf_Die vardie;
Dwarf_Attribute fb_attr_mem, *fb_attr = NULL;
- fb_attr = find_variable_and_frame_base (scope_die, pc, local,
+ fb_attr = find_variable_and_frame_base (scope_die, pc, local, e,
&vardie, &fb_attr_mem);
if (sess.verbose>2)
@@ -2362,7 +2114,8 @@ struct dwflpp
"attribute for local '" + local
+ "' (dieoffset: "
+ lex_cast_hex<string>(dwarf_dieoffset (&vardie))
- + ")");
+ + ")",
+ e->tok);
}
#define obstack_chunk_alloc malloc
@@ -2375,28 +2128,19 @@ struct dwflpp
/* Given $foo->bar->baz[NN], translate the location of foo. */
struct location *head = translate_location (&pool,
- &attr_mem, pc, fb_attr, &tail);
+ &attr_mem, pc, fb_attr, &tail,
+ e);
if (dwarf_attr_integrate (&vardie, DW_AT_type, &attr_mem) == NULL)
throw semantic_error("failed to retrieve type "
- "attribute for local '" + local + "'");
+ "attribute for local '" + local + "'",
+ e->tok);
/* Translate the ->bar->baz[NN] parts. */
- Dwarf_Die die_mem, *die = NULL;
- die = dwarf_formref_die (&attr_mem, &die_mem);
- die = translate_components (&pool, &tail, pc, components,
+ Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem);
+ die = translate_components (&pool, &tail, pc, e,
die, &die_mem, &attr_mem);
- if(!die)
- {
- die = dwarf_formref_die (&attr_mem, &vardie);
- stringstream alternatives;
- if (die != NULL)
- print_members(die,alternatives);
- throw semantic_error("unable to find local '" + local + "'"
- + " near pc " + lex_cast_hex<string>(pc)
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
- }
/* Translate the assignment part, either
x = $foo->bar->baz[NN]
@@ -2406,7 +2150,7 @@ struct dwflpp
string prelude, postlude;
translate_final_fetch_or_store (&pool, &tail, module_bias,
- die, &attr_mem, lvalue,
+ die, &attr_mem, lvalue, e,
prelude, postlude, ty);
/* Write the translation to a string. */
@@ -2417,8 +2161,7 @@ struct dwflpp
string
literal_stmt_for_return (Dwarf_Die *scope_die,
Dwarf_Addr pc,
- vector<pair<target_symbol::component_type,
- std::string> > const & components,
+ const target_symbol *e,
bool lvalue,
exp_type & ty)
{
@@ -2443,7 +2186,8 @@ struct dwflpp
" for "
+ string(dwarf_diename(scope_die) ?: "<unknown>")
+ "(" + string(dwarf_diename(cu) ?: "<unknown>")
- + ")");
+ + ")",
+ e->tok);
}
// the function has no return value (e.g. "void" in C)
else if (nlocops == 0)
@@ -2451,7 +2195,8 @@ struct dwflpp
throw semantic_error("function "
+ string(dwarf_diename(scope_die) ?: "<unknown>")
+ "(" + string(dwarf_diename(cu) ?: "<unknown>")
- + ") has no return value");
+ + ") has no return value",
+ e->tok);
}
struct location *head = c_translate_location (&pool, &loc2c_error, this,
@@ -2463,29 +2208,16 @@ struct dwflpp
/* Translate the ->bar->baz[NN] parts. */
Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = dwarf_attr (scope_die, DW_AT_type, &attr_mem);
-
- Dwarf_Die vardie_mem;
- Dwarf_Die *vardie = dwarf_formref_die (attr, &vardie_mem);
-
- Dwarf_Die die_mem, *die = NULL;
- die = translate_components (&pool, &tail, pc, components,
- vardie, &die_mem, &attr_mem);
- if(!die)
- {
- die = dwarf_formref_die (&attr_mem, vardie);
- stringstream alternatives;
- if (die != NULL)
- print_members(die,alternatives);
- throw semantic_error("unable to find return value"
- " near pc " + lex_cast_hex<string>(pc)
- + " for "
- + string(dwarf_diename(scope_die) ?: "<unknown>")
- + "(" + string(dwarf_diename(cu) ?: "<unknown>")
- + ")"
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
- }
-
+ if (dwarf_attr_integrate (scope_die, DW_AT_type, &attr_mem) == NULL)
+ throw semantic_error("failed to retrieve return value type attribute for "
+ + string(dwarf_diename(scope_die) ?: "<unknown>")
+ + "(" + string(dwarf_diename(cu) ?: "<unknown>")
+ + ")",
+ e->tok);
+
+ Dwarf_Die die_mem, *die = dwarf_formref_die (&attr_mem, &die_mem);
+ die = translate_components (&pool, &tail, pc, e,
+ die, &die_mem, &attr_mem);
/* Translate the assignment part, either
x = $return->bar->baz[NN]
@@ -2495,7 +2227,7 @@ struct dwflpp
string prelude, postlude;
translate_final_fetch_or_store (&pool, &tail, module_bias,
- die, &attr_mem, lvalue,
+ die, &attr_mem, lvalue, e,
prelude, postlude, ty);
/* Write the translation to a string. */
@@ -2505,8 +2237,7 @@ struct dwflpp
string
literal_stmt_for_pointer (Dwarf_Die *type_die,
- vector<pair<target_symbol::component_type,
- std::string> > const & components,
+ const target_symbol *e,
bool lvalue,
exp_type & ty)
{
@@ -2528,18 +2259,8 @@ struct dwflpp
Dwarf_Attribute attr_mem;
Dwarf_Die die_mem, *die = NULL;
- die = translate_components (&pool, &tail, 0, components,
+ die = translate_components (&pool, &tail, 0, e,
type_die, &die_mem, &attr_mem);
- if(!die)
- {
- die = dwarf_formref_die (&attr_mem, &die_mem);
- stringstream alternatives;
- print_members(die ?: type_die, alternatives);
- throw semantic_error("unable to find member for struct "
- + string(dwarf_diename(die ?: type_die) ?: "<unknown>")
- + (alternatives.str() == "" ? "" : (" (alternatives:" + alternatives.str () + ")")));
- }
-
/* Translate the assignment part, either
x = (THIS->pointer)->bar->baz[NN]
@@ -2549,7 +2270,7 @@ struct dwflpp
string prelude, postlude;
translate_final_fetch_or_store (&pool, &tail, module_bias,
- die, &attr_mem, lvalue,
+ die, &attr_mem, lvalue, e,
prelude, postlude, ty);
/* Write the translation to a string. */
@@ -2649,8 +2370,6 @@ struct uprobe_derived_probe: public derived_probe
void join_group (systemtap_session& s);
};
-
-
struct dwarf_derived_probe_group: public derived_probe_group
{
private:
@@ -2833,6 +2552,8 @@ struct dwarf_query : public base_query
bool has_absolute;
+ bool has_mark;
+
enum dbinfo_reqt dbinfo_reqt;
enum dbinfo_reqt assess_dbinfo_reqt();
@@ -2922,7 +2643,7 @@ dwflpp::has_single_line_record (dwarf_query * q, char const * srcfile, int linen
* only picks up top level stuff (i.e. nothing in a lower scope) */
int
dwflpp::iterate_over_globals (int (* callback)(Dwarf_Die *, void *),
- void * data)
+ void * data)
{
int rc = DWARF_CB_OK;
Dwarf_Die die;
@@ -2934,18 +2655,20 @@ dwflpp::iterate_over_globals (int (* callback)(Dwarf_Die *, void *),
if (dwarf_child(cu, &die) != 0)
return rc;
- do {
- /* We're only currently looking for structures and unions,
+ do
+ /* We're only currently looking for named types,
* although other types of declarations exist */
- if (dwarf_tag(&die) != DW_TAG_structure_type &&
- dwarf_tag(&die) != DW_TAG_union_type)
- continue;
-
- rc = (*callback)(&die, data);
- if (rc != DWARF_CB_OK)
- break;
-
- } while (dwarf_siblingof(&die, &die) == 0);
+ switch (dwarf_tag(&die))
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ rc = (*callback)(&die, data);
+ break;
+ }
+ while (rc == DWARF_CB_OK && dwarf_siblingof(&die, &die) == 0);
return rc;
}
@@ -3012,6 +2735,103 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query *
}
+void
+dwflpp::iterate_over_labels (Dwarf_Die *begin_die,
+ void *data,
+ void (* callback)(const string &,
+ const char *,
+ int,
+ Dwarf_Die *,
+ Dwarf_Addr,
+ dwarf_query *))
+{
+ dwarf_query * q __attribute__ ((unused)) = static_cast<dwarf_query *>(data) ;
+
+ get_module_dwarf();
+
+ const char * sym = q->label_val.c_str();
+ Dwarf_Die die;
+ int res = dwarf_child (begin_die, &die);
+ if (res != 0)
+ return; // die without children, bail out.
+
+ static string function_name = dwarf_diename (begin_die);
+ do
+ {
+ Dwarf_Attribute attr_mem;
+ Dwarf_Attribute *attr = dwarf_attr (&die, DW_AT_name, &attr_mem);
+ int tag = dwarf_tag(&die);
+ const char *name = dwarf_formstring (attr);
+ if (name == 0)
+ continue;
+ switch (tag)
+ {
+ case DW_TAG_label:
+ break;
+ case DW_TAG_subprogram:
+ if (!dwarf_hasattr(&die, DW_AT_declaration))
+ function_name = name;
+ else
+ continue;
+ default:
+ if (dwarf_haschildren (&die))
+ iterate_over_labels (&die, q, callback);
+ continue;
+ }
+
+ if (strcmp(function_name.c_str(), q->function.c_str()) == 0
+ || (name_has_wildcard(q->function)
+ && function_name_matches_pattern (function_name, q->function)))
+ {
+ }
+ else
+ continue;
+ if (strcmp(name, sym) == 0
+ || (name_has_wildcard(sym)
+ && function_name_matches_pattern (name, sym)))
+ {
+ const char *file = dwarf_decl_file (&die);
+ // Get the line number for this label
+ Dwarf_Attribute attr;
+ dwarf_attr (&die,DW_AT_decl_line, &attr);
+ Dwarf_Sword dline;
+ dwarf_formsdata (&attr, &dline);
+ Dwarf_Addr stmt_addr;
+ if (dwarf_lowpc (&die, &stmt_addr) != 0)
+ {
+ // There is no lowpc so figure out the address
+ // Get the real die for this cu
+ Dwarf_Die cudie;
+ dwarf_diecu (q->dw.cu, &cudie, NULL, NULL);
+ size_t nlines = 0;
+ // Get the line for this label
+ Dwarf_Line **aline;
+ dwarf_getsrc_file (module_dwarf, file, (int)dline, 0, &aline, &nlines);
+ // Get the address
+ for (size_t i = 0; i < nlines; i++)
+ {
+ dwarf_lineaddr (*aline, &stmt_addr);
+ if ((dwarf_haspc (&die, stmt_addr)))
+ break;
+ }
+ }
+
+ Dwarf_Die *scopes;
+ int nscopes = 0;
+ nscopes = dwarf_getscopes_die (&die, &scopes);
+ if (nscopes > 1)
+ {
+ callback(function_name.c_str(), file,
+ (int)dline, &scopes[1], stmt_addr, q);
+ if (sess.listing_mode)
+ q->results.back()->locations[0]->components.push_back
+ (new probe_point::component(TOK_LABEL, new literal_string (name)));
+ }
+ }
+ }
+ while (dwarf_siblingof (&die, &die) == 0);
+}
+
struct dwarf_builder: public derived_probe_builder
{
@@ -3084,6 +2904,7 @@ dwarf_query::dwarf_query(systemtap_session & sess,
has_return = has_null_param(params, TOK_RETURN);
has_maxactive = get_number_param(params, TOK_MAXACTIVE, maxactive_val);
has_absolute = has_null_param(params, TOK_ABSOLUTE);
+ has_mark = false;
if (has_function_str)
spec_type = parse_function_spec(function_str_val);
@@ -3521,9 +3342,17 @@ dwarf_query::blacklisted_p(const string& funcname,
if (! (goodfn && goodfile))
{
- if (sess.verbose>1)
- clog << " skipping - blacklisted";
- return true;
+ if (sess.guru_mode)
+ {
+ if (sess.verbose>1)
+ clog << " guru mode enabled - ignoring blacklist";
+ }
+ else
+ {
+ if (sess.verbose>1)
+ clog << " skipping - blacklisted";
+ return true;
+ }
}
// This probe point is not blacklisted.
@@ -3808,6 +3637,19 @@ query_func_info (Dwarf_Addr entrypc,
static void
+query_srcfile_label (const dwarf_line_t& line, void * arg)
+{
+ dwarf_query * q = static_cast<dwarf_query *>(arg);
+
+ Dwarf_Addr addr = line.addr();
+
+ for (func_info_map_t::iterator i = q->filtered_functions.begin();
+ i != q->filtered_functions.end(); ++i)
+ if (q->dw.die_has_pc (i->die, addr))
+ q->dw.iterate_over_labels (&i->die, q, query_statement);
+}
+
+static void
query_srcfile_line (const dwarf_line_t& line, void * arg)
{
dwarf_query * q = static_cast<dwarf_query *>(arg);
@@ -4020,9 +3862,9 @@ query_cu (Dwarf_Die * cudie, void * arg)
}
// Verify that a raw address matches the beginning of a
// statement. This is a somewhat lame check that the address
- // is at the start of an assembly instruction.
- // Avoid for now since this thwarts a probe on a statement in a macro
- if (0 && q->has_statement_num)
+ // is at the start of an assembly instruction. Mark probes are in the
+ // middle of a macro and thus not strictly at a statement beginning.
+ if (q->has_statement_num && ! q->has_mark)
{
Dwarf_Addr queryaddr = q->statement_num_val;
dwarf_line_t address_line(dwarf_getsrc_die(cudie, queryaddr));
@@ -4051,7 +3893,17 @@ query_cu (Dwarf_Die * cudie, void * arg)
if (! q->filtered_functions.empty())
q->dw.resolve_prologue_endings (q->filtered_functions);
- if ((q->has_statement_str || q->has_function_str)
+ if (q->has_label)
+ {
+ if (q->line[0] == 0) // No line number specified
+ q->dw.iterate_over_labels (q->dw.cu, q, query_statement);
+ else
+ for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin();
+ i != q->filtered_srcfiles.end(); ++i)
+ q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str,
+ q->line_type, query_srcfile_label, q);
+ }
+ else if ((q->has_statement_str || q->has_function_str)
&& (q->spec_type == function_file_and_line))
{
// If we have a pattern string with target *line*, we
@@ -4061,12 +3913,6 @@ query_cu (Dwarf_Die * cudie, void * arg)
q->dw.iterate_over_srcfile_lines (*i, q->line, q->has_statement_str,
q->line_type, query_srcfile_line, q);
}
- else if (q->has_label)
- {
- // If we have a pattern string with target *label*, we
- // have to look at labels in all the matched srcfiles.
- q->dw.iterate_over_cu_labels (q->label_val, q->dw.cu, q, query_statement);
- }
else
{
// Otherwise, simply probe all resolved functions.
@@ -4156,16 +4002,28 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
& main_filename,
& debug_filename);
const string& sess_machine = q->sess.architecture;
- string expect_machine;
+
+ string expect_machine; // to match sess.machine (i.e., kernel machine)
+ string expect_machine2;
switch (elf_machine)
{
- case EM_386: expect_machine = "i?86"; break; // accept e.g. i586
- case EM_X86_64: expect_machine = "x86_64"; break;
- // We don't support 32-bit ppc kernels, but we support 32-bit apps
- // running on ppc64 kernels.
- case EM_PPC: expect_machine = "ppc64"; break;
- case EM_PPC64: expect_machine = "ppc64"; break;
+ // x86 and ppc are bi-architecture; a 64-bit kernel
+ // can normally run either 32-bit or 64-bit *userspace*.
+ case EM_386:
+ expect_machine = "i?86";
+ if (! q->has_process) break; // 32-bit kernel/module
+ /* FALLSTHROUGH */
+ case EM_X86_64:
+ expect_machine2 = "x86_64";
+ break;
+ case EM_PPC:
+ expect_machine = "ppc";
+ if (! q->has_process) break; // 32-bit kernel/module
+ /* FALLSTHROUGH */
+ case EM_PPC64:
+ expect_machine2 = "ppc64";
+ break;
case EM_S390: expect_machine = "s390x"; break;
case EM_IA_64: expect_machine = "ia64"; break;
case EM_ARM: expect_machine = "armv*"; break;
@@ -4176,10 +4034,12 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
if (! debug_filename) debug_filename = main_filename;
if (! debug_filename) debug_filename = name;
- if (fnmatch (expect_machine.c_str(), sess_machine.c_str(), 0) != 0)
+ if (fnmatch (expect_machine.c_str(), sess_machine.c_str(), 0) != 0 &&
+ fnmatch (expect_machine2.c_str(), sess_machine.c_str(), 0) != 0)
{
stringstream msg;
- msg << "ELF machine " << expect_machine << " (code " << elf_machine
+ msg << "ELF machine " << expect_machine << "|" << expect_machine2
+ << " (code " << elf_machine
<< ") mismatch with target " << sess_machine
<< " in '" << debug_filename << "'";
throw semantic_error(msg.str ());
@@ -4191,7 +4051,7 @@ validate_module_elf (Dwfl_Module *mod, const char *name, base_query *q)
<< "-0x" << q->dw.module_end
<< ", bias 0x" << q->dw.module_bias << "]" << dec
<< " file " << debug_filename
- << " ELF machine " << expect_machine
+ << " ELF machine " << expect_machine << "|" << expect_machine2
<< " (code " << elf_machine << ")"
<< "\n";
}
@@ -4316,15 +4176,6 @@ dwflpp::query_modules(base_query *q)
iterate_over_modules(&query_module, q);
}
-struct var_expanding_visitor: public update_visitor
-{
- static unsigned tick;
- stack<functioncall**> target_symbol_setter_functioncalls;
-
- var_expanding_visitor() {}
- void visit_assignment (assignment* e);
-};
-
struct dwarf_var_expanding_visitor: public var_expanding_visitor
{
@@ -4343,7 +4194,6 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor
};
-
unsigned var_expanding_visitor::tick = 0;
void
@@ -4823,7 +4673,7 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
{
ec->code = q.dw.literal_stmt_for_return (scope_die,
addr,
- e->components,
+ e,
lvalue,
fdecl->type);
}
@@ -4832,7 +4682,7 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
ec->code = q.dw.literal_stmt_for_local (scope_die,
addr,
e->base_name.substr(1),
- e->components,
+ e,
lvalue,
fdecl->type);
}
@@ -4864,8 +4714,9 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
literal_number* ln_zero = new literal_number (0);
ln_zero->tok = e->tok;
provide (ln_zero);
- q.sess.print_warning ("Bad variable being substituted with literal 0",
- e->tok);
+ if (!q.sess.suppress_warnings)
+ q.sess.print_warning ("Bad $context variable being substituted with literal 0",
+ e->tok);
}
delete fdecl;
delete ec;
@@ -4924,13 +4775,13 @@ dwarf_var_expanding_visitor::visit_cast_op (cast_op *e)
struct dwarf_cast_query : public base_query
{
- const cast_op& e;
+ cast_op& e;
const bool lvalue;
exp_type& pe_type;
string& code;
- dwarf_cast_query(dwflpp& dw, const string& module, const cast_op& e,
+ dwarf_cast_query(dwflpp& dw, const string& module, cast_op& e,
bool lvalue, exp_type& pe_type, string& code):
base_query(dw, module), e(e), lvalue(lvalue),
pe_type(pe_type), code(code) {}
@@ -4965,14 +4816,18 @@ dwarf_cast_query::handle_query_cu(Dwarf_Die * cudie)
{
try
{
- code = dw.literal_stmt_for_pointer (type_die, e.components,
+ code = dw.literal_stmt_for_pointer (type_die, &e,
lvalue, pe_type);
}
- catch (const semantic_error& e)
+ catch (const semantic_error& er)
{
- // XXX might be better to save the error
- // and try again in another CU
- sess.print_error (e);
+ // XXX might be better to try again in another CU
+ // NB: we can have multiple errors, since a @cast
+ // may be expanded in several different contexts:
+ // function ("*") { @cast(...) }
+ semantic_error* new_er = new semantic_error(er);
+ new_er->chain = e.saved_conversion_error;
+ e.saved_conversion_error = new_er;
}
return DWARF_CB_ABORT;
}
@@ -4997,9 +4852,55 @@ struct dwarf_cast_expanding_visitor: public var_expanding_visitor
dwarf_cast_expanding_visitor(systemtap_session& s, dwarf_builder& db):
s(s), db(db) {}
void visit_cast_op (cast_op* e);
+ void filter_special_modules(string& module);
};
+void dwarf_cast_expanding_visitor::filter_special_modules(string& module)
+{
+ // look for "<path/to/header>" or "kernel<path/to/header>"
+ // for those cases, build a module including that header
+ if (module[module.size() - 1] == '>' &&
+ (module[0] == '<' || module.compare(0, 7, "kernel<") == 0))
+ {
+ string cached_module;
+ if (s.use_cache)
+ {
+ // see if the cached module exists
+ find_typequery_hash(s, module, cached_module);
+ if (!cached_module.empty())
+ {
+ int fd = open(cached_module.c_str(), O_RDONLY);
+ if (fd != -1)
+ {
+ if (s.verbose > 2)
+ clog << "Pass 2: using cached " << cached_module << endl;
+ module = cached_module;
+ close(fd);
+ return;
+ }
+ }
+ }
+
+ // no cached module, time to make it
+ if (make_typequery(s, module) == 0)
+ {
+ if (s.use_cache)
+ {
+ // try to save typequery in the cache
+ if (s.verbose > 2)
+ clog << "Copying " << module
+ << " to " << cached_module << endl;
+ if (copy_file(module.c_str(),
+ cached_module.c_str()) != 0)
+ cerr << "Copy failed (\"" << module << "\" to \""
+ << cached_module << "\"): " << strerror(errno) << endl;
+ }
+ }
+ }
+}
+
+
void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
{
bool lvalue = is_active_lvalue(e);
@@ -5011,13 +4912,14 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
string code;
exp_type type = pe_long;
- size_t mod_end = -1;
- do
+
+ // split the module string by ':' for alternatives
+ vector<string> modules;
+ tokenize(e->module, modules, ":");
+ for (unsigned i = 0; code.empty() && i < modules.size(); ++i)
{
- // split the module string by ':' for alternatives
- size_t mod_begin = mod_end + 1;
- mod_end = e->module.find(':', mod_begin);
- string module = e->module.substr(mod_begin, mod_end - mod_begin);
+ string& module = modules[i];
+ filter_special_modules(module);
// NB: This uses '/' to distinguish between kernel modules and userspace,
// which means that userspace modules won't get any PATH searching.
@@ -5027,10 +4929,21 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
// kernel or kernel module target
if (! db.kern_dw)
{
- db.kern_dw = new dwflpp(s);
- db.kern_dw->setup_kernel(true);
+ dw = new dwflpp(s);
+ try
+ {
+ dw->setup_kernel(true);
+ }
+ catch (const semantic_error& er)
+ {
+ /* ignore and go to the next module */
+ delete dw;
+ continue;
+ }
+ db.kern_dw = dw;
}
- dw = db.kern_dw;
+ else
+ dw = db.kern_dw;
}
else
{
@@ -5041,7 +4954,16 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
if (db.user_dw.find(module) == db.user_dw.end())
{
dw = new dwflpp(s);
- dw->setup_user(module);
+ try
+ {
+ dw->setup_user(module);
+ }
+ catch (const semantic_error& er)
+ {
+ /* ignore and go to the next module */
+ delete dw;
+ continue;
+ }
db.user_dw[module] = dw;
}
else
@@ -5051,20 +4973,12 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
dwarf_cast_query q (*dw, module, *e, lvalue, type, code);
dw->query_modules(&q);
}
- while (code.empty() && mod_end != string::npos);
if (code.empty())
{
- // We generate an error message, and pass the unresolved
- // cast_op to the next pass. We hope that this value ends
- // up not being referenced after all, so it can be optimized out
- // quietly.
- semantic_error* er = new semantic_error ("type definition not found", e->tok);
- // NB: we can have multiple errors, since a @cast
- // may be expanded in several different contexts:
- // function ("*") { @cast(...) }
- er->chain = e->saved_conversion_error;
- e->saved_conversion_error = er;
+ // We pass the unresolved cast_op to the next pass, and hope
+ // that this value ends up not being referenced after all, so
+ // it can be optimized out quietly.
provide (e);
return;
}
@@ -5360,7 +5274,6 @@ dwarf_derived_probe_group::enroll (dwarf_derived_probe* p)
// sequentially.
}
-
void
dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
{
@@ -5442,6 +5355,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
CALCIT(module);
CALCIT(section);
CALCIT(pp);
+#undef CALCIT
s.op->newline() << "const unsigned long address;";
s.op->newline() << "void (* const ph) (struct context*);";
@@ -5703,6 +5617,9 @@ dwarf_builder::build(systemtap_session & sess,
dw = user_dw[module_name];
}
+ if (sess.verbose > 3)
+ clog << "dwarf_builder::build for " << module_name << endl;
+
if (((probe_point::component*)(location->components[1]))->functor == TOK_MARK)
{
enum probe_types
@@ -5714,21 +5631,23 @@ dwarf_builder::build(systemtap_session & sess,
int probe_type = dwarf_no_probes;
string probe_name = (char*) location->components[1]->arg->tok->content.c_str();
+ if (sess.verbose > 3)
+ clog << "TOK_MARK: " << probe_name << endl;
+
__uint64_t probe_arg = 0;
Dwarf_Addr bias;
- Elf* elf = dwfl_module_getelf (dw->module, &bias);
+ Elf* elf = (dwarf_getelf (dwfl_module_getdwarf (dw->module, &bias))
+ ?: dwfl_module_getelf (dw->module, &bias));
size_t shstrndx;
Elf_Scn *probe_scn = NULL;
- bool probe_found = false;
- bool dynamic = (dwfl_module_relocations (dw->module) == 1);
dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
+ GElf_Shdr shdr_mem;
GElf_Shdr *shdr = NULL;
// Is there a .probes section?
while ((probe_scn = elf_nextscn (elf, probe_scn)))
{
- GElf_Shdr shdr_mem;
shdr = gelf_getshdr (probe_scn, &shdr_mem);
assert (shdr != NULL);
@@ -5738,21 +5657,48 @@ dwarf_builder::build(systemtap_session & sess,
break;
}
}
- if (dynamic || sess.listing_mode)
- probe_type = dwarf_no_probes;
+ // Older versions put .probes section in the debuginfo dwarf file,
+ // so check if it actually exists, if not take the main elf file
+ if (probe_type == probes_and_dwarf && shdr->sh_type == SHT_NOBITS)
+ {
+ elf = dwfl_module_getelf (dw->module, &bias);
+ dwfl_assert ("getshstrndx", elf_getshstrndx (elf, &shstrndx));
+ probe_scn = NULL;
+ while ((probe_scn = elf_nextscn (elf, probe_scn)))
+ {
+ shdr = gelf_getshdr (probe_scn, &shdr_mem);
+ if (strcmp (elf_strptr (elf, shstrndx, shdr->sh_name),
+ ".probes") == 0)
+ break;
+ }
+ }
+
+ // We got our .probes section, extract data.
if (probe_type == probes_and_dwarf)
{
+ if (sess.verbose > 3)
+ clog << "probe_type == probes_and_dwarf, use statement addr" << endl;
+
Elf_Data *pdata = elf_getdata_rawchunk (elf, shdr->sh_offset, shdr->sh_size, ELF_T_BYTE);
assert (pdata != NULL);
size_t probe_scn_offset = 0;
size_t probe_scn_addr = shdr->sh_addr;
+ if (sess.verbose > 4)
+ clog << "got .probes elf scn_addr@0x" << probe_scn_addr << dec
+ << ", size: " << pdata->d_size << endl;
while (probe_scn_offset < pdata->d_size)
{
const int stap_sentinel = 0x31425250;
probe_type = *((int*)((char*)pdata->d_buf + probe_scn_offset));
if (probe_type != stap_sentinel)
{
+ // Unless this is a mangled .probes section, this happens
+ // because the name of the probe comes first, followed by
+ // the sentinel.
+ if (sess.verbose > 5)
+ clog << "got unknown probe_type: 0x" << hex << probe_type
+ << dec << endl;
probe_scn_offset += sizeof(int);
continue;
}
@@ -5760,30 +5706,53 @@ dwarf_builder::build(systemtap_session & sess,
if (probe_scn_offset % (sizeof(__uint64_t)))
probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t));
- probe_name = ((char*)((long)(pdata->d_buf) + (long)(*((int*)((long)pdata->d_buf + probe_scn_offset)) - probe_scn_addr)));
+ probe_name = ((char*)((long)(pdata->d_buf) + (long)(*((long*)((char*)pdata->d_buf + probe_scn_offset)) - probe_scn_addr)));
probe_scn_offset += sizeof(void*);
if (probe_scn_offset % (sizeof(__uint64_t)))
probe_scn_offset += sizeof(__uint64_t) - (probe_scn_offset % sizeof(__uint64_t));
probe_arg = *((__uint64_t*)((char*)pdata->d_buf + probe_scn_offset));
+ if (sess.verbose > 4)
+ clog << "saw .probes " << probe_name
+ << "@0x" << hex << probe_arg << dec << endl;
+
if (probe_scn_offset % (sizeof(__uint64_t)*2))
probe_scn_offset = (probe_scn_offset + sizeof(__uint64_t)*2) - (probe_scn_offset % (sizeof(__uint64_t)*2));
- if (strcmp (location->components[1]->arg->tok->content.c_str(), probe_name.c_str()) == 0)
- probe_found = true;
+ if ((strcmp (location->components[1]->arg->tok->content.c_str(),
+ probe_name.c_str()) == 0)
+ || (dw->name_has_wildcard (location->components[1]->arg->tok->content.c_str())
+ && dw->function_name_matches_pattern
+ (probe_name.c_str(),
+ location->components[1]->arg->tok->content.c_str())))
+ {
+ if (sess.verbose > 3)
+ clog << "found probe_name" << probe_name << " at 0x"
+ << hex << probe_arg << dec << endl;
+ }
else
continue;
const token* sv_tok = location->components[1]->arg->tok;
location->components[1]->functor = TOK_STATEMENT;
- location->components[1]->arg = new literal_number((int)probe_arg);
+ location->components[1]->arg = new literal_number((long)probe_arg);
location->components[1]->arg->tok = sv_tok;
((literal_map_t&)parameters)[TOK_STATEMENT] = location->components[1]->arg;
+
+ if (sess.verbose > 3)
+ clog << "probe_type == probes_and_dwarf, use statement addr: 0x"
+ << hex << probe_arg << dec << endl;
+
dwarf_query q(sess, base, location, *dw, parameters, finished_results);
+ q.has_mark = true;
dw->query_modules(&q);
+ if (sess.listing_mode)
+ {
+ finished_results.back()->locations[0]->components[1]->functor = TOK_MARK;
+ finished_results.back()->locations[0]->components[1]->arg = new literal_string (probe_name.c_str());
+ }
}
- if (probe_found)
- return;
+ return;
}
- if (probe_type == dwarf_no_probes || ! probe_found)
+ else if (probe_type == dwarf_no_probes)
{
location->components[1]->functor = TOK_FUNCTION;
location->components[1]->arg = new literal_string("*");
@@ -5792,8 +5761,15 @@ dwarf_builder::build(systemtap_session & sess,
location->components[2]->arg = new literal_string("_stapprobe1_" + probe_name);
((literal_map_t&)parameters).erase(TOK_MARK);
((literal_map_t&)parameters).insert(pair<string,literal*>(TOK_LABEL, location->components[2]->arg));
+
+ if (sess.verbose > 3)
+ clog << "probe_type == dwarf_no_probes, use label name: "
+ << "_stapprobe1_" << probe_name << endl;
}
+ else if (sess.verbose > 3)
+ clog << "probe_type == probes_no_dwarf" << endl;
+
dw->module = 0;
}
@@ -6179,1086 +6155,6 @@ module_info::~module_info()
delete sym_table;
}
-
-
-// ------------------------------------------------------------------------
-// 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();
-}
-
-
-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->newline(1) << "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();";
-}
-
-// ------------------------------------------------------------------------
-// itrace user-space probes
-// ------------------------------------------------------------------------
-
-
-struct itrace_derived_probe: public derived_probe
-{
- bool has_path;
- string path;
- int64_t pid;
- int single_step;
-
- itrace_derived_probe (systemtap_session &s, probe* p, probe_point* l,
- bool hp, string &pn, int64_t pd, int ss
- );
- void join_group (systemtap_session& s);
-};
-
-
-struct itrace_derived_probe_group: public generic_dpg<itrace_derived_probe>
-{
-private:
- map<string, vector<itrace_derived_probe*> > probes_by_path;
- typedef map<string, vector<itrace_derived_probe*> >::iterator p_b_path_iterator;
- map<int64_t, vector<itrace_derived_probe*> > probes_by_pid;
- typedef map<int64_t, vector<itrace_derived_probe*> >::iterator p_b_pid_iterator;
- unsigned num_probes;
-
- void emit_probe_decl (systemtap_session& s, itrace_derived_probe *p);
-
-public:
- itrace_derived_probe_group(): num_probes(0) { }
-
- void enroll (itrace_derived_probe* probe);
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-itrace_derived_probe::itrace_derived_probe (systemtap_session &s,
- probe* p, probe_point* l,
- bool hp, string &pn, int64_t pd,
- int ss
- ):
- derived_probe(p, l), has_path(hp), path(pn), pid(pd), single_step(ss)
-{
-}
-
-
-void
-itrace_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.itrace_derived_probes)
- s.itrace_derived_probes = new itrace_derived_probe_group ();
-
- s.itrace_derived_probes->enroll (this);
-
- task_finder_derived_probe_group::create_session_group (s);
-}
-
-struct itrace_builder: public derived_probe_builder
-{
- itrace_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- std::map<std::string, literal *> const & parameters,
- vector<derived_probe *> & finished_results)
- {
- string path;
- int64_t pid = 0;
- int single_step;
-
- bool has_path = get_param (parameters, TOK_PROCESS, path);
- bool has_pid = get_param (parameters, TOK_PROCESS, pid);
- // XXX: PR 6445 needs !has_path && !has_pid support
- assert (has_path || has_pid);
-
- single_step = 1;
-
- // If we have a path, we need to validate it.
- if (has_path)
- path = find_executable (path);
-
- finished_results.push_back(new itrace_derived_probe(sess, base, location,
- has_path, path, pid,
- single_step
- ));
- }
-};
-
-
-void
-itrace_derived_probe_group::enroll (itrace_derived_probe* p)
-{
- if (p->has_path)
- probes_by_path[p->path].push_back(p);
- else
- probes_by_pid[p->pid].push_back(p);
- num_probes++;
-
- // XXX: multiple exec probes (for instance) for the same path (or
- // pid) should all share a itrace report function, and have their
- // handlers executed sequentially.
-}
-
-
-void
-itrace_derived_probe_group::emit_probe_decl (systemtap_session& s,
- itrace_derived_probe *p)
-{
- s.op->newline() << "{";
- s.op->line() << " .tgt={";
-
- if (p->has_path)
- {
- s.op->line() << " .pathname=\"" << p->path << "\",";
- s.op->line() << " .pid=0,";
- }
- else
- {
- s.op->line() << " .pathname=NULL,";
- s.op->line() << " .pid=" << p->pid << ",";
- }
-
- s.op->line() << " .callback=&_stp_itrace_probe_cb,";
- s.op->line() << " },";
- s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
- s.op->line() << " .single_step=" << p->single_step << ",";
- s.op->line() << " .ph=&" << p->name << ",";
-
- s.op->line() << " },";
-}
-
-
-void
-itrace_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty())
- return;
-
- s.op->newline();
- s.op->newline() << "/* ---- itrace probes ---- */";
- s.op->newline() << "#include \"task_finder.c\"";
- s.op->newline() << "struct stap_itrace_probe {";
- s.op->indent(1);
- s.op->newline() << "struct stap_task_finder_target tgt;";
- s.op->newline() << "const char *pp;";
- s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline() << "int single_step;";
- s.op->newline(-1) << "};";
- s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data);";
- s.op->newline() << "#include \"itrace.c\"";
-
- // output routine to call itrace probe
- s.op->newline() << "static void enter_itrace_probe(struct stap_itrace_probe *p, struct pt_regs *regs, void *data) {";
- s.op->indent(1);
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "p->pp");
- s.op->newline() << "c->regs = regs;";
- s.op->newline() << "c->data = data;";
-
- // call probe function
- s.op->newline() << "(*p->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
-
- s.op->newline() << "return;";
- s.op->newline(-1) << "}";
-
- // Output task finder callback routine that gets called for all
- // itrace probe types.
- s.op->newline() << "static int _stp_itrace_probe_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
- s.op->indent(1);
- s.op->newline() << "int rc = 0;";
- s.op->newline() << "struct stap_itrace_probe *p = container_of(tgt, struct stap_itrace_probe, tgt);";
-
- s.op->newline() << "if (register_p) ";
- s.op->indent(1);
-
- s.op->newline() << "rc = usr_itrace_init(p->single_step, tsk->pid, p);";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "remove_usr_itrace_info(find_itrace_info(p->tgt.pid));";
- s.op->newline(-1) << "return rc;";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static struct stap_itrace_probe stap_itrace_probes[] = {";
- s.op->indent(1);
-
- // Set up 'process(PATH)' probes
- if (! probes_by_path.empty())
- {
- for (p_b_path_iterator it = probes_by_path.begin();
- it != probes_by_path.end(); it++)
- {
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- itrace_derived_probe *p = it->second[i];
- emit_probe_decl(s, p);
- }
- }
- }
-
- // Set up 'process(PID)' probes
- if (! probes_by_pid.empty())
- {
- for (p_b_pid_iterator it = probes_by_pid.begin();
- it != probes_by_pid.end(); it++)
- {
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- itrace_derived_probe *p = it->second[i];
- emit_probe_decl(s, p);
- }
- }
- }
- s.op->newline(-1) << "};";
-}
-
-
-void
-itrace_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty())
- return;
-
- s.op->newline();
- s.op->newline() << "/* ---- itrace probes ---- */";
-
- s.op->newline() << "for (i=0; i<" << num_probes << "; i++) {";
- s.op->indent(1);
- s.op->newline() << "struct stap_itrace_probe *p = &stap_itrace_probes[i];";
- s.op->newline() << "rc = stap_register_task_finder_target(&p->tgt);";
- s.op->newline(-1) << "}";
-}
-
-
-void
-itrace_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty()) return;
- s.op->newline();
- s.op->newline() << "/* ---- itrace probes ---- */";
- s.op->newline() << "cleanup_usr_itrace();";
-}
-
-// ------------------------------------------------------------------------
-// utrace user-space probes
-// ------------------------------------------------------------------------
-
-static string TOK_THREAD("thread");
-static string TOK_SYSCALL("syscall");
-
-// Note that these flags don't match up exactly with UTRACE_EVENT
-// flags (and that's OK).
-enum utrace_derived_probe_flags {
- UDPF_NONE,
- UDPF_BEGIN, // process begin
- UDPF_END, // process end
- UDPF_THREAD_BEGIN, // thread begin
- UDPF_THREAD_END, // thread end
- UDPF_SYSCALL, // syscall entry
- UDPF_SYSCALL_RETURN, // syscall exit
- UDPF_NFLAGS
-};
-
-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);
- void emit_vm_callback_probe_decl (systemtap_session& s, bool has_path,
- string path, int64_t pid,
- string vm_callback);
-
-public:
- utrace_derived_probe_group(): num_probes(0), flags_seen() { }
-
- 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_visitor: public var_expanding_visitor
-{
- utrace_var_expanding_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_arg (target_symbol* e);
- void visit_target_symbol_context (target_symbol* e);
- 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, new probe_point (*l) /* .components soon rewritten */ ),
- has_path(hp), path(pn), pid(pd), flags(f),
- target_symbol_seen(false)
-{
- // Expand local variables in the probe body
- utrace_var_expanding_visitor v (s, name, flags);
- this->body = v.require (this->body);
- target_symbol_seen = v.target_symbol_seen;
-
- // Reset the sole element of the "locations" vector as a
- // "reverse-engineered" form of the incoming (q.base_loc) probe
- // point. This allows a user to see what program etc.
- // number any particular match of the wildcards.
-
- vector<probe_point::component*> comps;
- if (hp)
- comps.push_back (new probe_point::component(TOK_PROCESS, new literal_string(path)));
- else if (pid != 0)
- comps.push_back (new probe_point::component(TOK_PROCESS, new literal_number(pid)));
- else
- comps.push_back (new probe_point::component(TOK_PROCESS));
-
- switch (flags)
- {
- case UDPF_THREAD_BEGIN:
- comps.push_back (new probe_point::component(TOK_THREAD));
- comps.push_back (new probe_point::component(TOK_BEGIN));
- break;
- case UDPF_THREAD_END:
- comps.push_back (new probe_point::component(TOK_THREAD));
- comps.push_back (new probe_point::component(TOK_END));
- break;
- case UDPF_SYSCALL:
- comps.push_back (new probe_point::component(TOK_SYSCALL));
- break;
- case UDPF_SYSCALL_RETURN:
- comps.push_back (new probe_point::component(TOK_SYSCALL));
- comps.push_back (new probe_point::component(TOK_RETURN));
- break;
- case UDPF_BEGIN:
- comps.push_back (new probe_point::component(TOK_BEGIN));
- break;
- case UDPF_END:
- comps.push_back (new probe_point::component(TOK_END));
- break;
- default:
- assert (0);
- }
-
- // Overwrite it.
- this->sole_location()->components = comps;
-}
-
-
-void
-utrace_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.utrace_derived_probes)
- {
- s.utrace_derived_probes = new utrace_derived_probe_group ();
- }
- s.utrace_derived_probes->enroll (this);
-
- task_finder_derived_probe_group::create_session_group (s);
-}
-
-
-void
-utrace_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
-{
- string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
- int argnum = lex_cast<int>(argnum_s);
-
- if (flags != UDPF_SYSCALL)
- throw semantic_error ("only \"process(PATH_OR_PID).syscall\" support $argN.", 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 '$argN' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("utrace target variable '$argN' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of utrace target variable '$argN'",
- e->tok);
- break;
- }
- }
-
- // FIXME: max argnument number should not be hardcoded.
- if (argnum < 1 || argnum > 6)
- throw semantic_error ("invalid syscall argument number (1-6)", e->tok);
-
- bool lvalue = is_active_lvalue(e);
- if (lvalue)
- throw semantic_error("utrace '$argN' variable is read-only", e->tok);
-
- // Remember that we've seen a target variable.
- target_symbol_seen = true;
-
- // We're going to substitute a synthesized '_utrace_syscall_arg'
- // function call for the '$argN' reference.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = "_utrace_syscall_arg";
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-
- literal_number *num = new literal_number(argnum - 1);
- num->tok = e->tok;
- n->args.push_back(num);
-
- provide (n);
-}
-
-void
-utrace_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
-{
- string sname = e->base_name;
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("utrace target variable '" + sname + "' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("utrace target variable '" + sname + "' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of utrace target variable '" + sname + "'",
- e->tok);
- break;
- }
- }
-
- bool lvalue = is_active_lvalue(e);
- if (lvalue)
- throw semantic_error("utrace '" + sname + "' variable is read-only", e->tok);
-
- string fname;
- if (sname == "$return")
- {
- if (flags != UDPF_SYSCALL_RETURN)
- throw semantic_error ("only \"process(PATH_OR_PID).syscall.return\" support $return.", e->tok);
- fname = "_utrace_syscall_return";
- }
- else
- fname = "_utrace_syscall_nr";
-
- // Remember that we've seen a target variable.
- target_symbol_seen = true;
-
- // We're going to substitute a synthesized '_utrace_syscall_nr'
- // function call for the '$syscall' reference.
- 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 (n);
-}
-
-void
-utrace_var_expanding_visitor::visit_target_symbol (target_symbol* e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- if (flags != UDPF_SYSCALL && flags != UDPF_SYSCALL_RETURN)
- throw semantic_error ("only \"process(PATH_OR_PID).syscall\" and \"process(PATH_OR_PID).syscall.return\" probes support target symbols",
- e->tok);
-
- if (e->base_name.substr(0,4) == "$arg")
- visit_target_symbol_arg(e);
- else if (e->base_name == "$syscall" || e->base_name == "$return")
- visit_target_symbol_context(e);
- else
- throw semantic_error ("invalid target symbol for utrace probe, $syscall, $return or $argN expected",
- e->tok);
-}
-
-
-struct utrace_builder: public derived_probe_builder
-{
- utrace_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t 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;
-
- if (has_null_param (parameters, TOK_THREAD))
- {
- if (has_null_param (parameters, TOK_BEGIN))
- flags = UDPF_THREAD_BEGIN;
- else if (has_null_param (parameters, TOK_END))
- flags = UDPF_THREAD_END;
- }
- else if (has_null_param (parameters, TOK_SYSCALL))
- {
- if (has_null_param (parameters, TOK_RETURN))
- flags = UDPF_SYSCALL_RETURN;
- else
- flags = UDPF_SYSCALL;
- }
- else if (has_null_param (parameters, TOK_BEGIN))
- flags = UDPF_BEGIN;
- else if (has_null_param (parameters, TOK_END))
- flags = UDPF_END;
-
- // If we didn't get a path or pid, this means to probe everything.
- // Convert this to a pid-based probe.
- if (! has_path && ! has_pid)
- {
- has_path = false;
- path.clear();
- has_pid = true;
- pid = 0;
- }
- else if (has_path)
- {
- path = find_executable (path);
- sess.unwindsym_modules.insert (path);
- }
- else if (has_pid)
- {
- // We can't probe 'init' (pid 1). XXX: where does this limitation come from?
- if (pid < 2)
- throw semantic_error ("process pid must be greater than 1",
- location->tok);
-
- // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere?
- }
-
- 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() << " .vm_callback=NULL,";
- s.op->line() << " },";
- s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
- s.op->line() << " .ph=&" << p->name << ",";
-
- // Handle flags
- switch (p->flags)
- {
- // Notice that we'll just call the probe directly when we get
- // notified, since the task_finder layer stops the thread for us.
- case UDPF_BEGIN: // process begin
- s.op->line() << " .flags=(UDPF_BEGIN),";
- break;
- case UDPF_THREAD_BEGIN: // thread begin
- s.op->line() << " .flags=(UDPF_THREAD_BEGIN),";
- break;
-
- // Notice we're not setting up a .ops/.report_death handler for
- // either UDPF_END or UDPF_THREAD_END. Instead, we'll just call
- // the probe directly when we get notified.
- case UDPF_END: // process end
- s.op->line() << " .flags=(UDPF_END),";
- break;
- case UDPF_THREAD_END: // thread end
- s.op->line() << " .flags=(UDPF_THREAD_END),";
- break;
-
- // For UDPF_SYSCALL/UDPF_SYSCALL_RETURN probes, the .report_death
- // handler isn't strictly necessary. However, it helps to keep
- // our attaches/detaches symmetrical. Since the task_finder layer
- // stops the thread, that works around bug 6841.
- case UDPF_SYSCALL:
- s.op->line() << " .flags=(UDPF_SYSCALL),";
- s.op->line() << " .ops={ .report_syscall_entry=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_ENTRY)|UTRACE_EVENT(DEATH)),";
- break;
- case UDPF_SYSCALL_RETURN:
- s.op->line() << " .flags=(UDPF_SYSCALL_RETURN),";
- s.op->line() << " .ops={ .report_syscall_exit=stap_utrace_probe_syscall, .report_death=stap_utrace_task_finder_report_death },";
- s.op->line() << " .events=(UTRACE_EVENT(SYSCALL_EXIT)|UTRACE_EVENT(DEATH)),";
- break;
-
- case UDPF_NONE:
- s.op->line() << " .flags=(UDPF_NONE),";
- s.op->line() << " .ops={ },";
- s.op->line() << " .events=0,";
- break;
- default:
- throw semantic_error ("bad utrace probe flag");
- break;
- }
- s.op->line() << " .engine_attached=0,";
- s.op->line() << " },";
-}
-
-
-void
-utrace_derived_probe_group::emit_vm_callback_probe_decl (systemtap_session& s,
- bool has_path,
- string path,
- int64_t pid,
- string vm_callback)
-{
- s.op->newline() << "{";
- s.op->line() << " .tgt={";
-
- if (has_path)
- {
- s.op->line() << " .pathname=\"" << path << "\",";
- s.op->line() << " .pid=0,";
- }
- else
- {
- s.op->line() << " .pathname=NULL,";
- s.op->line() << " .pid=" << pid << ",";
- }
-
- s.op->line() << " .callback=NULL,";
- s.op->line() << " .vm_callback=&" << vm_callback << ",";
- s.op->line() << " },";
- s.op->line() << " .pp=\"internal\",";
- s.op->line() << " .ph=NULL,";
- s.op->line() << " .flags=(UDPF_NONE),";
- s.op->line() << " .ops={ NULL },";
- s.op->line() << " .events=0,";
- s.op->line() << " .engine_attached=0,";
- s.op->line() << " },";
-}
-
-
-void
-utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes_by_path.empty() && probes_by_pid.empty())
- return;
-
- s.op->newline();
- s.op->newline() << "/* ---- utrace probes ---- */";
- s.op->newline() << "#include \"task_finder.c\"";
-
- s.op->newline() << "enum utrace_derived_probe_flags {";
- s.op->indent(1);
- s.op->newline() << "UDPF_NONE,";
- s.op->newline() << "UDPF_BEGIN,";
- s.op->newline() << "UDPF_END,";
- s.op->newline() << "UDPF_THREAD_BEGIN,";
- s.op->newline() << "UDPF_THREAD_END,";
- s.op->newline() << "UDPF_SYSCALL,";
- s.op->newline() << "UDPF_SYSCALL_RETURN,";
- s.op->newline() << "UDPF_NFLAGS";
- s.op->newline(-1) << "};";
-
- s.op->newline() << "struct stap_utrace_probe {";
- s.op->indent(1);
- s.op->newline() << "struct stap_task_finder_target tgt;";
- s.op->newline() << "const char *pp;";
- s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline() << "enum utrace_derived_probe_flags flags;";
- s.op->newline() << "struct utrace_engine_ops ops;";
- s.op->newline() << "unsigned long events;";
- s.op->newline() << "int engine_attached;";
- s.op->newline(-1) << "};";
-
-
- // Output handler function for UDPF_BEGIN, UDPF_THREAD_BEGIN,
- // UDPF_END, and UDPF_THREAD_END
- if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN]
- || flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
- {
- s.op->newline() << "static void stap_utrace_probe_handler(struct task_struct *tsk, struct stap_utrace_probe *p) {";
- s.op->indent(1);
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "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] || flags_seen[UDPF_SYSCALL_RETURN])
- {
- s.op->newline() << "#ifdef UTRACE_ORIG_VERSION";
- s.op->newline() << "static u32 stap_utrace_probe_syscall(struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
- s.op->newline() << "#else";
- s.op->newline() << "static u32 stap_utrace_probe_syscall(enum utrace_resume_action action, struct utrace_attached_engine *engine, struct task_struct *tsk, struct pt_regs *regs) {";
- s.op->newline() << "#endif";
-
- 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", "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() << "if ((atomic_read (&session_state) != STAP_SESSION_STARTING) && (atomic_read (&session_state) != STAP_SESSION_RUNNING)) {";
- s.op->indent(1);
- s.op->newline() << "debug_task_finder_detach();";
- s.op->newline() << "return UTRACE_DETACH;";
- s.op->newline(-1) << "}";
- s.op->newline() << "return UTRACE_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 stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {";
- 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 receiving a UTRACE_EVENT(CLONE) event, we can't call the
- // begin/thread.begin probe directly. So, we'll just attach an
- // engine that waits for the thread to quiesce. When the thread
- // quiesces, then call the probe.
- if (flags_seen[UDPF_BEGIN])
- {
- s.op->newline() << "case UDPF_BEGIN:";
- s.op->indent(1);
- s.op->newline() << "if (process_p) {";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
- if (flags_seen[UDPF_THREAD_BEGIN])
- {
- s.op->newline() << "case UDPF_THREAD_BEGIN:";
- s.op->indent(1);
- s.op->newline() << "if (! process_p) {";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- // For end/thread_end probes, do nothing at registration time.
- // We'll handle these in the 'register_p == 0' case.
- if (flags_seen[UDPF_END] || flags_seen[UDPF_THREAD_END])
- {
- s.op->newline() << "case UDPF_END:";
- s.op->newline() << "case UDPF_THREAD_END:";
- s.op->indent(1);
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- // Attach an engine for SYSCALL_ENTRY and SYSCALL_EXIT events.
- if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
- {
- s.op->newline() << "case UDPF_SYSCALL:";
- s.op->newline() << "case UDPF_SYSCALL_RETURN:";
- s.op->indent(1);
- s.op->newline() << "rc = stap_utrace_attach(tsk, &p->ops, p, p->events);";
- s.op->newline() << "if (rc == 0) {";
- s.op->indent(1);
- s.op->newline() << "p->engine_attached = 1;";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- s.op->newline() << "default:";
- s.op->indent(1);
- s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
- s.op->newline() << "break;";
- s.op->indent(-1);
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
-
- // Since this engine could be attached to multiple threads, don't
- // call stap_utrace_detach_ops() here, only call
- // stap_utrace_detach() as necessary.
- s.op->newline() << "else {";
- s.op->indent(1);
- s.op->newline() << "switch (p->flags) {";
- s.op->indent(1);
- // For death probes, go ahead and call the probe directly.
- if (flags_seen[UDPF_END])
- {
- s.op->newline() << "case UDPF_END:";
- s.op->indent(1);
- s.op->newline() << "if (process_p) {";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
- if (flags_seen[UDPF_THREAD_END])
- {
- s.op->newline() << "case UDPF_THREAD_END:";
- s.op->indent(1);
- s.op->newline() << "if (! process_p) {";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_probe_handler(tsk, p);";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- // For begin/thread_begin probes, we don't need to do anything.
- if (flags_seen[UDPF_BEGIN] || flags_seen[UDPF_THREAD_BEGIN])
- {
- s.op->newline() << "case UDPF_BEGIN:";
- s.op->newline() << "case UDPF_THREAD_BEGIN:";
- s.op->indent(1);
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- if (flags_seen[UDPF_SYSCALL] || flags_seen[UDPF_SYSCALL_RETURN])
- {
- s.op->newline() << "case UDPF_SYSCALL:";
- s.op->newline() << "case UDPF_SYSCALL_RETURN:";
- s.op->indent(1);
- s.op->newline() << "stap_utrace_detach(tsk, &p->ops);";
- s.op->newline() << "break;";
- s.op->indent(-1);
- }
-
- s.op->newline() << "default:";
- s.op->indent(1);
- s.op->newline() << "_stp_error(\"unhandled flag value %d at %s:%d\", p->flags, __FUNCTION__, __LINE__);";
- s.op->newline() << "break;";
- s.op->indent(-1);
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
- s.op->newline() << "return rc;";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "static 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++)
- {
- // Emit a "fake" probe decl that is really a hook for to get
- // our vm_callback called.
- string path = it->first;
- s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
- emit_vm_callback_probe_decl (s, true, path, (int64_t)0,
- "__stp_tf_vm_cb");
- s.op->newline() << "#endif";
-
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- utrace_derived_probe *p = it->second[i];
- 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++)
- {
- // Emit a "fake" probe decl that is really a hook for to get
- // our vm_callback called.
- s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
- emit_vm_callback_probe_decl (s, false, "", it->first,
- "__stp_tf_vm_cb");
- s.op->newline() << "#endif";
-
- for (unsigned i = 0; i < it->second.size(); i++)
- {
- utrace_derived_probe *p = it->second[i];
- 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<ARRAY_SIZE(stap_utrace_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<ARRAY_SIZE(stap_utrace_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
// ------------------------------------------------------------------------
@@ -7404,7 +6300,11 @@ uprobe_derived_probe::join_group (systemtap_session& s)
if (! s.uprobe_derived_probes)
s.uprobe_derived_probes = new uprobe_derived_probe_group ();
s.uprobe_derived_probes->enroll (this);
- task_finder_derived_probe_group::create_session_group (s);
+ enable_task_finder(s);
+
+ // Ask buildrun.cxx to build extra module if needed, and
+ // signal staprun to load that module
+ s.need_uprobes = true;
}
@@ -7437,15 +6337,15 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
if (probes.empty()) return;
s.op->newline() << "/* ---- user probes ---- */";
- s.need_uprobes = true; // Ask buildrun.cxx to build extra module if needed
-
// If uprobes isn't in the kernel, pull it in from the runtime.
s.op->newline() << "#if defined(CONFIG_UPROBES) || defined(CONFIG_UPROBES_MODULE)";
s.op->newline() << "#include <linux/uprobes.h>";
s.op->newline() << "#else";
s.op->newline() << "#include \"uprobes/uprobes.h\"";
s.op->newline() << "#endif";
- s.op->newline() << "#include \"task_finder.c\"";
+ s.op->newline() << "#ifndef UPROBES_API_VERSION";
+ s.op->newline() << "#define UPROBES_API_VERSION 1";
+ s.op->newline() << "#endif";
s.op->newline() << "#ifndef MULTIPLE_UPROBES";
s.op->newline() << "#define MULTIPLE_UPROBES 256"; // maximum possible armed uprobes per process() probe point
@@ -7463,6 +6363,21 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(-1) << "} stap_uprobes [MAXUPROBES];";
s.op->newline() << "DEFINE_MUTEX(stap_uprobes_lock);"; // protects against concurrent registration/unregistration
+ // Emit vma callbacks.
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "static struct stap_task_finder_target stap_uprobe_vmcbs[] = {";
+ s.op->indent(1);
+ for (unsigned i = 0; i < probes.size(); i++)
+ {
+ uprobe_derived_probe* p = probes[i];
+ if (p->pid != 0)
+ emit_vma_callback_probe_decl (s, "", p->pid);
+ else
+ emit_vma_callback_probe_decl (s, p->module, (int64_t)0);
+ }
+ s.op->newline(-1) << "};";
+ s.op->newline() << "#endif";
+
s.op->newline() << "static struct stap_uprobe_spec {";
s.op->newline(1) << "struct stap_task_finder_target finder;";
s.op->newline() << "unsigned long address;";
@@ -7542,10 +6457,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
// register new uprobe
s.op->newline() << "if (register_p && sup->spec_index < 0) {";
- // PR6829: we need to check that the sup we're about to reuse is really completely free.
- // See PR6829 notes below.
- s.op->newline(1) << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;";
+ s.op->newline(1) << "#if (UPROBES_API_VERSION < 2)";
+ // See PR6829 comment.
+ s.op->newline() << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;";
s.op->newline() << "else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue;";
+ s.op->newline() << "#endif";
s.op->newline() << "sup->spec_index = spec_index;";
s.op->newline() << "slotted_p = 1;";
s.op->newline() << "break;";
@@ -7596,13 +6512,32 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(-1) << "} else if (!register_p && slotted_p) {";
s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];";
- // NB: we need to release this slot, so we need to borrow the mutex temporarily.
+ s.op->newline() << "int unregistered_flag;";
+ // PR6829, PR9940:
+ // Here we're unregistering for one of two reasons:
+ // 1. the process image is going away (or gone) due to exit or exec; or
+ // 2. the vma containing the probepoint has been unmapped.
+ // In case 1, it's sort of a nop, because uprobes will notice the event
+ // and dispose of the probes eventually, if it hasn't already. But by
+ // calling unmap_u[ret]probe() ourselves, we free up sup right away.
+ //
+ // In both cases, we must use unmap_u[ret]probe instead of
+ // unregister_u[ret]probe, so uprobes knows not to try to restore the
+ // original opcode.
+ s.op->newline() << "#if (UPROBES_API_VERSION >= 2)";
+ s.op->newline() << "if (sups->return_p)";
+ s.op->newline(1) << "unmap_uretprobe (& sup->urp);";
+ s.op->newline(-1) << "else";
+ s.op->newline(1) << "unmap_uprobe (& sup->up);";
+ s.op->newline(-1) << "unregistered_flag = -1;";
+ s.op->newline() << "#else";
+ // Uprobes lacks unmap_u[ret]probe. Before reusing sup, we must wait
+ // until uprobes turns loose of the u[ret]probe on its own, as indicated
+ // by uprobe.kdata = NULL.
+ s.op->newline() << "unregistered_flag = (sups->return_p ? -2 : -1);";
+ s.op->newline() << "#endif";
s.op->newline() << "mutex_lock (& stap_uprobes_lock);";
- // NB: We must not actually uregister u[ret]probes when a target process execs or exits;
- // uprobes does that by itself asynchronously. We can reuse the up/urp struct after
- // uprobes clears the sup->{up,urp}->kdata pointer. PR6829. To tell the two
- // cases apart, we use spec_index -2 vs -1.
- s.op->newline() << "sup->spec_index = (sups->return_p ? -2 : -1);";
+ s.op->newline() << "sup->spec_index = unregistered_flag;";
s.op->newline() << "mutex_unlock (& stap_uprobes_lock);";
s.op->newline() << "handled_p = 1;";
s.op->newline(-1) << "}"; // if slotted_p
@@ -7634,23 +6569,25 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(0) << "return stap_uprobe_change (tsk, register_p, 0, sups);";
s.op->newline(-1) << "}";
- // The task_finder_vm_callback we use for ET_DYN targets.
+ // The task_finder_mmap_callback we use for ET_DYN targets.
s.op->newline();
- s.op->newline() << "static int stap_uprobe_vmchange_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int map_p, char *vm_path, unsigned long vm_start, unsigned long vm_end, unsigned long vm_pgoff) {";
+ s.op->newline() << "static int stap_uprobe_mmap_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, char *path, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags) {";
s.op->newline(1) << "struct stap_uprobe_spec *sups = container_of(tgt, struct stap_uprobe_spec, finder);";
// 1 - shared libraries' executable segments load from offset 0 - ld.so convention
- s.op->newline() << "if (vm_pgoff != 0) return 0;";
+ s.op->newline() << "if (offset != 0) return 0;";
// 2 - the shared library we're interested in
- s.op->newline() << "if (vm_path == NULL || strcmp (vm_path, sups->pathname)) return 0;";
+ s.op->newline() << "if (path == NULL || strcmp (path, sups->pathname)) return 0;";
// 3 - probe address within the mapping limits; test should not fail
- s.op->newline() << "if (vm_end <= vm_start + sups->address) return 0;";
+ s.op->newline() << "if (sups->address >= addr && sups->address < (addr + length)) return 0;";
+ // 4 - mapping should be executable
+ s.op->newline() << "if (!(vm_flags & VM_EXEC)) return 0;";
s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA";
- s.op->newline() << "printk (KERN_INFO \"vmchange pid %d map_p %d path %s vms %p vme %p vmp %p\\n\", tsk->tgid, map_p, vm_path, (void*) vm_start, (void*) vm_end, (void*) vm_pgoff);";
+ s.op->newline() << "printk (KERN_INFO \"vmchange pid %d path %s addr %p length %lu offset %p\\n\", tsk->tgid, path, (void *) addr, length, (void*) offset);";
s.op->newline() << "printk (KERN_INFO \"sups %p pp %s path %s address %p\\n\", sups, sups->pp, sups->pathname ?: \"\", (void*) sups->address);";
s.op->newline() << "#endif";
- s.op->newline(0) << "return stap_uprobe_change (tsk, map_p, vm_start, sups);";
+ s.op->newline(0) << "return stap_uprobe_change (tsk, 1, addr, sups);";
s.op->newline(-1) << "}";
s.op->assert_0_indent();
@@ -7663,6 +6600,16 @@ void
uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
{
if (probes.empty()) return;
+ s.op->newline() << "#ifdef STP_NEED_VMA_TRACKER";
+ s.op->newline() << "_stp_sym_init();";
+ s.op->newline() << "/* ---- uprobe vma callbacks ---- */";
+ s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_uprobe_vmcbs); i++) {";
+ s.op->indent(1);
+ s.op->newline() << "struct stap_task_finder_target *r = &stap_uprobe_vmcbs[i];";
+ s.op->newline() << "rc = stap_register_task_finder_target(r);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#endif";
+
s.op->newline() << "/* ---- user probes ---- */";
s.op->newline() << "for (j=0; j<MAXUPROBES; j++) {";
@@ -7678,7 +6625,7 @@ uprobe_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline(1) << "struct stap_uprobe_spec *sups = & stap_uprobe_specs[i];";
s.op->newline() << "probe_point = sups->pp;"; // for error messages
s.op->newline() << "if (sups->finder.pathname) sups->finder.callback = & stap_uprobe_process_found;";
- s.op->newline() << "else if (sups->pathname) sups->finder.vm_callback = & stap_uprobe_vmchange_found;";
+ s.op->newline() << "else if (sups->pathname) sups->finder.mmap_callback = & stap_uprobe_mmap_found;";
s.op->newline() << "rc = stap_register_task_finder_target (& sups->finder);";
// NB: if (rc), there is no need (XXX: nor any way) to clean up any
@@ -7735,709 +6682,397 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
s.op->newline() << "mutex_destroy (& stap_uprobes_lock);";
}
-
-
// ------------------------------------------------------------------------
-// timer derived probes
+// Kprobe derived probes
// ------------------------------------------------------------------------
+static string TOK_KPROBE("kprobe");
-static string TOK_TIMER("timer");
-
-struct timer_derived_probe: public derived_probe
+struct kprobe_derived_probe: public derived_probe
{
- int64_t interval, randomize;
- bool time_is_msecs; // NB: hrtimers get ms-based probes on modern kernels instead
- timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms=false);
- virtual void join_group (systemtap_session& s);
+ kprobe_derived_probe (probe *base,
+ probe_point *location,
+ const string& name,
+ int64_t stmt_addr,
+ bool has_return,
+ bool has_statement,
+ bool has_maxactive,
+ long maxactive_val
+ );
+ string symbol_name;
+ Dwarf_Addr addr;
+ bool has_return;
+ bool has_statement;
+ bool has_maxactive;
+ long maxactive_val;
+ bool access_var;
+ void printsig (std::ostream &o) const;
+ void join_group (systemtap_session& s);
};
-
-struct timer_derived_probe_group: public generic_dpg<timer_derived_probe>
+struct kprobe_derived_probe_group: public derived_probe_group
{
- void emit_interval (translator_output* o);
+private:
+ multimap<string,kprobe_derived_probe*> probes_by_module;
+ typedef multimap<string,kprobe_derived_probe*>::iterator p_b_m_iterator;
+
public:
+ void enroll (kprobe_derived_probe* probe);
void emit_module_decls (systemtap_session& s);
void emit_module_init (systemtap_session& s);
void emit_module_exit (systemtap_session& s);
};
-
-timer_derived_probe::timer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r, bool ms):
- derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms)
-{
- if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints
- throw semantic_error ("invalid interval for jiffies timer");
- // randomize = 0 means no randomization
- if (randomize < 0 || randomize > interval)
- throw semantic_error ("invalid randomize for jiffies timer");
-
- if (locations.size() != 1)
- throw semantic_error ("expect single probe point");
- // so we don't have to loop over them in the other functions
-}
-
-
-void
-timer_derived_probe::join_group (systemtap_session& s)
+kprobe_derived_probe::kprobe_derived_probe (probe *base,
+ probe_point *location,
+ const string& name,
+ int64_t stmt_addr,
+ bool has_return,
+ bool has_statement,
+ bool has_maxactive,
+ long maxactive_val
+ ):
+ derived_probe (base, location),
+ symbol_name (name), addr (stmt_addr),
+ has_return (has_return), has_statement (has_statement),
+ has_maxactive (has_maxactive), maxactive_val (maxactive_val)
{
- if (! s.timer_derived_probes)
- s.timer_derived_probes = new timer_derived_probe_group ();
- s.timer_derived_probes->enroll (this);
-}
-
-
-void
-timer_derived_probe_group::emit_interval (translator_output* o)
-{
- o->line() << "({";
- o->newline(1) << "unsigned i = stp->intrv;";
- o->newline() << "if (stp->rnd != 0)";
- o->newline(1) << "i += _stp_random_pm(stp->rnd);";
- o->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;";
- o->newline(-1) << "})";
-}
+ this->tok = base->tok;
+ this->access_var = false;
+#ifndef USHRT_MAX
+#define USHRT_MAX 32767
+#endif
-void
-timer_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
+ // Expansion of $target variables in the probe body produces an error during
+ // translate phase, since we're not using debuginfo
- s.op->newline() << "/* ---- timer probes ---- */";
+ vector<probe_point::component*> comps;
+ comps.push_back (new probe_point::component(TOK_KPROBE));
- s.op->newline() << "static struct stap_timer_probe {";
- s.op->newline(1) << "struct timer_list timer_list;";
- s.op->newline() << "const char *pp;";
- s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline() << "unsigned intrv, ms, rnd;";
- s.op->newline(-1) << "} stap_timer_probes [" << probes.size() << "] = {";
- s.op->indent(1);
- for (unsigned i=0; i < probes.size(); i++)
+ if (has_statement)
{
- s.op->newline () << "{";
- s.op->line() << " .pp="
- << lex_cast_qstring (*probes[i]->sole_location()) << ",";
- s.op->line() << " .ph=&" << probes[i]->name << ",";
- s.op->line() << " .intrv=" << probes[i]->interval << ",";
- s.op->line() << " .ms=" << probes[i]->time_is_msecs << ",";
- s.op->line() << " .rnd=" << probes[i]->randomize;
- s.op->line() << " },";
+ comps.push_back (new probe_point::component(TOK_STATEMENT, new literal_number(addr)));
+ comps.push_back (new probe_point::component(TOK_ABSOLUTE));
+ }
+ else
+ {
+ size_t pos = name.find(':');
+ if (pos != string::npos)
+ {
+ string module = name.substr(0, pos);
+ string function = name.substr(pos + 1);
+ comps.push_back (new probe_point::component(TOK_MODULE, new literal_string(module)));
+ comps.push_back (new probe_point::component(TOK_FUNCTION, new literal_string(function)));
+ }
+ else
+ comps.push_back (new probe_point::component(TOK_FUNCTION, new literal_string(name)));
}
- s.op->newline(-1) << "};";
- s.op->newline();
-
- s.op->newline() << "static void enter_timer_probe (unsigned long val) {";
- s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];";
- s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
- s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING))";
- s.op->newline(1) << "mod_timer (& stp->timer_list, jiffies + ";
- emit_interval (s.op);
- s.op->line() << ");";
- s.op->newline(-1) << "{";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp");
- s.op->newline() << "(*stp->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}";
-}
-
-void
-timer_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
+ if (has_return)
+ comps.push_back (new probe_point::component(TOK_RETURN));
+ if (has_maxactive)
+ comps.push_back (new probe_point::component(TOK_MAXACTIVE, new literal_number(maxactive_val)));
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];";
- s.op->newline() << "probe_point = stp->pp;";
- s.op->newline() << "init_timer (& stp->timer_list);";
- s.op->newline() << "stp->timer_list.function = & enter_timer_probe;";
- s.op->newline() << "stp->timer_list.data = i;"; // NB: important!
- // copy timer renew calculations from above :-(
- s.op->newline() << "stp->timer_list.expires = jiffies + ";
- emit_interval (s.op);
- s.op->line() << ";";
- s.op->newline() << "add_timer (& stp->timer_list);";
- // note: no partial failure rollback is needed: add_timer cannot fail.
- s.op->newline(-1) << "}"; // for loop
+ this->sole_location()->components = comps;
}
-
-void
-timer_derived_probe_group::emit_module_exit (systemtap_session& s)
+void kprobe_derived_probe::printsig (ostream& o) const
{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);";
- s.op->indent(-1);
+ sole_location()->print (o);
+ o << " /* " << " name = " << symbol_name << "*/";
+ printsig_nested (o);
}
-
-
-// ------------------------------------------------------------------------
-// profile derived probes
-// ------------------------------------------------------------------------
-// On kernels < 2.6.10, this uses the register_profile_notifier API to
-// generate the timed events for profiling; on kernels >= 2.6.10 this
-// uses the register_timer_hook API. The latter doesn't currently allow
-// simultaneous users, so insertion will fail if the profiler is busy.
-// (Conflicting users may include OProfile, other SystemTap probes, etc.)
-
-
-struct profile_derived_probe: public derived_probe
+void kprobe_derived_probe::join_group (systemtap_session& s)
{
- profile_derived_probe (systemtap_session &s, probe* p, probe_point* l);
- void join_group (systemtap_session& s);
-};
-
-struct profile_derived_probe_group: public generic_dpg<profile_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
+ if (! s.kprobe_derived_probes)
+ s.kprobe_derived_probes = new kprobe_derived_probe_group ();
+ s.kprobe_derived_probes->enroll (this);
-
-profile_derived_probe::profile_derived_probe (systemtap_session &, probe* p, probe_point* l):
- derived_probe(p, l)
-{
}
-
-void
-profile_derived_probe::join_group (systemtap_session& s)
+void kprobe_derived_probe_group::enroll (kprobe_derived_probe* p)
{
- if (! s.profile_derived_probes)
- s.profile_derived_probes = new profile_derived_probe_group ();
- s.profile_derived_probes->enroll (this);
+ probes_by_module.insert (make_pair (p->symbol_name, p));
+ // probes of same symbol should share single kprobe/kretprobe
}
-
-struct profile_builder: public derived_probe_builder
-{
- profile_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const &,
- vector<derived_probe *> & finished_results)
- {
- sess.unwindsym_modules.insert ("kernel");
- finished_results.push_back(new profile_derived_probe(sess, base, location));
- }
-};
-
-
-// timer.profile probe handlers are hooked up in an entertaining way
-// to the underlying kernel facility. The fact that 2.6.11+ era
-// "register_timer_hook" API allows only one consumer *system-wide*
-// will give a hint. We will have a single entry function (and thus
-// trivial registration / unregistration), and it will call all probe
-// handler functions in sequence.
-
void
-profile_derived_probe_group::emit_module_decls (systemtap_session& s)
+kprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
{
- if (probes.empty()) return;
-
- // kernels < 2.6.10: use register_profile_notifier API
- // kernels >= 2.6.10: use register_timer_hook API
- s.op->newline() << "/* ---- profile probes ---- */";
-
- // This function calls all the profiling probe handlers in sequence.
- // The only tricky thing is that the context will be reused amongst
- // them. While a simple sequence of calls to the individual probe
- // handlers is unlikely to go terribly wrong (with c->last_error
- // being set causing an early return), but for extra assurance, we
- // open-code the same logic here.
-
- s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {";
- s.op->indent(1);
- string pp = lex_cast_qstring("timer.profile"); // hard-coded for convenience
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", pp);
- s.op->newline() << "c->regs = regs;";
-
- for (unsigned i=0; i<probes.size(); i++)
- {
- if (i > 0)
- {
- // Some lightweight inter-probe context resetting
- // XXX: not quite right: MAXERRORS not respected
- s.op->newline() << "c->actionremaining = MAXACTION;";
- }
- s.op->newline() << "if (c->last_error == NULL) " << probes[i]->name << " (c);";
- }
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
-
- s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
-
- s.op->newline() << "static int enter_profile_probes (struct notifier_block *self,"
- << " unsigned long val, void *data) {";
- s.op->newline(1) << "(void) self; (void) val;";
- s.op->newline() << "enter_all_profile_probes ((struct pt_regs *) data);";
- s.op->newline() << "return 0;";
- s.op->newline(-1) << "}";
- s.op->newline() << "struct notifier_block stap_profile_notifier = {"
- << " .notifier_call = & enter_profile_probes };";
-
- s.op->newline() << "#else";
+ if (probes_by_module.empty()) return;
- s.op->newline() << "static int enter_profile_probes (struct pt_regs *regs) {";
- s.op->newline(1) << "enter_all_profile_probes (regs);";
- s.op->newline() << "return 0;";
- s.op->newline(-1) << "}";
+ s.op->newline() << "/* ---- kprobe-based probes ---- */";
+ // Warn of misconfigured kernels
+ s.op->newline() << "#if ! defined(CONFIG_KPROBES)";
+ s.op->newline() << "#error \"Need CONFIG_KPROBES!\"";
s.op->newline() << "#endif";
-}
-
+ s.op->newline();
-void
-profile_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
+ // Forward declare the master entry functions
+ s.op->newline() << "static int enter_kprobe2_probe (struct kprobe *inst,";
+ s.op->line() << " struct pt_regs *regs);";
+ s.op->newline() << "static int enter_kretprobe2_probe (struct kretprobe_instance *inst,";
+ s.op->line() << " struct pt_regs *regs);";
- s.op->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience
- s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
- s.op->newline() << "rc = register_profile_notifier (& stap_profile_notifier);";
- s.op->newline() << "#else";
- s.op->newline() << "rc = register_timer_hook (& enter_profile_probes);";
+ // Emit an array of kprobe/kretprobe pointers
+ s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)";
+ s.op->newline() << "static void * stap_unreg_kprobes[" << probes_by_module.size() << "];";
s.op->newline() << "#endif";
-}
+ // Emit the actual probe list.
-void
-profile_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
- s.op->newline() << "unregister_profile_notifier (& stap_profile_notifier);";
- s.op->newline() << "#else";
- s.op->newline() << "unregister_timer_hook (& enter_profile_probes);";
+ s.op->newline() << "static struct stap_dwarfless_kprobe {";
+ s.op->newline(1) << "union { struct kprobe kp; struct kretprobe krp; } u;";
+ s.op->newline() << "#ifdef __ia64__";
+ s.op->newline() << "struct kprobe dummy;";
s.op->newline() << "#endif";
- s.op->indent(-1);
-}
-
-
-
-// ------------------------------------------------------------------------
-// procfs file derived probes
-// ------------------------------------------------------------------------
-
-
-static string TOK_PROCFS("procfs");
-static string TOK_READ("read");
-static string TOK_WRITE("write");
-
-struct procfs_derived_probe: public derived_probe
-{
- string path;
- bool write;
- bool target_symbol_seen;
-
- procfs_derived_probe (systemtap_session &, probe* p, probe_point* l, string ps, bool w);
- void join_group (systemtap_session& s);
-};
-
-
-struct procfs_probe_set
-{
- procfs_derived_probe* read_probe;
- procfs_derived_probe* write_probe;
-
- procfs_probe_set () : read_probe (NULL), write_probe (NULL) {}
-};
-
-
-struct procfs_derived_probe_group: public generic_dpg<procfs_derived_probe>
-{
-private:
- map<string, procfs_probe_set*> probes_by_path;
- typedef map<string, procfs_probe_set*>::iterator p_b_p_iterator;
- bool has_read_probes;
- bool has_write_probes;
-
-public:
- procfs_derived_probe_group () :
- has_read_probes(false), has_write_probes(false) {}
-
- void enroll (procfs_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 procfs_var_expanding_visitor: public var_expanding_visitor
-{
- procfs_var_expanding_visitor(systemtap_session& s, const string& pn,
- string path, bool write_probe):
- sess (s), probe_name (pn), path (path), write_probe (write_probe),
- target_symbol_seen (false) {}
-
- systemtap_session& sess;
- string probe_name;
- string path;
- bool write_probe;
- bool target_symbol_seen;
-
- void visit_target_symbol (target_symbol* e);
-};
-
-
-procfs_derived_probe::procfs_derived_probe (systemtap_session &s, probe* p,
- probe_point* l, string ps, bool w):
- derived_probe(p, l), path(ps), write(w), target_symbol_seen(false)
-{
- // Expand local variables in the probe body
- procfs_var_expanding_visitor v (s, name, path, write);
- this->body = v.require (this->body);
- target_symbol_seen = v.target_symbol_seen;
-}
-
-
-void
-procfs_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.procfs_derived_probes)
- s.procfs_derived_probes = new procfs_derived_probe_group ();
- s.procfs_derived_probes->enroll (this);
-}
+ s.op->newline(-1) << "} stap_dwarfless_kprobes[" << probes_by_module.size() << "];";
+ // NB: bss!
+ s.op->newline() << "static struct stap_dwarfless_probe {";
+ s.op->newline(1) << "const unsigned return_p:1;";
+ s.op->newline() << "const unsigned maxactive_p:1;";
+ s.op->newline() << "unsigned registered_p:1;";
+ s.op->newline() << "const unsigned short maxactive_val;";
-void
-procfs_derived_probe_group::enroll (procfs_derived_probe* p)
-{
- procfs_probe_set *pset;
+ // Function Names are mostly small and uniform enough to justify putting
+ // char[MAX]'s into the array instead of relocated char*'s.
- if (probes_by_path.count(p->path) == 0)
- {
- pset = new procfs_probe_set;
- probes_by_path[p->path] = pset;
- }
- else
+ size_t pp_name_max = 0, symbol_string_name_max = 0;
+ size_t pp_name_tot = 0, symbol_string_name_tot = 0;
+ for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
{
- pset = probes_by_path[p->path];
-
- // You can only specify 1 read and 1 write probe.
- if (p->write && pset->write_probe != NULL)
- throw semantic_error("only one write procfs probe can exist for procfs path \"" + p->path + "\"");
- else if (! p->write && pset->read_probe != NULL)
- throw semantic_error("only one read procfs probe can exist for procfs path \"" + p->path + "\"");
-
- // XXX: multiple writes should be acceptable
+ kprobe_derived_probe* p = it->second;
+#define DOIT(var,expr) do { \
+ size_t var##_size = (expr) + 1; \
+ var##_max = max (var##_max, var##_size); \
+ var##_tot += var##_size; } while (0)
+ DOIT(pp_name, lex_cast_qstring(*p->sole_location()).size());
+ DOIT(symbol_string_name, p->symbol_name.size());
+#undef DOIT
}
- if (p->write)
- {
- pset->write_probe = p;
- has_write_probes = true;
- }
- else
- {
- pset->read_probe = p;
- has_read_probes = true;
- }
-}
-
+#define CALCIT(var) \
+ s.op->newline() << "const char " << #var << "[" << var##_name_max << "] ;";
-void
-procfs_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes_by_path.empty())
- return;
+ CALCIT(pp);
+ CALCIT(symbol_string);
+#undef CALCIT
- s.op->newline() << "/* ---- procfs probes ---- */";
- s.op->newline() << "#include \"procfs.c\"";
-
- // Emit the procfs probe data list
- s.op->newline() << "static struct stap_procfs_probe {";
- s.op->newline(1)<< "const char *path;";
- s.op->newline() << "const char *read_pp;";
- s.op->newline() << "void (*read_ph) (struct context*);";
- s.op->newline() << "const char *write_pp;";
- s.op->newline() << "void (*write_ph) (struct context*);";
- s.op->newline(-1) << "} stap_procfs_probes[] = {";
+ s.op->newline() << "const unsigned long address;";
+ s.op->newline() << "void (* const ph) (struct context*);";
+ s.op->newline(-1) << "} stap_dwarfless_probes[] = {";
s.op->indent(1);
- for (p_b_p_iterator it = probes_by_path.begin(); it != probes_by_path.end();
- it++)
- {
- procfs_probe_set *pset = it->second;
-
+ for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
+ {
+ kprobe_derived_probe* p = it->second;
s.op->newline() << "{";
- s.op->line() << " .path=" << lex_cast_qstring (it->first) << ",";
+ if (p->has_return)
+ s.op->line() << " .return_p=1,";
- if (pset->read_probe != NULL)
- {
- s.op->line() << " .read_pp="
- << lex_cast_qstring (*pset->read_probe->sole_location())
- << ",";
- s.op->line() << " .read_ph=&" << pset->read_probe->name << ",";
- }
- else
+ if (p->has_maxactive)
{
- s.op->line() << " .read_pp=NULL,";
- s.op->line() << " .read_ph=NULL,";
- }
+ s.op->line() << " .maxactive_p=1,";
+ assert (p->maxactive_val >= 0 && p->maxactive_val <= USHRT_MAX);
+ s.op->line() << " .maxactive_val=" << p->maxactive_val << ",";
+ }
- if (pset->write_probe != NULL)
- {
- s.op->line() << " .write_pp="
- << lex_cast_qstring (*pset->write_probe->sole_location())
- << ",";
- s.op->line() << " .write_ph=&" << pset->write_probe->name;
- }
+ if (p->has_statement)
+ s.op->line() << " .address=(unsigned long)0x" << hex << p->addr << dec << "ULL,";
else
- {
- s.op->line() << " .write_pp=NULL,";
- s.op->line() << " .write_ph=NULL";
- }
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
-
- if (has_read_probes)
- {
- // Output routine to fill in 'page' with our data.
- s.op->newline();
-
- s.op->newline() << "static int _stp_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data) {";
-
- s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
- s.op->newline() << "int bytes = 0;";
- s.op->newline() << "string_t strdata = {'\\0'};";
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->read_pp");
-
- s.op->newline() << "if (c->data == NULL)";
- s.op->newline(1) << "c->data = &strdata;";
- s.op->newline(-1) << "else {";
-
- s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
- s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
- s.op->newline() << "_stp_exit ();";
- s.op->newline(-1) << "}";
- s.op->newline() << "atomic_dec (& c->busy);";
- s.op->newline() << "goto probe_epilogue;";
- s.op->newline(-1) << "}";
-
- // call probe function (which copies data into strdata)
- s.op->newline() << "(*spp->read_ph) (c);";
-
- // copy string data into 'page'
- s.op->newline() << "c->data = NULL;";
- s.op->newline() << "bytes = strnlen(strdata, MAXSTRINGLEN - 1);";
- s.op->newline() << "if (off >= bytes)";
- s.op->newline(1) << "*eof = 1;";
- s.op->newline(-1) << "else {";
- s.op->newline(1) << "bytes -= off;";
- s.op->newline() << "if (bytes > count)";
- s.op->newline(1) << "bytes = count;";
- s.op->newline(-1) << "memcpy(page, strdata + off, bytes);";
- s.op->newline() << "*start = page;";
- s.op->newline(-1) << "}";
+ s.op->line() << " .symbol_string=\"" << p->symbol_name << "\",";
- common_probe_entryfn_epilogue (s.op);
- s.op->newline() << "return bytes;";
-
- s.op->newline(-1) << "}";
+ s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
+ s.op->line() << " .ph=&" << p->name;
+ s.op->line() << " },";
}
- if (has_write_probes)
- {
- s.op->newline() << "static int _stp_procfs_write(struct file *file, const char *buffer, unsigned long count, void *data) {";
-
- s.op->newline(1) << "struct stap_procfs_probe *spp = (struct stap_procfs_probe *)data;";
- s.op->newline() << "string_t strdata = {'\\0'};";
-
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "spp->write_pp");
- s.op->newline() << "if (count > (MAXSTRINGLEN - 1))";
- s.op->newline(1) << "count = MAXSTRINGLEN - 1;";
- s.op->newline(-1) << "_stp_copy_from_user(strdata, buffer, count);";
-
- s.op->newline() << "if (c->data == NULL)";
- s.op->newline(1) << "c->data = &strdata;";
- s.op->newline(-1) << "else {";
+ s.op->newline(-1) << "};";
- s.op->newline(1) << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
- s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
- s.op->newline() << "_stp_exit ();";
- s.op->newline(-1) << "}";
- s.op->newline() << "atomic_dec (& c->busy);";
- s.op->newline() << "goto probe_epilogue;";
- s.op->newline(-1) << "}";
+ // Emit the kprobes callback function
+ s.op->newline();
+ s.op->newline() << "static int enter_kprobe2_probe (struct kprobe *inst,";
+ s.op->line() << " struct pt_regs *regs) {";
+ // NB: as of PR5673, the kprobe|kretprobe union struct is in BSS
+ s.op->newline(1) << "int kprobe_idx = ((uintptr_t)inst-(uintptr_t)stap_dwarfless_kprobes)/sizeof(struct stap_dwarfless_kprobe);";
+ // Check that the index is plausible
+ s.op->newline() << "struct stap_dwarfless_probe *sdp = &stap_dwarfless_probes[";
+ s.op->line() << "((kprobe_idx >= 0 && kprobe_idx < " << probes_by_module.size() << ")?";
+ s.op->line() << "kprobe_idx:0)"; // NB: at least we avoid memory corruption
+ // XXX: it would be nice to give a more verbose error though; BUG_ON later?
+ s.op->line() << "];";
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp");
+ s.op->newline() << "c->regs = regs;";
+ s.op->newline() << "(*sdp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline() << "return 0;";
+ s.op->newline(-1) << "}";
- // call probe function (which copies data out of strdata)
- s.op->newline() << "(*spp->write_ph) (c);";
+ // Same for kretprobes
+ s.op->newline();
+ s.op->newline() << "static int enter_kretprobe2_probe (struct kretprobe_instance *inst,";
+ s.op->line() << " struct pt_regs *regs) {";
+ s.op->newline(1) << "struct kretprobe *krp = inst->rp;";
- s.op->newline() << "c->data = NULL;";
- common_probe_entryfn_epilogue (s.op);
+ // NB: as of PR5673, the kprobe|kretprobe union struct is in BSS
+ s.op->newline() << "int kprobe_idx = ((uintptr_t)krp-(uintptr_t)stap_dwarfless_kprobes)/sizeof(struct stap_dwarfless_kprobe);";
+ // Check that the index is plausible
+ s.op->newline() << "struct stap_dwarfless_probe *sdp = &stap_dwarfless_probes[";
+ s.op->line() << "((kprobe_idx >= 0 && kprobe_idx < " << probes_by_module.size() << ")?";
+ s.op->line() << "kprobe_idx:0)"; // NB: at least we avoid memory corruption
+ // XXX: it would be nice to give a more verbose error though; BUG_ON later?
+ s.op->line() << "];";
- s.op->newline() << "return count;";
- s.op->newline(-1) << "}";
- }
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sdp->pp");
+ s.op->newline() << "c->regs = regs;";
+ s.op->newline() << "c->pi = inst;"; // for assisting runtime's backtrace logic
+ s.op->newline() << "(*sdp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline() << "return 0;";
+ s.op->newline(-1) << "}";
}
void
-procfs_derived_probe_group::emit_module_init (systemtap_session& s)
+kprobe_derived_probe_group::emit_module_init (systemtap_session& s)
{
- if (probes_by_path.empty())
- return;
-
- s.op->newline() << "for (i = 0; i < " << probes_by_path.size() << "; i++) {";
- s.op->newline(1) << "struct stap_procfs_probe *spp = &stap_procfs_probes[i];";
-
- s.op->newline() << "if (spp->read_pp)";
- s.op->newline(1) << "probe_point = spp->read_pp;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "probe_point = spp->write_pp;";
-
- s.op->newline(-1) << "rc = _stp_create_procfs(spp->path, i);";
-
- s.op->newline() << "if (rc) {";
- s.op->newline(1) << "_stp_close_procfs();";
- s.op->newline() << "break;";
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
+ s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
+ s.op->newline() << "void *addr = (void *) sdp->address;";
+ s.op->newline() << "const char *symbol_name = addr ? NULL : sdp->symbol_string;";
+ s.op->newline() << "probe_point = sdp->pp;"; // for error messages
+ s.op->newline() << "if (sdp->return_p) {";
+ s.op->newline(1) << "kp->u.krp.kp.addr = addr;";
+ s.op->newline() << "kp->u.krp.kp.symbol_name = (char *) symbol_name;";
+ s.op->newline() << "if (sdp->maxactive_p) {";
+ s.op->newline(1) << "kp->u.krp.maxactive = sdp->maxactive_val;";
+ s.op->newline(-1) << "} else {";
+ s.op->newline(1) << "kp->u.krp.maxactive = max(10, 4*NR_CPUS);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "kp->u.krp.handler = &enter_kretprobe2_probe;";
+ // to ensure safeness of bspcache, always use aggr_kprobe on ia64
+ s.op->newline() << "#ifdef __ia64__";
+ s.op->newline() << "kp->dummy.addr = kp->u.krp.kp.addr;";
+ s.op->newline() << "kp->dummy.symbol_name = kp->u.krp.kp.symbol_name;";
+ s.op->newline() << "kp->dummy.pre_handler = NULL;";
+ s.op->newline() << "rc = register_kprobe (& kp->dummy);";
+ s.op->newline() << "if (rc == 0) {";
+ s.op->newline(1) << "rc = register_kretprobe (& kp->u.krp);";
+ s.op->newline() << "if (rc != 0)";
+ s.op->newline(1) << "unregister_kprobe (& kp->dummy);";
+ s.op->newline(-2) << "}";
+ s.op->newline() << "#else";
+ s.op->newline() << "rc = register_kretprobe (& kp->u.krp);";
+ s.op->newline() << "#endif";
+ s.op->newline(-1) << "} else {";
+ // to ensure safeness of bspcache, always use aggr_kprobe on ia64
+ s.op->newline(1) << "kp->u.kp.addr = addr;";
+ s.op->newline() << "kp->u.kp.symbol_name = (char *) symbol_name;";
+ s.op->newline() << "kp->u.kp.pre_handler = &enter_kprobe2_probe;";
+ s.op->newline() << "#ifdef __ia64__";
+ s.op->newline() << "kp->dummy.pre_handler = NULL;";
+ s.op->newline() << "kp->dummy.addr = kp->u.kp.addr;";
+ s.op->newline() << "kp->dummy.symbol_name = kp->u.kp.symbol_name;";
+ s.op->newline() << "rc = register_kprobe (& kp->dummy);";
+ s.op->newline() << "if (rc == 0) {";
+ s.op->newline(1) << "rc = register_kprobe (& kp->u.kp);";
+ s.op->newline() << "if (rc != 0)";
+ s.op->newline(1) << "unregister_kprobe (& kp->dummy);";
+ s.op->newline(-2) << "}";
+ s.op->newline() << "#else";
+ s.op->newline() << "rc = register_kprobe (& kp->u.kp);";
+ s.op->newline() << "#endif";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "if (rc) {"; // PR6749: tolerate a failed register_*probe.
+ s.op->newline(1) << "sdp->registered_p = 0;";
+ s.op->newline() << "_stp_warn (\"probe %s registration error (rc %d)\", probe_point, rc);";
+ s.op->newline() << "rc = 0;"; // continue with other probes
+ // XXX: shall we increment numskipped?
s.op->newline(-1) << "}";
- if (has_read_probes)
- {
- s.op->newline() << "if (spp->read_pp)";
- s.op->newline(1) << "_stp_procfs_files[i]->read_proc = &_stp_procfs_read;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "_stp_procfs_files[i]->read_proc = NULL;";
- s.op->indent(-1);
- }
- else
- s.op->newline() << "_stp_procfs_files[i]->read_proc = NULL;";
-
- if (has_write_probes)
- {
- s.op->newline() << "if (spp->write_pp)";
- s.op->newline(1) << "_stp_procfs_files[i]->write_proc = &_stp_procfs_write;";
- s.op->newline(-1) << "else";
- s.op->newline(1) << "_stp_procfs_files[i]->write_proc = NULL;";
- s.op->indent(-1);
- }
- else
- s.op->newline() << "_stp_procfs_files[i]->write_proc = NULL;";
-
- s.op->newline() << "_stp_procfs_files[i]->data = spp;";
+ s.op->newline() << "else sdp->registered_p = 1;";
s.op->newline(-1) << "}"; // for loop
}
-
void
-procfs_derived_probe_group::emit_module_exit (systemtap_session& s)
+kprobe_derived_probe_group::emit_module_exit (systemtap_session& s)
{
- if (probes_by_path.empty())
- return;
-
- s.op->newline() << "_stp_close_procfs();";
-}
-
-
-void
-procfs_var_expanding_visitor::visit_target_symbol (target_symbol* e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- if (e->base_name != "$value")
- throw semantic_error ("invalid target symbol for procfs probe, $value expected",
- e->tok);
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("procfs target variable '$value' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("procfs target variable '$value' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of procfs target variable '$value'",
- e->tok);
- break;
- }
- }
-
- bool lvalue = is_active_lvalue(e);
- if (write_probe && lvalue)
- throw semantic_error("procfs $value variable is read-only in a procfs write probe", e->tok);
- else if (! write_probe && ! lvalue)
- throw semantic_error("procfs $value variable cannot be read in a procfs read probe", 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(lvalue ? "_procfs_value_set" : "_procfs_value_get")
- + "_" + lex_cast<string>(tick++));
- string locvalue = "CONTEXT->data";
-
- if (! lvalue)
- ec->code = string("strlcpy (THIS->__retvalue, ") + locvalue
- + string(", MAXSTRINGLEN); /* pure */");
- else
- ec->code = string("strlcpy (") + locvalue
- + string(", THIS->value, MAXSTRINGLEN);");
-
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_string;
-
- if (lvalue)
- {
- // Modify the fdecl so it carries a single pe_string formal
- // argument called "value".
-
- vardecl *v = new vardecl;
- v->type = pe_string;
- v->name = "value";
- v->tok = e->tok;
- fdecl->formal_args.push_back(v);
- }
- sess.functions[fdecl->name]=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
-
- if (lvalue)
- {
- // Provide the functioncall to our parent, so that it can be
- // used to substitute for the assignment node immediately above
- // us.
- assert(!target_symbol_setter_functioncalls.empty());
- *(target_symbol_setter_functioncalls.top()) = n;
- }
+ //Unregister kprobes by batch interfaces.
+ s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)";
+ s.op->newline() << "j = 0;";
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
+ s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
+ s.op->newline() << "if (! sdp->registered_p) continue;";
+ s.op->newline() << "if (!sdp->return_p)";
+ s.op->newline(1) << "stap_unreg_kprobes[j++] = &kp->u.kp;";
+ s.op->newline(-2) << "}";
+ s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes, j);";
+ s.op->newline() << "j = 0;";
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
+ s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
+ s.op->newline() << "if (! sdp->registered_p) continue;";
+ s.op->newline() << "if (sdp->return_p)";
+ s.op->newline(1) << "stap_unreg_kprobes[j++] = &kp->u.krp;";
+ s.op->newline(-2) << "}";
+ s.op->newline() << "unregister_kretprobes((struct kretprobe **)stap_unreg_kprobes, j);";
+ s.op->newline() << "#ifdef __ia64__";
+ s.op->newline() << "j = 0;";
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
+ s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
+ s.op->newline() << "if (! sdp->registered_p) continue;";
+ s.op->newline() << "stap_unreg_kprobes[j++] = &kp->dummy;";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "unregister_kprobes((struct kprobe **)stap_unreg_kprobes, j);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "#endif";
- provide (n);
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_dwarfless_probe *sdp = & stap_dwarfless_probes[i];";
+ s.op->newline() << "struct stap_dwarfless_kprobe *kp = & stap_dwarfless_kprobes[i];";
+ s.op->newline() << "if (! sdp->registered_p) continue;";
+ s.op->newline() << "if (sdp->return_p) {";
+ s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES)";
+ s.op->newline(1) << "unregister_kretprobe (&kp->u.krp);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "atomic_add (kp->u.krp.nmissed, & skipped_count);";
+ s.op->newline() << "#ifdef STP_TIMING";
+ s.op->newline() << "if (kp->u.krp.nmissed)";
+ s.op->newline(1) << "_stp_warn (\"Skipped due to missed kretprobe/1 on '%s': %d\\n\", sdp->pp, kp->u.krp.nmissed);";
+ s.op->newline(-1) << "#endif";
+ s.op->newline() << "atomic_add (kp->u.krp.kp.nmissed, & skipped_count);";
+ s.op->newline() << "#ifdef STP_TIMING";
+ s.op->newline() << "if (kp->u.krp.kp.nmissed)";
+ s.op->newline(1) << "_stp_warn (\"Skipped due to missed kretprobe/2 on '%s': %d\\n\", sdp->pp, kp->u.krp.kp.nmissed);";
+ s.op->newline(-1) << "#endif";
+ s.op->newline(-1) << "} else {";
+ s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES)";
+ s.op->newline(1) << "unregister_kprobe (&kp->u.kp);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "atomic_add (kp->u.kp.nmissed, & skipped_count);";
+ s.op->newline() << "#ifdef STP_TIMING";
+ s.op->newline() << "if (kp->u.kp.nmissed)";
+ s.op->newline(1) << "_stp_warn (\"Skipped due to missed kprobe on '%s': %d\\n\", sdp->pp, kp->u.kp.nmissed);";
+ s.op->newline(-1) << "#endif";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "#if !defined(STAPCONF_UNREGISTER_KPROBES) && defined(__ia64__)";
+ s.op->newline() << "unregister_kprobe (&kp->dummy);";
+ s.op->newline() << "#endif";
+ s.op->newline() << "sdp->registered_p = 0;";
+ s.op->newline(-1) << "}";
}
-
-struct procfs_builder: public derived_probe_builder
+struct kprobe_builder: public derived_probe_builder
{
- procfs_builder() {}
+ kprobe_builder() {}
virtual void build(systemtap_session & sess,
probe * base,
probe_point * location,
@@ -8447,782 +7082,49 @@ struct procfs_builder: public derived_probe_builder
void
-procfs_builder::build(systemtap_session & sess,
+kprobe_builder::build(systemtap_session & sess,
probe * base,
probe_point * location,
literal_map_t const & parameters,
vector<derived_probe *> & finished_results)
{
- string path;
- bool has_procfs = get_param(parameters, TOK_PROCFS, path);
- bool has_read = (parameters.find(TOK_READ) != parameters.end());
- bool has_write = (parameters.find(TOK_WRITE) != parameters.end());
-
- // If no procfs path, default to "command". The runtime will do
- // this for us, but if we don't do it here, we'll think the
- // following 2 probes are attached to different paths:
- //
- // probe procfs("command").read {}"
- // probe procfs.write {}
+ string function_string_val, module_string_val;
+ int64_t statement_num_val = 0, maxactive_val = 0;
+ bool has_function_str, has_module_str, has_statement_num;
+ bool has_absolute, has_return, has_maxactive;
- if (! has_procfs)
- path = "command";
- // If we have a path, we need to validate it.
- else
- {
- string::size_type start_pos, end_pos;
- string component;
- start_pos = 0;
- while ((end_pos = path.find('/', start_pos)) != string::npos)
- {
- // Make sure it doesn't start with '/'.
- if (end_pos == 0)
- throw semantic_error ("procfs path cannot start with a '/'",
- location->tok);
-
- component = path.substr(start_pos, end_pos - start_pos);
- // Make sure it isn't empty.
- if (component.size() == 0)
- throw semantic_error ("procfs path component cannot be empty",
- location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("procfs 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 ("procfs path cannot end with a '/'", location->tok);
- // Make sure it isn't relative.
- else if (component == "." || component == "..")
- throw semantic_error ("procfs path cannot be relative (and contain '.' or '..')", location->tok);
- }
+ has_function_str = get_param(parameters, TOK_FUNCTION, function_string_val);
+ has_module_str = get_param(parameters, TOK_MODULE, module_string_val);
+ has_return = has_null_param (parameters, TOK_RETURN);
+ has_maxactive = get_param(parameters, TOK_MAXACTIVE, maxactive_val);
+ has_statement_num = get_param(parameters, TOK_STATEMENT, statement_num_val);
+ has_absolute = has_null_param (parameters, TOK_ABSOLUTE);
- if (!(has_read ^ has_write))
- throw semantic_error ("need read/write component", location->tok);
-
- finished_results.push_back(new procfs_derived_probe(sess, base, location,
- path, has_write));
-}
-
-
-
-// ------------------------------------------------------------------------
-// statically inserted macro-based derived probes
-// ------------------------------------------------------------------------
-
-static string TOK_FORMAT("format");
-
-struct mark_arg
-{
- bool str;
- string c_type;
- exp_type stp_type;
-};
-
-struct mark_derived_probe: public derived_probe
-{
- mark_derived_probe (systemtap_session &s,
- const string& probe_name, const string& probe_format,
- probe* base_probe, probe_point* location);
-
- systemtap_session& sess;
- string probe_name, probe_format;
- vector <struct mark_arg *> mark_args;
- bool target_symbol_seen;
-
- void join_group (systemtap_session& s);
- void emit_probe_context_vars (translator_output* o);
- void initialize_probe_context_vars (translator_output* o);
- void printargs (std::ostream &o) const;
-
- void parse_probe_format ();
-};
-
-
-struct mark_derived_probe_group: public generic_dpg<mark_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-struct mark_var_expanding_visitor: public var_expanding_visitor
-{
- mark_var_expanding_visitor(systemtap_session& s, const string& pn,
- vector <struct mark_arg *> &mark_args):
- sess (s), probe_name (pn), mark_args (mark_args),
- target_symbol_seen (false) {}
- systemtap_session& sess;
- string probe_name;
- vector <struct mark_arg *> &mark_args;
- bool target_symbol_seen;
-
- void visit_target_symbol (target_symbol* e);
- void visit_target_symbol_arg (target_symbol* e);
- void visit_target_symbol_context (target_symbol* e);
-};
-
-
-void
-hex_dump(unsigned char *data, size_t len)
-{
- // Dump data
- size_t idx = 0;
- while (idx < len)
- {
- string char_rep;
-
- clog << " 0x" << setfill('0') << setw(8) << hex << internal << idx;
-
- for (int i = 0; i < 4; i++)
- {
- clog << " ";
- size_t limit = idx + 4;
- while (idx < len && idx < limit)
- {
- clog << setfill('0') << setw(2)
- << ((unsigned) *((unsigned char *)data + idx));
- if (isprint(*((char *)data + idx)))
- char_rep += *((char *)data + idx);
- else
- char_rep += '.';
- idx++;
- }
- while (idx < limit)
- {
- clog << " ";
- idx++;
- }
- }
- clog << " " << char_rep << dec << setfill(' ') << endl;
- }
-}
-
-
-void
-mark_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
-{
- string argnum_s = e->base_name.substr(4,e->base_name.length()-4);
- int argnum = atoi (argnum_s.c_str());
-
- if (argnum < 1 || argnum > (int)mark_args.size())
- throw semantic_error ("invalid marker argument number", e->tok);
-
- if (is_active_lvalue (e))
- throw semantic_error("write to marker parameter not permitted", e->tok);
-
- if (e->components.size() > 0)
+ if (has_function_str)
{
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("marker argument may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("marker argument may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid marker argument use", e->tok);
- break;
- }
- }
-
- // 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("_mark_tvar_get")
- + "_" + e->base_name.substr(1)
- + "_" + lex_cast<string>(tick++);
-
- if (mark_args[argnum-1]->stp_type == pe_long)
- ec->code = string("THIS->__retvalue = CONTEXT->locals[0].")
- + probe_name + string(".__mark_arg")
- + lex_cast<string>(argnum) + string (";");
- else
- ec->code = string("strlcpy (THIS->__retvalue, CONTEXT->locals[0].")
- + probe_name + string(".__mark_arg")
- + lex_cast<string>(argnum) + string (", MAXSTRINGLEN);");
- ec->code += "/* pure */";
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = mark_args[argnum-1]->stp_type;
- sess.functions[fdecl->name]=fdecl;
+ if (has_module_str)
+ function_string_val = module_string_val + ":" + function_string_val;
- // 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 (n);
-}
-
-
-void
-mark_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
-{
- string sname = e->base_name;
-
- if (is_active_lvalue (e))
- throw semantic_error("write to marker '" + sname + "' not permitted", e->tok);
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("marker '" + sname + "' may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("marker '" + sname + "' may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid marker '" + sname + "' use", e->tok);
- break;
- }
+ finished_results.push_back (new kprobe_derived_probe (base,
+ location, function_string_val,
+ 0, has_return,
+ has_statement_num,
+ has_maxactive,
+ maxactive_val));
}
-
- string fname;
- if (e->base_name == "$format") {
- fname = string("_mark_format_get");
- } else {
- fname = string("_mark_name_get");
- }
-
- // 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 (n);
-}
-
-void
-mark_var_expanding_visitor::visit_target_symbol (target_symbol* e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- if (e->base_name.substr(0,4) == "$arg")
- visit_target_symbol_arg (e);
- else if (e->base_name == "$format" || e->base_name == "$name")
- visit_target_symbol_context (e);
else
- throw semantic_error ("invalid target symbol for marker, $argN, $name or $format expected",
- e->tok);
-}
-
-
-
-mark_derived_probe::mark_derived_probe (systemtap_session &s,
- const string& p_n,
- const string& p_f,
- probe* base, probe_point* loc):
- derived_probe (base, new probe_point(*loc) /* .components soon rewritten */),
- sess (s), probe_name (p_n), probe_format (p_f),
- target_symbol_seen (false)
-{
- // create synthetic probe point name; preserve condition
- vector<probe_point::component*> comps;
- comps.push_back (new probe_point::component (TOK_KERNEL));
- comps.push_back (new probe_point::component (TOK_MARK, new literal_string (probe_name)));
- comps.push_back (new probe_point::component (TOK_FORMAT, new literal_string (probe_format)));
- this->sole_location()->components = comps;
-
- // expand the marker format
- parse_probe_format();
-
- // Now expand the local variables in the probe body
- mark_var_expanding_visitor v (sess, name, mark_args);
- this->body = v.require (this->body);
- target_symbol_seen = v.target_symbol_seen;
-
- if (sess.verbose > 2)
- clog << "marker-based " << name << " mark=" << probe_name
- << " fmt='" << probe_format << "'" << endl;
-}
-
-
-static int
-skip_atoi(const char **s)
-{
- int i = 0;
- while (isdigit(**s))
- i = i * 10 + *((*s)++) - '0';
- return i;
-}
-
-
-void
-mark_derived_probe::parse_probe_format()
-{
- const char *fmt = probe_format.c_str();
- int qualifier; // 'h', 'l', or 'L' for integer fields
- mark_arg *arg;
-
- for (; *fmt ; ++fmt)
{
- if (*fmt != '%')
- {
- /* Skip text */
- continue;
- }
-
-repeat:
- ++fmt;
-
- // skip conversion flags (if present)
- switch (*fmt)
- {
- case '-':
- case '+':
- case ' ':
- case '#':
- case '0':
- goto repeat;
- }
-
- // skip minimum field witdh (if present)
- if (isdigit(*fmt))
- skip_atoi(&fmt);
-
- // skip precision (if present)
- if (*fmt == '.')
- {
- ++fmt;
- if (isdigit(*fmt))
- skip_atoi(&fmt);
- }
-
- // get the conversion qualifier (if present)
- qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
- {
- qualifier = *fmt;
- ++fmt;
- if (qualifier == 'l' && *fmt == 'l')
- {
- qualifier = 'L';
- ++fmt;
- }
- }
-
- // get the conversion type
- switch (*fmt)
- {
- case 'c':
- arg = new mark_arg;
- arg->str = false;
- arg->c_type = "int";
- arg->stp_type = pe_long;
- mark_args.push_back(arg);
- continue;
-
- case 's':
- arg = new mark_arg;
- arg->str = true;
- arg->c_type = "char *";
- arg->stp_type = pe_string;
- mark_args.push_back(arg);
- continue;
-
- case 'p':
- arg = new mark_arg;
- arg->str = false;
- // This should really be 'void *'. But, then we'll get a
- // compile error when we assign the void pointer to an
- // integer without a cast. So, we use 'long' instead, since
- // it should have the same size as 'void *'.
- arg->c_type = "long";
- arg->stp_type = pe_long;
- mark_args.push_back(arg);
- continue;
-
- case '%':
- continue;
-
- case 'o':
- case 'X':
- case 'x':
- case 'd':
- case 'i':
- case 'u':
- // fall through...
- break;
-
- default:
- if (!*fmt)
- --fmt;
- continue;
- }
-
- arg = new mark_arg;
- arg->str = false;
- arg->stp_type = pe_long;
- switch (qualifier)
- {
- case 'L':
- arg->c_type = "long long";
- break;
-
- case 'l':
- arg->c_type = "long";
- break;
-
- case 'h':
- arg->c_type = "short";
- break;
-
- default:
- arg->c_type = "int";
- break;
- }
- mark_args.push_back(arg);
- }
-}
-
-
-void
-mark_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.mark_derived_probes)
- {
- 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);
-}
-
-
-void
-mark_derived_probe::emit_probe_context_vars (translator_output* o)
-{
- // If we haven't seen a target symbol for this probe, quit.
- if (! target_symbol_seen)
- return;
-
- for (unsigned i = 0; i < mark_args.size(); i++)
- {
- string localname = "__mark_arg" + lex_cast<string>(i+1);
- switch (mark_args[i]->stp_type)
- {
- case pe_long:
- o->newline() << "int64_t " << localname << ";";
- break;
- case pe_string:
- o->newline() << "string_t " << localname << ";";
- break;
- default:
- throw semantic_error ("cannot expand unknown type");
- break;
- }
- }
-}
-
-
-void
-mark_derived_probe::initialize_probe_context_vars (translator_output* o)
-{
- // If we haven't seen a target symbol for this probe, quit.
- if (! target_symbol_seen)
- return;
-
- bool deref_fault_needed = false;
- for (unsigned i = 0; i < mark_args.size(); i++)
- {
- string localname = "l->__mark_arg" + lex_cast<string>(i+1);
- switch (mark_args[i]->stp_type)
- {
- case pe_long:
- o->newline() << localname << " = va_arg(*c->mark_va_list, "
- << mark_args[i]->c_type << ");";
- break;
-
- case pe_string:
- // We're assuming that this is a kernel string (this code is
- // basically the guts of kernel_string), not a user string.
- o->newline() << "{ " << mark_args[i]->c_type
- << " tmp_str = va_arg(*c->mark_va_list, "
- << mark_args[i]->c_type << ");";
- o->newline() << "deref_string (" << localname
- << ", tmp_str, MAXSTRINGLEN); }";
- deref_fault_needed = true;
- break;
-
- default:
- throw semantic_error ("cannot expand unknown type");
- break;
- }
- }
- if (deref_fault_needed)
- // Need to report errors?
- o->newline() << "deref_fault: ;";
-}
-
-void
-mark_derived_probe::printargs(std::ostream &o) const
-{
- for (unsigned i = 0; i < mark_args.size(); i++)
- {
- string localname = "$arg" + lex_cast<string>(i+1);
- switch (mark_args[i]->stp_type)
- {
- case pe_long:
- o << " " << localname << ":long";
- break;
- case pe_string:
- o << " " << localname << ":string";
- break;
- default:
- o << " " << localname << ":unknown";
- break;
- }
- }
-}
-
-
-void
-mark_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty())
- return;
-
- s.op->newline() << "/* ---- marker probes ---- */";
-
- s.op->newline() << "static struct stap_marker_probe {";
- s.op->newline(1) << "const char * const name;";
- s.op->newline() << "const char * const format;";
- s.op->newline() << "const char * const pp;";
- s.op->newline() << "void (* const ph) (struct context *);";
-
- s.op->newline(-1) << "} stap_marker_probes [" << probes.size() << "] = {";
- s.op->indent(1);
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .name=" << lex_cast_qstring(probes[i]->probe_name)
- << ",";
- s.op->line() << " .format=" << lex_cast_qstring(probes[i]->probe_format)
- << ",";
- s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location())
- << ",";
- s.op->line() << " .ph=&" << probes[i]->name;
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
- s.op->newline();
-
-
- // Emit the marker callback function
- s.op->newline();
- s.op->newline() << "static void enter_marker_probe (void *probe_data, void *call_data, const char *fmt, va_list *args) {";
- s.op->newline(1) << "struct stap_marker_probe *smp = (struct stap_marker_probe *)probe_data;";
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "smp->pp");
- s.op->newline() << "c->marker_name = smp->name;";
- s.op->newline() << "c->marker_format = smp->format;";
- s.op->newline() << "c->mark_va_list = args;";
- s.op->newline() << "(*smp->ph) (c);";
- s.op->newline() << "c->mark_va_list = NULL;";
- s.op->newline() << "c->data = NULL;";
-
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
-
- return;
-}
-
-
-void
-mark_derived_probe_group::emit_module_init (systemtap_session &s)
-{
- if (probes.size () == 0)
- return;
-
- s.op->newline() << "/* init marker probes */";
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
- s.op->newline() << "probe_point = smp->pp;";
- s.op->newline() << "rc = marker_probe_register(smp->name, smp->format, enter_marker_probe, smp);";
- s.op->newline() << "if (rc) {";
- s.op->newline(1) << "for (j=i-1; j>=0; j--) {"; // partial rollback
- s.op->newline(1) << "struct stap_marker_probe *smp2 = &stap_marker_probes[j];";
- s.op->newline() << "marker_probe_unregister(smp2->name, enter_marker_probe, smp2);";
- s.op->newline(-1) << "}";
- s.op->newline() << "break;"; // don't attempt to register any more probes
- s.op->newline(-1) << "}";
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-void
-mark_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty())
- return;
-
- s.op->newline() << "/* deregister marker probes */";
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_marker_probe *smp = &stap_marker_probes[i];";
- s.op->newline() << "marker_probe_unregister(smp->name, enter_marker_probe, smp);";
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-struct mark_builder: public derived_probe_builder
-{
-private:
- bool cache_initialized;
- typedef multimap<string, string> mark_cache_t;
- typedef multimap<string, string>::const_iterator mark_cache_const_iterator_t;
- typedef pair<mark_cache_const_iterator_t, mark_cache_const_iterator_t>
- mark_cache_const_iterator_pair_t;
- mark_cache_t mark_cache;
-
-public:
- mark_builder(): cache_initialized(false) {}
-
- void build_no_more (systemtap_session &s)
- {
- if (! mark_cache.empty())
- {
- if (s.verbose > 3)
- clog << "mark_builder releasing cache" << endl;
- mark_cache.clear();
- }
- }
-
- void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results);
-};
-
-
-void
-mark_builder::build(systemtap_session & sess,
- probe * base,
- probe_point *loc,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
-{
- string mark_str_val;
- bool has_mark_str = get_param (parameters, TOK_MARK, mark_str_val);
- string mark_format_val;
- bool has_mark_format = get_param (parameters, TOK_FORMAT, mark_format_val);
- assert (has_mark_str);
- (void) has_mark_str;
-
- if (! cache_initialized)
- {
- cache_initialized = true;
- string module_markers_path = sess.kernel_build_tree + "/Module.markers";
-
- ifstream module_markers;
- module_markers.open(module_markers_path.c_str(), ifstream::in);
- if (! module_markers)
- {
- if (sess.verbose>3)
- clog << module_markers_path << " cannot be opened: "
- << strerror(errno) << endl;
- return;
- }
-
- string name, module, format;
- do
- {
- module_markers >> name >> module;
- getline(module_markers, format);
-
- // trim leading whitespace
- 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;
-
- if (mark_cache.count(name) > 0)
- {
- // If we have 2 markers with the same we've got 2 cases:
- // different format strings or duplicate format strings.
- // If an existing marker in the cache doesn't have the
- // same format string, add this marker.
- mark_cache_const_iterator_pair_t ret;
- mark_cache_const_iterator_t it;
- bool matching_format_string = false;
-
- ret = mark_cache.equal_range(name);
- for (it = ret.first; it != ret.second; ++it)
- {
- if (format == it->second)
- {
- matching_format_string = true;
- break;
- }
- }
-
- if (! matching_format_string)
- mark_cache.insert(pair<string,string>(name, format));
- }
- else
- mark_cache.insert(pair<string,string>(name, format));
- }
- while (! module_markers.eof());
- module_markers.close();
- }
-
- // Search marker list for matching markers
- for (mark_cache_const_iterator_t it = mark_cache.begin();
- it != mark_cache.end(); it++)
- {
- // Below, "rc" has negative polarity: zero iff matching.
- int rc = fnmatch(mark_str_val.c_str(), it->first.c_str(), 0);
- if (! rc)
- {
- bool add_result = true;
-
- // Match format strings (if the user specified one)
- if (has_mark_format && fnmatch(mark_format_val.c_str(),
- it->second.c_str(), 0))
- add_result = false;
+ // assert guru mode for absolute probes
+ if ( has_statement_num && has_absolute && !base->privileged )
+ throw semantic_error ("absolute statement probe in unprivileged script", base->tok);
- if (add_result)
- {
- derived_probe *dp
- = new mark_derived_probe (sess,
- it->first, it->second,
- base, loc);
- finished_results.push_back (dp);
- }
- }
+ finished_results.push_back (new kprobe_derived_probe (base,
+ location, "",
+ statement_num_val,
+ has_return,
+ has_statement_num,
+ has_maxactive,
+ maxactive_val));
}
}
@@ -9234,10 +7136,10 @@ mark_builder::build(systemtap_session & sess,
struct tracepoint_arg
{
- string name, c_type;
- bool used, isptr;
+ string name, c_type, typecast;
+ bool usable, used, isptr;
Dwarf_Die type_die;
- tracepoint_arg(): used(false), isptr(false) {}
+ tracepoint_arg(): usable(false), used(false), isptr(false) {}
};
struct tracepoint_derived_probe: public derived_probe
@@ -9254,6 +7156,7 @@ struct tracepoint_derived_probe: public derived_probe
void build_args(dwflpp& dw, Dwarf_Die& func_die);
void printargs (std::ostream &o) const;
void join_group (systemtap_session& s);
+ void print_dupe_stamp(ostream& o);
void emit_probe_context_vars (translator_output* o);
};
@@ -9289,7 +7192,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
// search for a tracepoint parameter matching this name
tracepoint_arg *arg = NULL;
for (unsigned i = 0; i < args.size(); ++i)
- if (args[i].name == argname)
+ if (args[i].usable && args[i].name == argname)
{
arg = &args[i];
arg->used = true;
@@ -9337,36 +7240,16 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
if (lvalue && (!dw.sess.guru_mode || e->components.empty()))
throw semantic_error("write to tracepoint variable '" + e->base_name
+ "' not permitted", e->tok);
+ // XXX: if a struct/union arg is passed by value, then writing to its fields
+ // is also meaningless until you dereference past a pointer member. It's
+ // harder to detect and prevent that though...
if (e->components.empty())
{
- // Synthesize a simple function to grab the parameter
- functiondecl *fdecl = new functiondecl;
- fdecl->tok = e->tok;
- embeddedcode *ec = new embeddedcode;
- ec->tok = e->tok;
-
- string fname = (string("_tracepoint_tvar_get")
- + "_" + e->base_name.substr(1)
- + "_" + lex_cast<string>(tick++));
-
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_long;
-
- ec->code = (string("THIS->__retvalue = CONTEXT->locals[0].")
- + probe_name + string(".__tracepoint_arg_")
- + arg->name + string (";/* pure */"));
-
- dw.sess.functions[fdecl->name] = 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 (n);
+ // Just grab the value from the probe locals
+ e->probe_context_var = "__tracepoint_arg_" + arg->name;
+ e->type = pe_long;
+ provide (e);
}
else
{
@@ -9386,7 +7269,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
try
{
- ec->code = dw.literal_stmt_for_pointer (&arg->type_die, e->components,
+ ec->code = dw.literal_stmt_for_pointer (&arg->type_die, e,
lvalue, fdecl->type);
}
catch (const semantic_error& er)
@@ -9489,7 +7372,6 @@ tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
}
else if (e->base_name == "$$vars" || e->base_name == "$$parms")
{
- target_symbol *tsym = new target_symbol;
print_format* pf = new print_format;
// Convert $$vars to sprintf of a list of vars which we recursively evaluate
@@ -9508,9 +7390,12 @@ tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
for (unsigned i = 0; i < args.size(); ++i)
{
+ if (!args[i].usable)
+ continue;
if (i > 0)
pf->raw_components += " ";
pf->raw_components += args[i].name;
+ target_symbol *tsym = new target_symbol;
tsym->tok = e->tok;
tsym->base_name = "$" + args[i].name;
@@ -9519,7 +7404,7 @@ tracepoint_var_expanding_visitor::visit_target_symbol_context (target_symbol* e)
expression *texp = require (tsym); // NB: throws nothing ...
assert (!tsym->saved_conversion_error); // ... but this is how we know it happened.
- pf->raw_components += "=%#x";
+ pf->raw_components += args[i].isptr ? "=%p" : "=%#x";
pf->args.push_back(texp);
}
@@ -9573,6 +7458,7 @@ tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s,
// tracepoints from FOO_event_types.h should really be included from FOO.h
// XXX can dwarf tell us the include hierarchy? it would be better to
// ... walk up to see which one was directly included by tracequery.c
+ // XXX: see also PR9993.
header_pos = header.find("_event_types");
if (header_pos != string::npos)
header.erase(header_pos, 12);
@@ -9590,32 +7476,39 @@ tracepoint_derived_probe::tracepoint_derived_probe (systemtap_session& s,
static bool
dwarf_type_name(Dwarf_Die& type_die, string& c_type)
{
- // if this die has a direct name, then we're done
- const char *diename = dwarf_diename_integrate(&type_die);
- if (diename != NULL)
+ // if we've gotten down to a basic type, then we're done
+ bool done = true;
+ switch (dwarf_tag(&type_die))
{
- switch (dwarf_tag(&type_die))
- {
- case DW_TAG_structure_type:
- c_type.append("struct ");
- break;
- case DW_TAG_union_type:
- c_type.append("union ");
- break;
- }
- c_type.append(diename);
+ case DW_TAG_structure_type:
+ c_type.append("struct ");
+ break;
+ case DW_TAG_union_type:
+ c_type.append("union ");
+ break;
+ case DW_TAG_typedef:
+ case DW_TAG_base_type:
+ break;
+ default:
+ done = false;
+ break;
+ }
+ if (done)
+ {
+ c_type.append(dwarf_diename_integrate(&type_die));
return true;
}
// otherwise, this die is a type modifier.
// recurse into the referent type
+ // if it can't be named, just call it "void"
Dwarf_Attribute subtype_attr;
Dwarf_Die subtype_die;
if (!dwarf_attr_integrate(&type_die, DW_AT_type, &subtype_attr)
|| !dwarf_formref_die(&subtype_attr, &subtype_die)
|| !dwarf_type_name(subtype_die, c_type))
- return false;
+ c_type = "void";
const char *suffix = NULL;
switch (dwarf_tag(&type_die))
@@ -9636,33 +7529,47 @@ dwarf_type_name(Dwarf_Die& type_die, string& c_type)
return false;
}
c_type.append(suffix);
+
+ // XXX HACK! The va_list isn't usable as found in the debuginfo...
+ if (c_type == "struct __va_list_tag*")
+ c_type = "va_list";
+
return true;
}
static bool
-resolve_tracepoint_arg_type(Dwarf_Die& type_die, bool& isptr)
+resolve_tracepoint_arg_type(tracepoint_arg& arg)
{
Dwarf_Attribute type_attr;
- switch (dwarf_tag(&type_die))
+ switch (dwarf_tag(&arg.type_die))
{
case DW_TAG_typedef:
case DW_TAG_const_type:
case DW_TAG_volatile_type:
// iterate on the referent type
- return (dwarf_attr_integrate(&type_die, DW_AT_type, &type_attr)
- && dwarf_formref_die(&type_attr, &type_die)
- && resolve_tracepoint_arg_type(type_die, isptr));
+ return (dwarf_attr_integrate(&arg.type_die, DW_AT_type, &type_attr)
+ && dwarf_formref_die(&type_attr, &arg.type_die)
+ && resolve_tracepoint_arg_type(arg));
case DW_TAG_base_type:
// base types will simply be treated as script longs
- isptr = false;
+ arg.isptr = false;
return true;
case DW_TAG_pointer_type:
- // pointers can be either script longs,
- // or dereferenced with their referent type
- isptr = true;
- return (dwarf_attr_integrate(&type_die, DW_AT_type, &type_attr)
- && dwarf_formref_die(&type_attr, &type_die));
+ // pointers can be treated as script longs,
+ // and if we know their type, they can also be dereferenced
+ if (dwarf_attr_integrate(&arg.type_die, DW_AT_type, &type_attr)
+ && dwarf_formref_die(&type_attr, &arg.type_die))
+ arg.isptr = true;
+ arg.typecast = "(intptr_t)";
+ return true;
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ // for structs/unions which are passed by value, we turn it into
+ // a pointer that can be dereferenced.
+ arg.isptr = true;
+ arg.typecast = "(intptr_t)&";
+ return true;
default:
// should we consider other types too?
return false;
@@ -9686,12 +7593,12 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die)
Dwarf_Attribute type_attr;
if (!dwarf_attr_integrate (&arg, DW_AT_type, &type_attr)
|| !dwarf_formref_die (&type_attr, &tparg.type_die)
- || !dwarf_type_name(tparg.type_die, tparg.c_type)
- || !resolve_tracepoint_arg_type(tparg.type_die, tparg.isptr))
+ || !dwarf_type_name(tparg.type_die, tparg.c_type))
throw semantic_error ("cannot get type of tracepoint '"
+ tracepoint_name + "' parameter '"
+ tparg.name + "'");
+ tparg.usable = resolve_tracepoint_arg_type(tparg);
args.push_back(tparg);
if (sess.verbose > 4)
clog << "found parameter for tracepoint '" << tracepoint_name
@@ -9704,8 +7611,9 @@ tracepoint_derived_probe::build_args(dwflpp& dw, Dwarf_Die& func_die)
void
tracepoint_derived_probe::printargs(std::ostream &o) const
{
- for (unsigned i = 0; i < args.size(); ++i)
- o << " $" << args[i].name << ":" << args[i].c_type;
+ for (unsigned i = 0; i < args.size(); ++i)
+ if (args[i].usable)
+ o << " $" << args[i].name << ":" << args[i].c_type;
}
void
@@ -9718,6 +7626,15 @@ tracepoint_derived_probe::join_group (systemtap_session& s)
void
+tracepoint_derived_probe::print_dupe_stamp(ostream& o)
+{
+ for (unsigned i = 0; i < args.size(); i++)
+ if (args[i].used)
+ o << "__tracepoint_arg_" << args[i].name << endl;
+}
+
+
+void
tracepoint_derived_probe::emit_probe_context_vars (translator_output* o)
{
for (unsigned i = 0; i < args.size(); i++)
@@ -9726,6 +7643,16 @@ tracepoint_derived_probe::emit_probe_context_vars (translator_output* o)
}
+static vector<string> tracepoint_extra_headers ()
+{
+ vector<string> they_live;
+ // PR 9993
+ // XXX: may need this to be configurable
+ they_live.push_back ("linux/skbuff.h");
+ return they_live;
+}
+
+
void
tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
{
@@ -9735,6 +7662,12 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "/* ---- tracepoint probes ---- */";
s.op->newline();
+ // PR9993: Add extra headers to work around undeclared types in individual
+ // include/trace/foo.h files
+ const vector<string>& extra_headers = tracepoint_extra_headers ();
+ for (unsigned z=0; z<extra_headers.size(); z++)
+ s.op->newline() << "#include <" << extra_headers[z] << ">\n";
+
for (unsigned i = 0; i < probes.size(); ++i)
{
tracepoint_derived_probe *p = probes[i];
@@ -9743,6 +7676,8 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
// don't provide any sort of context pointer.
s.op->newline() << "#include <" << p->header << ">";
s.op->newline() << "static void enter_tracepoint_probe_" << i << "(";
+ if (p->args.size() == 0)
+ s.op->line() << "void";
for (unsigned j = 0; j < p->args.size(); ++j)
{
if (j > 0)
@@ -9761,8 +7696,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
{
s.op->newline() << "c->locals[0]." << p->name << ".__tracepoint_arg_"
<< p->args[j].name << " = (int64_t)";
- if (p->args[j].isptr)
- s.op->line() << "(intptr_t)";
+ s.op->line() << p->args[j].typecast;
s.op->line() << "__tracepoint_arg_" << p->args[j].name << ";";
}
s.op->newline() << p->name << " (c);";
@@ -9774,8 +7708,13 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline(1) << "return register_trace_" << p->tracepoint_name
<< "(enter_tracepoint_probe_" << i << ");";
s.op->newline(-1) << "}";
- s.op->newline() << "static int unregister_tracepoint_probe_" << i << "(void) {";
- s.op->newline(1) << "return unregister_trace_" << p->tracepoint_name
+
+ // NB: we're not prepared to deal with unreg failures. However, failures
+ // can only occur if the tracepoint doesn't exist (yet?), or if we
+ // weren't even registered. The former should be OKed by the initial
+ // registration call, and the latter is safe to ignore.
+ s.op->newline() << "static void unregister_tracepoint_probe_" << i << "(void) {";
+ s.op->newline(1) << "(void) unregister_trace_" << p->tracepoint_name
<< "(enter_tracepoint_probe_" << i << ");";
s.op->newline(-1) << "}";
s.op->newline();
@@ -9784,7 +7723,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
// emit an array of registration functions for easy init/shutdown
s.op->newline() << "static struct stap_tracepoint_probe {";
s.op->newline(1) << "int (*reg)(void);";
- s.op->newline(0) << "int (*unreg)(void);";
+ s.op->newline(0) << "void (*unreg)(void);";
s.op->newline(-1) << "} stap_tracepoint_probes[] = {";
s.op->indent(1);
for (unsigned i = 0; i < probes.size(); ++i)
@@ -9926,6 +7865,7 @@ private:
bool init_dw(systemtap_session& s);
public:
+
tracepoint_builder(): dw(0) {}
~tracepoint_builder() { delete dw; }
@@ -9950,12 +7890,43 @@ tracepoint_builder::init_dw(systemtap_session& s)
if (dw != NULL)
return true;
+ if (s.use_cache)
+ {
+ // see if the cached module exists
+ find_tracequery_hash(s);
+ if (!s.tracequery_path.empty())
+ {
+ int fd = open(s.tracequery_path.c_str(), O_RDONLY);
+ if (fd != -1)
+ {
+ if (s.verbose > 2)
+ clog << "Pass 2: using cached " << s.tracequery_path << endl;
+
+ dw = new dwflpp(s);
+ dw->setup_user(s.tracequery_path);
+ close(fd);
+ return true;
+ }
+ }
+ }
+
+ // no cached module, time to make it
string tracequery_ko;
- int rc = make_tracequery(s, tracequery_ko);
+ int rc = make_tracequery(s, tracequery_ko, tracepoint_extra_headers());
if (rc != 0)
return false;
- // TODO cache tracequery.ko
+ if (s.use_cache)
+ {
+ // try to save tracequery in the cache
+ if (s.verbose > 2)
+ clog << "Copying " << tracequery_ko
+ << " to " << s.tracequery_path << endl;
+ if (copy_file(tracequery_ko.c_str(),
+ s.tracequery_path.c_str()) != 0)
+ cerr << "Copy failed (\"" << tracequery_ko << "\" to \""
+ << s.tracequery_path << "\"): " << strerror(errno) << endl;
+ }
dw = new dwflpp(s);
dw->setup_user(tracequery_ko);
@@ -9982,745 +7953,20 @@ tracepoint_builder::build(systemtap_session& s,
// ------------------------------------------------------------------------
-// hrtimer derived probes
-// ------------------------------------------------------------------------
-// This is a new timer interface that provides more flexibility in specifying
-// intervals, and uses the hrtimer APIs when available for greater precision.
-// While hrtimers were added in 2.6.16, the API's weren't exported until
-// 2.6.17, so we must check this kernel version before attempting to use
-// hrtimers.
-//
-// * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
-
-
-struct hrtimer_derived_probe: public derived_probe
-{
- // set a (generous) maximum of one day in ns
- static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL;
-
- // 100us seems like a reasonable minimum
- static const int64_t min_ns_interval = 100000LL;
-
- int64_t interval, randomize;
-
- hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r):
- derived_probe (p, l), interval (i), randomize (r)
- {
- if ((i < min_ns_interval) || (i > max_ns_interval))
- throw semantic_error("interval value out of range");
-
- // randomize = 0 means no randomization
- if ((r < 0) || (r > i))
- throw semantic_error("randomization value out of range");
- }
-
- void join_group (systemtap_session& s);
-};
-
-
-struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
-{
- void emit_interval (translator_output* o);
-public:
- void emit_module_decls (systemtap_session& s);
- void emit_module_init (systemtap_session& s);
- void emit_module_exit (systemtap_session& s);
-};
-
-
-void
-hrtimer_derived_probe::join_group (systemtap_session& s)
-{
- if (! s.hrtimer_derived_probes)
- s.hrtimer_derived_probes = new hrtimer_derived_probe_group ();
- s.hrtimer_derived_probes->enroll (this);
-}
-
-
-void
-hrtimer_derived_probe_group::emit_interval (translator_output* o)
-{
- o->line() << "({";
- o->newline(1) << "unsigned long nsecs;";
- o->newline() << "int64_t i = stp->intrv;";
- o->newline() << "if (stp->rnd != 0) {";
- // XXX: why not use stp_random_pm instead of this?
- o->newline(1) << "int64_t r;";
- o->newline() << "get_random_bytes(&r, sizeof(r));";
- // ensure that r is positive
- o->newline() << "r &= ((uint64_t)1 << (8*sizeof(r) - 1)) - 1;";
- o->newline() << "r = _stp_mod64(NULL, r, (2*stp->rnd+1));";
- o->newline() << "r -= stp->rnd;";
- o->newline() << "i += r;";
- o->newline(-1) << "}";
- o->newline() << "if (unlikely(i < stap_hrtimer_resolution))";
- o->newline(1) << "i = stap_hrtimer_resolution;";
- o->indent(-1);
- o->newline() << "nsecs = do_div(i, NSEC_PER_SEC);";
- o->newline() << "ktime_set(i, nsecs);";
- o->newline(-1) << "})";
-}
-
-
-void
-hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "/* ---- hrtimer probes ---- */";
-
- s.op->newline() << "static unsigned long stap_hrtimer_resolution;"; // init later
- s.op->newline() << "static struct stap_hrtimer_probe {";
- s.op->newline(1) << "struct hrtimer hrtimer;";
- s.op->newline() << "const char *pp;";
- s.op->newline() << "void (*ph) (struct context*);";
- s.op->newline() << "int64_t intrv, rnd;";
- s.op->newline(-1) << "} stap_hrtimer_probes [" << probes.size() << "] = {";
- s.op->indent(1);
- for (unsigned i=0; i < probes.size(); i++)
- {
- s.op->newline () << "{";
- s.op->line() << " .pp=" << lex_cast_qstring (*probes[i]->sole_location()) << ",";
- s.op->line() << " .ph=&" << probes[i]->name << ",";
- s.op->line() << " .intrv=" << probes[i]->interval << "LL,";
- s.op->line() << " .rnd=" << probes[i]->randomize << "LL";
- s.op->line() << " },";
- }
- s.op->newline(-1) << "};";
- s.op->newline();
-
- // autoconf: add get/set expires if missing (pre 2.6.28-rc1)
- s.op->newline() << "#ifndef STAPCONF_HRTIMER_GETSET_EXPIRES";
- s.op->newline() << "#define hrtimer_get_expires(timer) ((timer)->expires)";
- s.op->newline() << "#define hrtimer_set_expires(timer, time) (void)((timer)->expires = (time))";
- s.op->newline() << "#endif";
-
- // autoconf: adapt to HRTIMER_REL -> HRTIMER_MODE_REL renaming near 2.6.21
- s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
- s.op->newline() << "#define HRTIMER_MODE_REL HRTIMER_REL";
- s.op->newline() << "#endif";
-
- // The function signature changed in 2.6.21.
- s.op->newline() << "#ifdef STAPCONF_HRTIMER_REL";
- s.op->newline() << "static int ";
- s.op->newline() << "#else";
- s.op->newline() << "static enum hrtimer_restart ";
- s.op->newline() << "#endif";
- s.op->newline() << "enter_hrtimer_probe (struct hrtimer *timer) {";
-
- s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
- s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
- s.op->newline() << "if ((atomic_read (&session_state) == STAP_SESSION_STARTING) ||";
- s.op->newline() << " (atomic_read (&session_state) == STAP_SESSION_RUNNING)) {";
- // Compute next trigger time
- s.op->newline(1) << "hrtimer_set_expires(timer, ktime_add (hrtimer_get_expires(timer),";
- emit_interval (s.op);
- s.op->line() << "));";
- s.op->newline() << "rc = HRTIMER_RESTART;";
- s.op->newline(-1) << "}";
- s.op->newline() << "{";
- s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp->pp");
- s.op->newline() << "(*stp->ph) (c);";
- common_probe_entryfn_epilogue (s.op);
- s.op->newline(-1) << "}";
- s.op->newline() << "return rc;";
- s.op->newline(-1) << "}";
-}
-
-
-void
-hrtimer_derived_probe_group::emit_module_init (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "{";
- s.op->newline(1) << "struct timespec res;";
- s.op->newline() << "hrtimer_get_res (CLOCK_MONOTONIC, &res);";
- s.op->newline() << "stap_hrtimer_resolution = timespec_to_ns (&res);";
- s.op->newline(-1) << "}";
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
- s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
- s.op->newline() << "probe_point = stp->pp;";
- s.op->newline() << "hrtimer_init (& stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);";
- s.op->newline() << "stp->hrtimer.function = & enter_hrtimer_probe;";
- // There is no hrtimer field to identify *this* (i-th) probe handler
- // callback. So instead we'll deduce it at entry time.
- s.op->newline() << "(void) hrtimer_start (& stp->hrtimer, ";
- emit_interval (s.op);
- s.op->line() << ", HRTIMER_MODE_REL);";
- // Note: no partial failure rollback is needed: hrtimer_start only
- // "fails" if the timer was already active, which cannot be.
- s.op->newline(-1) << "}"; // for loop
-}
-
-
-void
-hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s)
-{
- if (probes.empty()) return;
-
- s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "hrtimer_cancel (& stap_hrtimer_probes[i].hrtimer);";
- s.op->indent(-1);
-}
-
-
-
-struct timer_builder: public derived_probe_builder
-{
- virtual void build(systemtap_session & sess,
- probe * base, probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results);
-
- static void register_patterns(systemtap_session& s);
-};
-
-void
-timer_builder::build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
-{
- int64_t period, rand=0;
-
- if (!get_param(parameters, "randomize", rand))
- rand = 0;
-
- if (get_param(parameters, "jiffies", period))
- {
- // always use basic timers for jiffies
- finished_results.push_back(
- new timer_derived_probe(base, location, period, rand, false));
- return;
- }
- else if (get_param(parameters, "hz", period))
- {
- if (period <= 0)
- throw semantic_error ("frequency must be greater than 0");
- period = (1000000000 + period - 1)/period;
- }
- else if (get_param(parameters, "s", period)
- || get_param(parameters, "sec", period))
- {
- period *= 1000000000;
- rand *= 1000000000;
- }
- else if (get_param(parameters, "ms", period)
- || get_param(parameters, "msec", period))
- {
- period *= 1000000;
- rand *= 1000000;
- }
- else if (get_param(parameters, "us", period)
- || get_param(parameters, "usec", period))
- {
- period *= 1000;
- rand *= 1000;
- }
- else if (get_param(parameters, "ns", period)
- || get_param(parameters, "nsec", period))
- {
- // ok
- }
- else
- throw semantic_error ("unrecognized timer variant");
-
- // Redirect wallclock-time based probes to hrtimer code on recent
- // enough kernels.
- if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0)
- {
- // hrtimers didn't exist, so use the old-school timers
- period = (period + 1000000 - 1)/1000000;
- rand = (rand + 1000000 - 1)/1000000;
-
- finished_results.push_back(
- new timer_derived_probe(base, location, period, rand, true));
- }
- else
- finished_results.push_back(
- new hrtimer_derived_probe(base, location, period, rand));
-}
-
-void
-timer_builder::register_patterns(systemtap_session& s)
-{
- match_node* root = s.pattern_root;
- derived_probe_builder *builder = new timer_builder();
-
- root = root->bind(TOK_TIMER);
-
- root->bind_num("s")->bind(builder);
- root->bind_num("s")->bind_num("randomize")->bind(builder);
- root->bind_num("sec")->bind(builder);
- root->bind_num("sec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("ms")->bind(builder);
- root->bind_num("ms")->bind_num("randomize")->bind(builder);
- root->bind_num("msec")->bind(builder);
- root->bind_num("msec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("us")->bind(builder);
- root->bind_num("us")->bind_num("randomize")->bind(builder);
- root->bind_num("usec")->bind(builder);
- root->bind_num("usec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("ns")->bind(builder);
- root->bind_num("ns")->bind_num("randomize")->bind(builder);
- root->bind_num("nsec")->bind(builder);
- root->bind_num("nsec")->bind_num("randomize")->bind(builder);
-
- root->bind_num("jiffies")->bind(builder);
- root->bind_num("jiffies")->bind_num("randomize")->bind(builder);
-
- root->bind_num("hz")->bind(builder);
-}
-
-
-
-// ------------------------------------------------------------------------
-// perfmon derived probes
-// ------------------------------------------------------------------------
-// This is a new interface to the perfmon hw.
-//
-
-
-struct perfmon_var_expanding_visitor: public var_expanding_visitor
-{
- systemtap_session & sess;
- unsigned counter_number;
- perfmon_var_expanding_visitor(systemtap_session & s, unsigned c):
- sess(s), counter_number(c) {}
- void visit_target_symbol (target_symbol* e);
-};
-
-
-void
-perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- // Synthesize a function.
- functiondecl *fdecl = new functiondecl;
- fdecl->tok = e->tok;
- embeddedcode *ec = new embeddedcode;
- ec->tok = e->tok;
- bool lvalue = is_active_lvalue(e);
-
- if (lvalue )
- throw semantic_error("writes to $counter not permitted");
-
- string fname = string("_perfmon_tvar_get")
- + "_" + e->base_name.substr(1)
- + "_" + lex_cast<string>(counter_number);
-
- if (e->base_name != "$counter")
- throw semantic_error ("target variables not available to perfmon probes");
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("perfmon probe '$counter' variable may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("perfmon probe '$counter' variable may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of perfmon probe '$counter' variable",
- e->tok);
- break;
- }
- }
-
- ec->code = "THIS->__retvalue = _pfm_pmd_x[" +
- lex_cast<string>(counter_number) + "].reg_num;";
- ec->code += "/* pure */";
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_long;
- sess.functions[fdecl->name]=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 (n);
-}
-
-
-enum perfmon_mode
-{
- perfmon_count,
- perfmon_sample
-};
-
-
-struct perfmon_derived_probe: public derived_probe
-{
-protected:
- static unsigned probes_allocated;
-
-public:
- systemtap_session & sess;
- string event;
- perfmon_mode mode;
-
- perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s,
- string e, perfmon_mode m);
- virtual void join_group (systemtap_session& s);
-};
-
-
-struct perfmon_derived_probe_group: public generic_dpg<perfmon_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session&) {}
- void emit_module_init (systemtap_session&) {}
- void emit_module_exit (systemtap_session&) {}
-};
-
-
-struct perfmon_builder: public derived_probe_builder
-{
- perfmon_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
- {
- string event;
- if (!get_param (parameters, "counter", event))
- throw semantic_error("perfmon requires an event");
-
- sess.perfmon++;
-
- // XXX: need to revise when doing sampling
- finished_results.push_back(new perfmon_derived_probe(base, location,
- sess, event,
- perfmon_count));
- }
-};
-
-
-unsigned perfmon_derived_probe::probes_allocated;
-
-perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
- systemtap_session &s,
- string e, perfmon_mode m)
- : derived_probe (p, l), sess(s), event(e), mode(m)
-{
- ++probes_allocated;
-
- // Now expand the local variables in the probe body
- perfmon_var_expanding_visitor v (sess, probes_allocated-1);
- this->body = v.require (this->body);
-
- if (sess.verbose > 1)
- clog << "perfmon-based probe" << endl;
-}
-
-
-void
-perfmon_derived_probe::join_group (systemtap_session& s)
-{
- throw semantic_error ("incomplete", this->tok);
-
- if (! s.perfmon_derived_probes)
- s.perfmon_derived_probes = new perfmon_derived_probe_group ();
- s.perfmon_derived_probes->enroll (this);
-}
-
-
-#if 0
-void
-perfmon_derived_probe::emit_registrations_start (translator_output* o,
- unsigned index)
-{
- for (unsigned i=0; i<locations.size(); i++)
- o->newline() << "enter_" << name << "_" << i << " ();";
-}
-
-
-void
-perfmon_derived_probe::emit_registrations_end (translator_output * o,
- unsigned index)
-{
-}
-
-
-void
-perfmon_derived_probe::emit_deregistrations (translator_output * o)
-{
-}
-
-
-void
-perfmon_derived_probe::emit_probe_entries (translator_output * o)
-{
- o->newline() << "#ifdef STP_TIMING";
- // NB: This variable may be multiply (but identically) defined.
- o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";";
- o->newline() << "#endif";
-
- for (unsigned i=0; i<locations.size(); i++)
- {
- probe_point *l = locations[i];
- o->newline() << "/* location " << i << ": " << *l << " */";
- o->newline() << "static void enter_" << name << "_" << i << " (void) {";
-
- o->indent(1);
- o->newline() << "const char* probe_point = "
- << lex_cast_qstring(*l) << ";";
- emit_probe_prologue (o,
- (mode == perfmon_count ?
- "STAP_SESSION_STARTING" :
- "STAP_SESSION_RUNNING"),
- "probe_point");
-
- // NB: locals are initialized by probe function itself
- o->newline() << name << " (c);";
-
- emit_probe_epilogue (o);
-
- o->newline(-1) << "}\n";
- }
-}
-#endif
-
-
-#if 0
-void no_pfm_event_error (string s)
-{
- string msg(string("Cannot find event:" + s));
- throw semantic_error(msg);
-}
-
-
-void no_pfm_mask_error (string s)
-{
- string msg(string("Cannot find mask:" + s));
- throw semantic_error(msg);
-}
-
-
-void
-split(const string& s, vector<string>& v, const string & separator)
-{
- string::size_type last_pos = s.find_first_not_of(separator, 0);
- string::size_type pos = s.find_first_of(separator, last_pos);
-
- while (string::npos != pos || string::npos != last_pos) {
- v.push_back(s.substr(last_pos, pos - last_pos));
- last_pos = s.find_first_not_of(separator, pos);
- pos = s.find_first_of(separator, last_pos);
- }
-}
-
-
-void
-perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up)
-{
- for (unsigned i=0; i < probes.size(); i++)
- {
- op->newline ();
- up->emit_probe (probes[i]);
- }
-}
-
-
-void
-perfmon_derived_probe_group::emit_module_init (translator_output* o)
-{
- int ret;
- pfmlib_input_param_t inp;
- pfmlib_output_param_t outp;
- pfarg_pmd_t pd[PFMLIB_MAX_PMDS];
- pfarg_pmc_t pc[PFMLIB_MAX_PMCS];
- pfarg_ctx_t ctx;
- pfarg_load_t load_args;
- pfmlib_options_t pfmlib_options;
- unsigned int max_counters;
-
- if ( probes.size() == 0)
- return;
- ret = pfm_initialize();
- if (ret != PFMLIB_SUCCESS)
- throw semantic_error("Unable to generate performance monitoring events (no libpfm)");
-
- pfm_get_num_counters(&max_counters);
-
- memset(&pfmlib_options, 0, sizeof(pfmlib_options));
- pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
- pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */
- pfm_set_options(&pfmlib_options);
-
- memset(pd, 0, sizeof(pd));
- memset(pc, 0, sizeof(pc));
- memset(&ctx, 0, sizeof(ctx));
- memset(&load_args, 0, sizeof(load_args));
-
- /*
- * prepare parameters to library.
- */
- memset(&inp,0, sizeof(inp));
- memset(&outp,0, sizeof(outp));
-
- /* figure out the events */
- for (unsigned i=0; i<probes.size(); ++i)
- {
- if (probes[i]->event == "cycles") {
- if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS)
- no_pfm_event_error(probes[i]->event);
- } else if (probes[i]->event == "instructions") {
- if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) !=
- PFMLIB_SUCCESS)
- no_pfm_event_error(probes[i]->event);
- } else {
- unsigned int event_id = 0;
- unsigned int mask_id = 0;
- vector<string> event_spec;
- split(probes[i]->event, event_spec, ":");
- int num = event_spec.size();
- int masks = num - 1;
-
- if (num == 0)
- throw semantic_error("No events found");
-
- /* setup event */
- if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS)
- no_pfm_event_error(event_spec[0]);
- inp.pfp_events[i].event = event_id;
-
- /* set up masks */
- if (masks > PFMLIB_MAX_MASKS_PER_EVENT)
- throw semantic_error("Too many unit masks specified");
-
- for (int j=0; j < masks; j++) {
- if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(),
- &mask_id) != PFMLIB_SUCCESS)
- no_pfm_mask_error(string(event_spec[j+1]));
- inp.pfp_events[i].unit_masks[j] = mask_id;
- }
- inp.pfp_events[i].num_masks = masks;
- }
- }
-
- /* number of counters in use */
- inp.pfp_event_count = probes.size();
-
- // XXX: no elimination of duplicated counters
- if (inp.pfp_event_count>max_counters)
- throw semantic_error("Too many performance monitoring events.");
-
- /* count events both in kernel and user-space */
- inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3;
-
- /* XXX: some cases a perfmon register might be used of watch dog
- this code doesn't handle that case */
-
- /* figure out the pmcs for the events */
- if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
- throw semantic_error("Cannot configure events");
-
- for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
- pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
- pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
- }
-
- /*
- * There could be more pmc settings than pmd.
- * Figure out the actual pmds to use.
- */
- for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) {
- pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num;
- for(; j < outp.pfp_pmc_count; j++)
- if (outp.pfp_pmcs[j].reg_evt_idx != i) break;
- }
-
- // Output the be probes create function
- o->newline() << "static int register_perfmon_probes (void) {";
- o->newline(1) << "int rc = 0;";
-
- o->newline() << "/* data for perfmon */";
- o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";";
- o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count
- << "] = {";
- /* output the needed bits for pmc here */
- for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
- o->newline() << "{.reg_num=" << pc[i].reg_num << ", "
- << ".reg_value=" << lex_cast_hex<string>(pc[i].reg_value)
- << "},";
- }
-
- o->newline() << "};";
- o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";";
- o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count
- << "] = {";
- /* output the needed bits for pmd here */
- for (unsigned i=0; i < inp.pfp_event_count; i++) {
- o->newline() << "{.reg_num=" << pd[i].reg_num << ", "
- << ".reg_value=" << pd[i].reg_value << "},";
- }
- o->newline() << "};";
- o->newline();
-
- o->newline() << "_pfm_pmc_x=_pfm_pmc;";
- o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;";
- o->newline() << "_pfm_pmd_x=_pfm_pmd;";
- o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;";
-
- // call all the function bodies associated with perfcounters
- for (unsigned i=0; i < probes.size (); i++)
- probes[i]->emit_registrations_start (o,i);
-
- /* generate call to turn on instrumentation */
- o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;";
- o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,";
- o->newline(1) << "_pfm_pmc, _pfm_num_pmc,";
- o->newline() << "_pfm_pmd, _pfm_num_pmd);";
- o->newline(-1);
-
- o->newline() << "return rc;";
- o->newline(-1) << "}\n";
-
- // Output the be probes destroy function
- o->newline() << "static void unregister_perfmon_probes (void) {";
- o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);";
- o->newline(-1) << "}\n";
-}
-#endif
-
-
-// ------------------------------------------------------------------------
// Standard tapset registry.
// ------------------------------------------------------------------------
void
register_standard_tapsets(systemtap_session & s)
{
- s.pattern_root->bind(TOK_BEGIN)->bind(new be_builder(BEGIN));
- s.pattern_root->bind_num(TOK_BEGIN)->bind(new be_builder(BEGIN));
- s.pattern_root->bind(TOK_END)->bind(new be_builder(END));
- s.pattern_root->bind_num(TOK_END)->bind(new be_builder(END));
- s.pattern_root->bind(TOK_ERROR)->bind(new be_builder(ERROR));
- s.pattern_root->bind_num(TOK_ERROR)->bind(new be_builder(ERROR));
-
- s.pattern_root->bind(TOK_NEVER)->bind(new never_builder());
+ register_tapset_been(s);
+ register_tapset_itrace(s);
+ register_tapset_mark(s);
+ register_tapset_perfmon(s);
+ register_tapset_procfs(s);
+ register_tapset_timers(s);
+ register_tapset_utrace(s);
- timer_builder::register_patterns(s);
- s.pattern_root->bind(TOK_TIMER)->bind("profile")->bind(new profile_builder());
- s.pattern_root->bind("perfmon")->bind_str("counter")
- ->bind(new perfmon_builder());
// dwarf-based kprobe/uprobe parts
dwarf_derived_probe::register_patterns(s);
@@ -10733,67 +7979,26 @@ 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(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_BEGIN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_THREAD)->bind(TOK_END)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_str(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
- ->bind(new utrace_builder ());
- s.pattern_root->bind(TOK_PROCESS)->bind(TOK_SYSCALL)->bind(TOK_RETURN)
- ->bind(new utrace_builder ());
-
- // itrace user-space probes
- s.pattern_root->bind_str(TOK_PROCESS)->bind("itrace")
- ->bind(new itrace_builder ());
- s.pattern_root->bind_num(TOK_PROCESS)->bind("itrace")
- ->bind(new itrace_builder ());
-
- // marker-based parts
- s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)
- ->bind(new mark_builder());
- s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)->bind_str(TOK_FORMAT)
- ->bind(new mark_builder());
-
// kernel tracepoint probes
s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE)
->bind(new tracepoint_builder());
- // procfs parts
- s.pattern_root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(new procfs_builder());
- s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_READ)
- ->bind(new procfs_builder());
- s.pattern_root->bind(TOK_PROCFS)->bind(TOK_WRITE)->bind(new procfs_builder());
- s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_WRITE)
- ->bind(new procfs_builder());
+ // Kprobe based probe
+ s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)
+ ->bind(new kprobe_builder());
+ s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
+ ->bind_str(TOK_FUNCTION)->bind(new kprobe_builder());
+ s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)
+ ->bind(new kprobe_builder());
+ s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)
+ ->bind_num(TOK_MAXACTIVE)->bind(new kprobe_builder());
+ s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
+ ->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)->bind(new kprobe_builder());
+ s.pattern_root->bind(TOK_KPROBE)->bind_str(TOK_MODULE)
+ ->bind_str(TOK_FUNCTION)->bind(TOK_RETURN)
+ ->bind_num(TOK_MAXACTIVE)->bind(new kprobe_builder());
+ s.pattern_root->bind(TOK_KPROBE)->bind_num(TOK_STATEMENT)
+ ->bind(TOK_ABSOLUTE)->bind(new kprobe_builder());
}
@@ -10801,7 +8006,10 @@ vector<derived_probe_group*>
all_session_groups(systemtap_session& s)
{
vector<derived_probe_group*> g;
-#define DOONE(x) if (s. x##_derived_probes) g.push_back (s. x##_derived_probes)
+
+#define DOONE(x) \
+ if (s. x##_derived_probes) \
+ g.push_back ((derived_probe_group*)(s. x##_derived_probes))
// Note that order *is* important here. We want to make sure we
// register (actually run) begin probes before any other probe type
@@ -10816,6 +8024,7 @@ all_session_groups(systemtap_session& s)
DOONE(profile);
DOONE(mark);
DOONE(tracepoint);
+ DOONE(kprobe);
DOONE(hrtimer);
DOONE(perfmon);
DOONE(procfs);
diff --git a/tapsets.h b/tapsets.h
index 7165244b..7a74ad31 100644
--- a/tapsets.h
+++ b/tapsets.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-// Copyright (C) 2005 Red Hat Inc.
+// Copyright (C) 2005, 2009 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
@@ -13,11 +13,47 @@
#include "staptree.h"
#include "elaborate.h"
-struct derived_probe_group;
-
void register_standard_tapsets(systemtap_session& sess);
std::vector<derived_probe_group*> all_session_groups(systemtap_session& s);
+int dwfl_report_offline_predicate (const char* modname, const char* filename);
+void common_probe_entryfn_prologue (translator_output* o, std::string statestr,
+ std::string new_pp, bool overload_processing = true);
+void common_probe_entryfn_epilogue (translator_output* o, bool overload_processing = true);
+
+void register_tapset_been(systemtap_session& sess);
+void register_tapset_itrace(systemtap_session& sess);
+void register_tapset_mark(systemtap_session& sess);
+void register_tapset_perfmon(systemtap_session& sess);
+void register_tapset_procfs(systemtap_session& sess);
+void register_tapset_timers(systemtap_session& sess);
+void register_tapset_utrace(systemtap_session& sess);
+
+
+// ------------------------------------------------------------------------
+// Generic derived_probe_group: contains an ordinary vector of the
+// given type. It provides only the enrollment function.
+
+template <class DP> struct generic_dpg: public derived_probe_group
+{
+protected:
+ std::vector <DP*> probes;
+public:
+ generic_dpg () {}
+ void enroll (DP* probe) { probes.push_back (probe); }
+};
+
+
+// ------------------------------------------------------------------------
+// An update visitor that allows replacing assignments with a function call
+
+struct var_expanding_visitor: public update_visitor
+{
+ static unsigned tick;
+ std::stack<functioncall**> target_symbol_setter_functioncalls;
+ var_expanding_visitor() {}
+ void visit_assignment (assignment* e);
+};
#endif // TAPSETS_H
diff --git a/task_finder.cxx b/task_finder.cxx
new file mode 100644
index 00000000..de1c2208
--- /dev/null
+++ b/task_finder.cxx
@@ -0,0 +1,103 @@
+// task finder for user tapsets
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// 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 "session.h"
+#include "tapsets.h"
+#include "task_finder.h"
+#include "translate.h"
+#include "util.h"
+
+#include <cstring>
+#include <string>
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+// ------------------------------------------------------------------------
+// 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:
+ 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::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->newline(1) << "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();";
+}
+
+
+// Declare that task_finder is needed in this session
+void
+enable_task_finder(systemtap_session& s)
+{
+ if (! s.task_finder_derived_probes)
+ s.task_finder_derived_probes = new task_finder_derived_probe_group();
+}
+
+// Helper function to emit vma tracker callbacks.
+void
+emit_vma_callback_probe_decl (systemtap_session& s,
+ string path,
+ int64_t pid)
+{
+ s.op->newline() << "{";
+ if (pid == 0)
+ {
+ s.op->line() << " .pathname=\"" << path << "\",";
+ s.op->line() << " .pid=0,";
+ }
+ else
+ {
+ s.op->line() << " .pathname=NULL,";
+ s.op->line() << " .pid=" << pid << ",";
+ }
+ s.op->line() << " .callback=NULL,";
+ s.op->line() << " .mmap_callback=&_stp_tf_mmap_cb,";
+ s.op->line() << " .munmap_callback=&_stp_tf_munmap_cb,";
+ s.op->line() << " .mprotect_callback=NULL,";
+ s.op->line() << " },";
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/task_finder.h b/task_finder.h
new file mode 100644
index 00000000..99419e32
--- /dev/null
+++ b/task_finder.h
@@ -0,0 +1,20 @@
+// -*- C++ -*-
+// Copyright (C) 2009 Red Hat Inc.
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#ifndef TASK_FINDER_H
+#define TASK_FINDER_H
+
+// Declare that task_finder is needed in this session
+void enable_task_finder(systemtap_session& s);
+
+// Helper function to emit vma tracker callbacks.
+void emit_vma_callback_probe_decl (systemtap_session& s, std::string path, int64_t pid);
+
+#endif // TASK_FINDER_H
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 19b30bf1..709de57f 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -2,3 +2,6 @@
site.exp
systemtap.log
systemtap.sum
+*.so
+*_exe
+*.exe.[0-9]
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index 9547479b..c0f0b19c 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -1,8 +1,8 @@
-# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -31,14 +31,16 @@ POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
-subdir = testsuite
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+subdir = .
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
SOURCES =
DEJATOOL = $(PACKAGE)
@@ -48,39 +50,22 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
-CC = @CC@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CXX = @CXX@
-CXXCPP = @CXXCPP@
-CXXDEPMODE = @CXXDEPMODE@
-CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
-DATE = @DATE@
DEFS = @DEFS@
-DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
-LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
-OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
@@ -88,25 +73,15 @@ PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
-PIECFLAGS = @PIECFLAGS@
-PIECXXFLAGS = @PIECXXFLAGS@
-PIELDFLAGS = @PIELDFLAGS@
-PROCFLAGS = @PROCFLAGS@
-RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
-U = @U@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_CXX = @ac_ct_CXX@
-am__include = @am__include@
am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
@@ -114,15 +89,10 @@ build_alias = @build_alias@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dejazilla = @dejazilla@
docdir = @docdir@
dvidir = @dvidir@
-elfutils_abs_srcdir = @elfutils_abs_srcdir@
exec_prefix = @exec_prefix@
-have_dvips = @have_dvips@
-have_latex = @have_latex@
-have_latex2html = @have_latex2html@
-have_ps2pdf = @have_ps2pdf@
-have_xmlto = @have_xmlto@
host_alias = @host_alias@
htmldir = @htmldir@
includedir = @includedir@
@@ -134,8 +104,6 @@ localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
-nspr_CFLAGS = @nspr_CFLAGS@
-nss_CFLAGS = @nss_CFLAGS@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
@@ -143,14 +111,9 @@ program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
-sqlite3_LIBS = @sqlite3_LIBS@
srcdir = @srcdir@
-stap_LIBS = @stap_LIBS@
-staplog_CPPFLAGS = @staplog_CPPFLAGS@
-subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
-top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = dejagnu no-dist
@@ -171,35 +134,39 @@ RUNTEST = "env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMT
all: all-am
.SUFFIXES:
+am--refresh:
+ @:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \
+ cd $(srcdir) && $(AUTOMAKE) --foreign \
&& exit 0; \
exit 1;; \
esac; \
done; \
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu testsuite/Makefile'; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
cd $(top_srcdir) && \
- $(AUTOMAKE) --gnu testsuite/Makefile
+ $(AUTOMAKE) --foreign Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
*) \
- echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
- cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+ $(SHELL) ./config.status --recheck
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+ cd $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
tags: TAGS
TAGS:
@@ -270,6 +237,7 @@ clean: clean-am
clean-am: clean-generic clean-local mostlyclean-am
distclean: distclean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -f Makefile
distclean-am: clean-am distclean-DEJAGNU distclean-generic
@@ -302,6 +270,8 @@ install-ps: install-ps-am
installcheck-am:
maintainer-clean: maintainer-clean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
@@ -321,16 +291,17 @@ uninstall-am:
.MAKE: install-am install-strip
-.PHONY: all all-am all-local check check-DEJAGNU check-am check-local \
- clean clean-generic clean-local distclean distclean-DEJAGNU \
- distclean-generic dvi dvi-am html html-am info info-am install \
- install-am install-data install-data-am install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip installcheck installcheck-am installdirs \
- maintainer-clean maintainer-clean-generic mostlyclean \
- mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am
+.PHONY: all all-am all-local am--refresh check check-DEJAGNU check-am \
+ check-local clean clean-generic clean-local distclean \
+ distclean-DEJAGNU distclean-generic dvi dvi-am html html-am \
+ info info-am install install-am install-data install-data-am \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \
+ uninstall-am
all-local:
diff --git a/testsuite/aclocal.m4 b/testsuite/aclocal.m4
index c9daa488..5aee677e 100644
--- a/testsuite/aclocal.m4
+++ b/testsuite/aclocal.m4
@@ -1,7 +1,7 @@
-# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+# generated automatically by aclocal 1.10 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# 2005, 2006 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -11,15 +11,12 @@
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
-m4_ifndef([AC_AUTOCONF_VERSION],
- [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(AC_AUTOCONF_VERSION, [2.61],,
-[m4_warning([this file was generated for autoconf 2.61.
-You have another version of autoconf. It may work, but is not guaranteed to.
-If you have problems, you may need to regenerate the build system entirely.
-To do so, use the procedure documented by the package, typically `autoreconf'.])])
+m4_if(m4_PACKAGE_VERSION, [2.61],,
+[m4_fatal([this file was generated for autoconf 2.61.
+You have another version of autoconf. If you want to use that,
+you should regenerate the build system entirely.], [63])])
-# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -34,7 +31,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.10'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.10.1], [],
+m4_if([$1], [1.10], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -50,10 +47,8 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.10.1])dnl
-m4_ifndef([AC_AUTOCONF_VERSION],
- [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
+[AM_AUTOMAKE_VERSION([1.10])dnl
+_AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
@@ -146,13 +141,13 @@ fi])])
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2008 Free Software Foundation, Inc.
+# 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
-# serial 13
+# serial 12
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
@@ -257,17 +252,16 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJC],
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
-_am_arg=$1
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
- $_am_arg | $_am_arg:* )
+ $1 | $1:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
-echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
#
@@ -516,7 +510,7 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])])
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
-# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# Prevent Automake from outputing VARIABLE = @VARIABLE@ in Makefile.in.
# This macro is traced by Automake.
AC_DEFUN([_AM_SUBST_NOTMAKE])
diff --git a/testsuite/buildko/two.stp b/testsuite/buildko/two.stp
new file mode 100755
index 00000000..25350dc0
--- /dev/null
+++ b/testsuite/buildko/two.stp
@@ -0,0 +1,14 @@
+#! stap -p4
+
+# tests overwide arrays
+global a10
+global b10
+global c10
+global d10
+
+probe begin {
+ a10[0,"a",0,"a",0,"a",0,"a",0,"a"]="a";
+ b10["b",0,"b",0,"b",0,"b",0,"b",0]=0;
+ c10[0,"a",0,"a",0,"a",0,"a",0,"a"]<<<0;
+ d10["b",0,"b",0,"b",0,"b",0,"b",0]<<<0;
+}
diff --git a/testsuite/buildok/context_test.stp b/testsuite/buildok/context_test.stp
index 84f1cbf1..acc4ea07 100755
--- a/testsuite/buildok/context_test.stp
+++ b/testsuite/buildok/context_test.stp
@@ -1,6 +1,6 @@
#! stap -p4
-function print_stuff () {
+probe begin {
print_regs()
print_backtrace()
bt = backtrace()
@@ -18,23 +18,5 @@ function print_stuff () {
printf("gid is %d\n", gid())
printf("egid is %d\n", egid())
printf("pp is %s\n", pp())
-}
-
-probe kernel.function("uptime_read_proc") ? {
- print("NOW IN UPTIME\n")
- print_stuff ()
-}
-
-probe kernel.function("uptime_read_proc").return ? {
- print("DONE WITH UPTIME\n")
- print_stuff ()
- exit ()
-}
-
-probe begin {
- print ("BEGIN\n")
-}
-
-probe end {
- print ("END\n")
+ printf("sid is %d\n", sid())
}
diff --git a/testsuite/buildok/maxactive01.stp b/testsuite/buildok/maxactive01.stp
index afdb2cea..1cf893ef 100755
--- a/testsuite/buildok/maxactive01.stp
+++ b/testsuite/buildok/maxactive01.stp
@@ -1,6 +1,6 @@
#! stap -p4
-probe kernel.function("sys_read").return.maxactive(3)
+probe kernel.function("vfs_read").return.maxactive(3)
{
printf(".");
}
diff --git a/testsuite/buildok/modname.stp b/testsuite/buildok/modname.stp
new file mode 100755
index 00000000..02229301
--- /dev/null
+++ b/testsuite/buildok/modname.stp
@@ -0,0 +1,8 @@
+#! stap -p4
+#
+# Test the translatability for modname()
+#
+probe begin
+{
+ log(modname(0))
+}
diff --git a/testsuite/buildok/process-all-probes.stp b/testsuite/buildok/process-all-probes.stp
index 91a96514..c754462b 100755
--- a/testsuite/buildok/process-all-probes.stp
+++ b/testsuite/buildok/process-all-probes.stp
@@ -2,11 +2,11 @@
// Tests if all probes in the process tapset are resolvable.
-probe process.create,
- process.start,
- process.exec,
- process.exec_complete,
- process.exit,
- process.release
+probe kprocess.create,
+ kprocess.start,
+ kprocess.exec,
+ kprocess.exec_complete,
+ kprocess.exit,
+ kprocess.release
{
}
diff --git a/testsuite/buildok/process_test.stp b/testsuite/buildok/process_test.stp
index 90de8b69..ba3fadf1 100755
--- a/testsuite/buildok/process_test.stp
+++ b/testsuite/buildok/process_test.stp
@@ -1,31 +1,31 @@
#! stap -p4
-probe process.create {
+probe kprocess.create {
log(pp())
log(sprint(task))
}
-probe process.start {
+probe kprocess.start {
log(pp())
}
-probe process.exec {
+probe kprocess.exec {
log(pp())
log(filename)
}
-probe process.exec_complete {
+probe kprocess.exec_complete {
log(pp())
log(sprint(errno))
log(sprint(success))
}
-probe process.exit {
+probe kprocess.exit {
log(pp())
log(sprint(code))
}
-probe process.release {
+probe kprocess.release {
log(pp())
log(sprint(task))
}
diff --git a/testsuite/buildok/seventeen.stp b/testsuite/buildok/seventeen.stp
index 126db1fb..4e0b07c4 100755
--- a/testsuite/buildok/seventeen.stp
+++ b/testsuite/buildok/seventeen.stp
@@ -11,3 +11,12 @@ probe kernel.function("pipe_write")
printf("0x%x\n", $write_fifo_fops->llseek)
%)
}
+
+# PR10000: We're looking for *some* module function that has a nearby global variable in scope
+# XXX: See PR4096
+probe module("nfs").function("nfs_create_client") !, module("nfs").function("nfs_init_client") !,
+ kernel.function("nfs_fsync_dir") {
+ println(kernel_string($nfs_program->name))
+}
+
+probe timer.s(5) { exit() }
diff --git a/testsuite/buildok/symdata.stp b/testsuite/buildok/symdata.stp
new file mode 100755
index 00000000..d7e803a9
--- /dev/null
+++ b/testsuite/buildok/symdata.stp
@@ -0,0 +1,8 @@
+#! stap -p4
+#
+# Test the translatability for symdata()
+#
+probe begin
+{
+ log(symdata(0))
+}
diff --git a/testsuite/buildok/symname.stp b/testsuite/buildok/symname.stp
new file mode 100755
index 00000000..e082d1a5
--- /dev/null
+++ b/testsuite/buildok/symname.stp
@@ -0,0 +1,8 @@
+#! stap -p4
+#
+# Test the translatability for symname()
+#
+probe begin
+{
+ log(symname(0))
+}
diff --git a/testsuite/buildok/task-embedded.stp b/testsuite/buildok/task-embedded.stp
index 4d1f5300..d35f3e0d 100755
--- a/testsuite/buildok/task-embedded.stp
+++ b/testsuite/buildok/task-embedded.stp
@@ -14,6 +14,8 @@ probe begin {
task_nice (0) +
task_cpu (0) +
task_open_file_handles (0) +
- task_max_file_handles (0))
+ task_max_file_handles (0) +
+ pid2task(0))
print (task_execname (0))
+ print (pid2execname (0))
}
diff --git a/testsuite/buildok/task_test.stp b/testsuite/buildok/task_test.stp
index c8da7da5..792f96ea 100755
--- a/testsuite/buildok/task_test.stp
+++ b/testsuite/buildok/task_test.stp
@@ -16,5 +16,7 @@ probe begin {
log(sprint(task_cpu(c)))
log(sprint(task_open_file_handles(c)))
log(sprint(task_max_file_handles(c)))
+ log(sprint(pid2task(pid())))
+ log(sprint(pid2execname(pid())))
exit()
}
diff --git a/testsuite/buildok/tcp_test.stp b/testsuite/buildok/tcp_test.stp
index a262ab29..a5e3bafb 100755
--- a/testsuite/buildok/tcp_test.stp
+++ b/testsuite/buildok/tcp_test.stp
@@ -8,16 +8,16 @@ function print_report()
}
probe tcp.sendmsg {
- ports = inet_get_local_port(sk)
- src_ips = inet_get_ip_source(sk)
- rtos = tcp_get_info_rto(sk)
+ ports = inet_get_local_port(sock)
+ src_ips = inet_get_ip_source(sock)
+ rtos = tcp_get_info_rto(sock)
}
probe tcp.recvmsg {
- cwnd = tcp_get_info_snd_cwnd(sk)
- mss = tcp_ts_get_info_rcv_mss(sk)
- ssthresh = tcp_ts_get_info_snd_ssthresh(sk)
- state = tcp_ts_get_info_state(sk)
+ cwnd = tcp_get_info_snd_cwnd(sock)
+ mss = tcp_ts_get_info_rcv_mss(sock)
+ ssthresh = tcp_ts_get_info_snd_ssthresh(sock)
+ state = tcp_ts_get_info_state(sock)
}
probe tcp.sendmsg.return {
diff --git a/testsuite/buildok/thirteen.stp b/testsuite/buildok/thirteen.stp
index 4dffc4b9..32228e79 100755
--- a/testsuite/buildok/thirteen.stp
+++ b/testsuite/buildok/thirteen.stp
@@ -1,6 +1,6 @@
#! stap -p4
-probe kernel.function("sys_read")
+probe kernel.function("vfs_read")
{
printf ("count=%d\n", $count)
}
diff --git a/testsuite/buildok/thirty.stp b/testsuite/buildok/thirty.stp
new file mode 100755
index 00000000..042bae56
--- /dev/null
+++ b/testsuite/buildok/thirty.stp
@@ -0,0 +1,49 @@
+#! stap -p4
+
+# tests wide arrays
+global a1, a2, a3, a4, a5, a6, a7, a8, a9
+global b1, b2, b3, b4, b5, b6, b7, b8, b9
+global c1, c2, c3, c4, c5, c6, c7, c8, c9
+global d1, d2, d3, d4, d5, d6, d7, d8, d9
+
+probe begin {
+ a1[0]="a";
+ a2[0,"a"]="a";
+ a3[0,"a",0]="a";
+ a4[0,"a",0,"a"]="a";
+ a5[0,"a",0,"a",0]="a";
+ a6[0,"a",0,"a",0,"a"]="a";
+ a7[0,"a",0,"a",0,"a",0]="a";
+ a8[0,"a",0,"a",0,"a",0,"a"]="a";
+ a9[0,"a",0,"a",0,"a",0,"a",0]="a";
+
+ b1["b"]=0;
+ b2["b",0]=0;
+ b3["b",0,"b"]=0;
+ b4["b",0,"b",0]=0;
+ b5["b",0,"b",0,"b"]=0;
+ b6["b",0,"b",0,"b",0]=0;
+ b7["b",0,"b",0,"b",0,"b"]=0;
+ b8["b",0,"b",0,"b",0,"b",0]=0;
+ b9["b",0,"b",0,"b",0,"b",0,"b"]=0;
+
+ c1[0]<<<0;
+ c2[0,"a"]<<<0;
+ c3[0,"a",0]<<<0;
+ c4[0,"a",0,"a"]<<<0;
+ c5[0,"a",0,"a",0]<<<0;
+ c6[0,"a",0,"a",0,"a"]<<<0;
+ c7[0,"a",0,"a",0,"a",0]<<<0;
+ c8[0,"a",0,"a",0,"a",0,"a"]<<<0;
+ c9[0,"a",0,"a",0,"a",0,"a",0]<<<0;
+
+ d1["b"]<<<0;
+ d2["b",0]<<<0;
+ d3["b",0,"b"]<<<0;
+ d4["b",0,"b",0]<<<0;
+ d5["b",0,"b",0,"b"]<<<0;
+ d6["b",0,"b",0,"b",0]<<<0;
+ d7["b",0,"b",0,"b",0,"b"]<<<0;
+ d8["b",0,"b",0,"b",0,"b",0]<<<0;
+ d9["b",0,"b",0,"b",0,"b",0,"b"]<<<0;
+}
diff --git a/testsuite/buildok/thirtyone.stp b/testsuite/buildok/thirtyone.stp
new file mode 100755
index 00000000..8a97d84f
--- /dev/null
+++ b/testsuite/buildok/thirtyone.stp
@@ -0,0 +1,4 @@
+#! stap -p4
+
+probe kprobe.function("sys_open") {}
+probe kernel.function("sys_close") {}
diff --git a/testsuite/buildok/twentysix.stp b/testsuite/buildok/twentysix.stp
deleted file mode 100755
index 3fb7526f..00000000
--- a/testsuite/buildok/twentysix.stp
+++ /dev/null
@@ -1,7 +0,0 @@
-#! stap -up4
-
-global a
-probe begin
-{
- a [1,2,3,4,5,6] = 0
-}
diff --git a/testsuite/buildok/uaddr.stp b/testsuite/buildok/uaddr.stp
new file mode 100755
index 00000000..8acfc495
--- /dev/null
+++ b/testsuite/buildok/uaddr.stp
@@ -0,0 +1,8 @@
+#! stap -p4
+#
+# Test the translatability for uaddr()
+#
+probe begin
+{
+ printf("uaddr: 0x%x\n", uaddr())
+}
diff --git a/testsuite/buildok/ustack.stp b/testsuite/buildok/ustack.stp
new file mode 100755
index 00000000..23af0bff
--- /dev/null
+++ b/testsuite/buildok/ustack.stp
@@ -0,0 +1,10 @@
+#! stap -p4
+#
+# Test the translatability for ubacktrace(), print_ustack()
+# and print_ubacktrace()
+#
+probe begin
+{
+ print_ustack(ubacktrace());
+ print_ubacktrace();
+}
diff --git a/testsuite/buildok/usymdata.stp b/testsuite/buildok/usymdata.stp
new file mode 100755
index 00000000..48c1f36f
--- /dev/null
+++ b/testsuite/buildok/usymdata.stp
@@ -0,0 +1,8 @@
+#! stap -p4
+#
+# Test the translatability for usymdata()
+#
+probe begin
+{
+ log(usymdata(0))
+}
diff --git a/testsuite/buildok/usymname.stp b/testsuite/buildok/usymname.stp
new file mode 100755
index 00000000..57e3f9c2
--- /dev/null
+++ b/testsuite/buildok/usymname.stp
@@ -0,0 +1,8 @@
+#! stap -p4
+#
+# Test the translatability for usymname()
+#
+probe begin
+{
+ log(usymname(0))
+}
diff --git a/testsuite/configure b/testsuite/configure
index 094f99c7..cc73571a 100755
--- a/testsuite/configure
+++ b/testsuite/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for systemtap 0.9.
+# Generated by GNU Autoconf 2.61 for systemtap 0.9.7.
#
# Report bugs to <systemtap@sources.redhat.com>.
#
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='systemtap'
PACKAGE_TARNAME='systemtap'
-PACKAGE_VERSION='0.9'
-PACKAGE_STRING='systemtap 0.9'
+PACKAGE_VERSION='0.9.7'
+PACKAGE_STRING='systemtap 0.9.7'
PACKAGE_BUGREPORT='systemtap@sources.redhat.com'
ac_subst_vars='SHELL
@@ -1149,7 +1149,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures systemtap 0.9 to adapt to many kinds of systems.
+\`configure' configures systemtap 0.9.7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1215,7 +1215,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of systemtap 0.9:";;
+ short | recursive ) echo "Configuration of systemtap 0.9.7:";;
esac
cat <<\_ACEOF
@@ -1291,7 +1291,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-systemtap configure 0.9
+systemtap configure 0.9.7
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1305,7 +1305,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by systemtap $as_me 0.9, which was
+It was created by systemtap $as_me 0.9.7, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@@ -1997,7 +1997,7 @@ fi
# Define the identity of the package.
PACKAGE='systemtap'
- VERSION='0.9'
+ VERSION='0.9.7'
cat >>confdefs.h <<_ACEOF
@@ -2617,7 +2617,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by systemtap $as_me 0.9, which was
+This file was extended by systemtap $as_me 0.9.7, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -2660,7 +2660,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-systemtap config.status 0.9
+systemtap config.status 0.9.7
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/testsuite/configure.ac b/testsuite/configure.ac
index c40fdf72..1a82fe36 100644
--- a/testsuite/configure.ac
+++ b/testsuite/configure.ac
@@ -1,7 +1,7 @@
dnl configure.ac --- autoconf input file for systemtap testsuite
dnl Process this file with autoconf to produce a configure script.
-AC_INIT([systemtap], 0.9, systemtap@sources.redhat.com, systemtap)
+AC_INIT([systemtap], 0.9.7, systemtap@sources.redhat.com, systemtap)
AC_PREREQ(2.59)
AC_CONFIG_AUX_DIR(..)
diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp
index a4beaa12..3043eeed 100644
--- a/testsuite/lib/stap_run.exp
+++ b/testsuite/lib/stap_run.exp
@@ -30,6 +30,7 @@ proc stap_run { TEST_NAME {LOAD_GEN_FUNCTION ""} {OUTPUT_CHECK_STRING ""} args }
if [file readable $test_file_name] {
lappend cmd $test_file_name
}
+ send_log "executing: $cmd\n"
eval spawn $cmd
expect {
-timeout 180
diff --git a/testsuite/lib/stap_run2.exp b/testsuite/lib/stap_run2.exp
index cb1c6615..d1f02c83 100644
--- a/testsuite/lib/stap_run2.exp
+++ b/testsuite/lib/stap_run2.exp
@@ -10,12 +10,27 @@
proc stap_run2 { TEST_NAME args } {
# zap the srcdir prefix
- set test_file_name $TEST_NAME
+ set TEST_FILE $TEST_NAME
set TEST_NAME [regsub {.*/testsuite/} $TEST_NAME ""]
-
+ if {[llength $args] == 0} {
+ stap_run3 $TEST_NAME $TEST_FILE
+ } else {
+ stap_run3 $TEST_NAME $TEST_FILE $args
+ }
+}
+
+# stap_run3 TEST_NAME TEST_FILE
+# TEST_NAME is the name of the test as shown in PASS/FAIL/SKIPPED messages.
+# TEST_FILE is the path to the current test
+# Additional arguments are passed to stap as-is.
+#
+# global result_string must be set to the expected output
+
+proc stap_run3 { TEST_NAME TEST_FILE args } {
if {[info procs installtest_p] != "" && ![installtest_p]} { untested $TEST_NAME; return }
-
- set cmd [concat stap $args $test_file_name]
+
+ set cmd [concat stap $TEST_FILE $args]
+ send_log "executing: $cmd\n"
catch {eval exec $cmd} res
set n 0
diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp
index c80ad171..379f6c58 100644
--- a/testsuite/lib/systemtap.exp
+++ b/testsuite/lib/systemtap.exp
@@ -16,6 +16,16 @@ proc use_server_p {} {
}
+proc utrace_p {} {
+ set path "/proc/kallsyms"
+ if {! [catch {exec grep -q utrace_attach $path} dummy]} {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+
proc print_systemtap_version {} {
set version [exec /bin/uname -r]
set location "/boot/vmlinux-$version"
@@ -75,7 +85,7 @@ proc setup_server {} {
# Make sure that the necessary resources are available to run the client/server.
if {[installtest_p]} then {
- if {[exec /usr/bin/which stap-client-connect] == ""} then {
+ if {[catch {exec /usr/bin/which stap-client-connect} dummy]} then {
print "Unable to start a server: stap-client-connect is not found in PATH"
return 0
}
@@ -83,7 +93,7 @@ proc setup_server {} {
print "Unable to start a server: [exec pwd]/../stap-client-connect is not found"
return 0
}
- if {[exec /usr/bin/which avahi-publish-service] == ""} then {
+ if {[catch {exec /usr/bin/which avahi-publish-service} dummy]} then {
print "Unable to start a server: avahi-publish-service is not found in PATH"
return 0
}
@@ -99,6 +109,7 @@ proc setup_server {} {
if {! [installtest_p]} then {
# Make sure the server management scripts and tools are on the $PATH.
set env(PATH) "$srcdir/..:[exec pwd]/..:$env(PATH)"
+ set env(SYSTEMTAP_SERVER_SCRIPTS) "$srcdir/.."
}
# Try to find or start the server.
@@ -118,8 +129,10 @@ proc setup_server {} {
# The server does not call this instance of 'stap'
if {[installtest_p]} then {
exec /bin/cp -p [exec which stap-client] $net_path/stap
+ exec /bin/cp -p [exec which stap-env] $net_path/stap-env
} else {
exec /bin/cp -p $srcdir/../stap-client $net_path/stap
+ exec /bin/cp -p $srcdir/../stap-env $net_path/stap-env
}
set env(PATH) "$net_path:$env(PATH)"
@@ -148,13 +161,18 @@ proc get_system_info {} {
set Snapshot [exec /bin/cat $env(SRCDIR)/../SNAPSHOT]
} else {
regexp {version [^)]*} [exec stap -V 2>@ stdout] version
- set Snapshot $version
+ set Snapshot $version
}
set Distro "Linux"
- if [file exists /etc/fedora-release] {set Distro [exec /bin/cat /etc/fedora-release]}
- if [file exists /etc/redhat-release] {set Distro [exec /bin/cat /etc/redhat-release]}
- if [file exists /etc/suse-release] {set Distro [exec /bin/cat /etc/suse-release]}
- if [file exists /etc/debian_version] {set Distro [exec /bin/cat /etc/debian_version]}
+ if [file exists /usr/bin/lsb_release] {
+ # this produces one line of this format:
+ # Distribution:\tSTRING
+ set Distro [lrange [exec /usr/bin/lsb_release -d] 1 end]
+ } else {
+ foreach f {/etc/fedora-release /etc/enterprise-release /etc/redhat-release /etc/suse-release /etc/debian_version} {
+ if [file exists $f] then {set Distro [exec /bin/cat $f]; break }
+ }
+ }
}
if {! [setup_systemtap_environment]} then {
diff --git a/testsuite/parseko/cmdline17.stp b/testsuite/parseko/cmdline17.stp
new file mode 100755
index 00000000..a9baf2d4
--- /dev/null
+++ b/testsuite/parseko/cmdline17.stp
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# options '-D' and '-L' are mutually exclusive
+#
+#-D Run in background. This requires '-o' option.
+#-L Load module and start probes, then detach.
+
+staprun -L -D fake_module
diff --git a/testsuite/parseko/cmdline18.stp b/testsuite/parseko/cmdline18.stp
new file mode 100755
index 00000000..bbdfbcc5
--- /dev/null
+++ b/testsuite/parseko/cmdline18.stp
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# options '-D' and '-d' are mutually exclusive
+#
+#-D Run in background. This requires '-o' option.
+#-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.
+
+staprun -d -D fake_module
diff --git a/testsuite/parseko/cmdline19.stp b/testsuite/parseko/cmdline19.stp
new file mode 100755
index 00000000..fbcef351
--- /dev/null
+++ b/testsuite/parseko/cmdline19.stp
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# options '-D' and '-c cmd' are mutually exclusive
+#
+#-D Run in background. This requires '-o' option.
+#-c cmd Command 'cmd' will be run and staprun will
+# exit when it does. The '_stp_target' variable
+# will contain the pid for the command.
+
+staprun -c /bin/ls -D fake_module
diff --git a/testsuite/parseko/cmdline20.stp b/testsuite/parseko/cmdline20.stp
new file mode 100755
index 00000000..625cf20d
--- /dev/null
+++ b/testsuite/parseko/cmdline20.stp
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# You have to specify ouput FILE with '-D' option
+#
+#-D Run in background. This requires '-o' option.
+#-o FILE Send output to FILE. This supports strftime(3)
+# formats for FILE.
+
+staprun -D fake_module
diff --git a/testsuite/parseko/cmdline21.stp b/testsuite/parseko/cmdline21.stp
new file mode 100755
index 00000000..d7496c8c
--- /dev/null
+++ b/testsuite/parseko/cmdline21.stp
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# You have to specify ouput FILE with '-S' option
+#
+#-S size[,N] Switches output file to next file when the size
+# of file reaches the specified size. The value
+# should be an integer greater than 1 which is
+# assumed to be the maximum file size in MB.
+# When the number of output files reaches N, it
+# switches to the first output file. You can omit
+# the second argument.
+#-o FILE Send output to FILE. This supports strftime(3)
+# formats for FILE.
+
+staprun -S 1,1 fake_module
diff --git a/testsuite/parseko/utrace01.stp b/testsuite/parseko/utrace01.stp
index 1cb4227f..9f3619b5 100755
--- a/testsuite/parseko/utrace01.stp
+++ b/testsuite/parseko/utrace01.stp
@@ -1,4 +1,4 @@
#! stap -p2
# process NAME must be a string
-probe process(/bin/cat).death { }
+probe process(/bin/cat).end { }
diff --git a/testsuite/semko/forty.stp b/testsuite/semko/forty.stp
index f7721a47..b7d1d139 100755
--- a/testsuite/semko/forty.stp
+++ b/testsuite/semko/forty.stp
@@ -1,4 +1,4 @@
#! stap -p2
global x
-probe kernel.function("sys_open") if (x = 1) { } # bad side-effect
+probe kernel.function("do_sys_open") if (x = 1) { } # bad side-effect
diff --git a/testsuite/semko/fortyone.stp b/testsuite/semko/fortyone.stp
index e9b986df..d3ba6205 100755
--- a/testsuite/semko/fortyone.stp
+++ b/testsuite/semko/fortyone.stp
@@ -1,3 +1,3 @@
#! stap -p2
-probe kernel.function("sys_open") if (x > 1) { } # not a global
+probe kernel.function("vfs_read") if (x > 1) { } # not a global
diff --git a/testsuite/semko/fortytwo.stp b/testsuite/semko/fortytwo.stp
index 17dacb1c..09a04ea7 100755
--- a/testsuite/semko/fortytwo.stp
+++ b/testsuite/semko/fortytwo.stp
@@ -1,6 +1,6 @@
#! stap -p2
-probe kernel.function("sys_open") if (foo(2)) { } # must not call functions
+probe kernel.function("vfs_read") if (foo(2)) { } # must not call functions
function foo(x) { return x }
diff --git a/testsuite/semko/maxactive04.stp b/testsuite/semko/maxactive04.stp
index 9471fd21..25d63ef4 100755
--- a/testsuite/semko/maxactive04.stp
+++ b/testsuite/semko/maxactive04.stp
@@ -1,5 +1,5 @@
#! stap -p2
-probe kernel.function("sys_open").return.maxactive(-4)
+probe kernel.function("vfs_read").return.maxactive(-4)
{
}
diff --git a/testsuite/semko/maxactive05.stp b/testsuite/semko/maxactive05.stp
index bdc8a101..3833ab6c 100755
--- a/testsuite/semko/maxactive05.stp
+++ b/testsuite/semko/maxactive05.stp
@@ -1,5 +1,5 @@
#! stap -p2
-probe kernel.function("sys_open").return.maxactive(99999999)
+probe kernel.function("vfs_read").return.maxactive(99999999)
{
}
diff --git a/testsuite/semko/return02.stp b/testsuite/semko/return02.stp
index db4cd8c7..3d64f5dc 100755
--- a/testsuite/semko/return02.stp
+++ b/testsuite/semko/return02.stp
@@ -1,6 +1,6 @@
#! stap -p2
-probe kernel.function("sys_read")
+probe kernel.function("vfs_read")
{
# this should fail - using $return not in a '.return' probe
printf("in sys_read - return = %d\n", $return)
diff --git a/testsuite/semko/thirtyfour.stp b/testsuite/semko/thirtyfour.stp
index 515fcfbb..dca63722 100755
--- a/testsuite/semko/thirtyfour.stp
+++ b/testsuite/semko/thirtyfour.stp
@@ -2,9 +2,9 @@
# can't write to target variables in .return probes
-probe kernel.function("sys_read").return
+probe kernel.function("fget_light").return
{
$fd = 0
printf("fd is %d\n", $fd)
}
-probe kernel.function("sys_open").return { $filename }
+probe kernel.function("do_sys_open").return { $filename }
diff --git a/testsuite/semko/twentytwo.stp b/testsuite/semko/twentytwo.stp
index 9321d5f6..ef04cd30 100755
--- a/testsuite/semko/twentytwo.stp
+++ b/testsuite/semko/twentytwo.stp
@@ -3,6 +3,6 @@
# tests that a non-inline function is *not* matched using
# the inline() pattern
-probe kernel.function("sys_recv").inline {
+probe kernel.function("vfs_read").inline {
log ("found a non-inline via inline()")
}
diff --git a/testsuite/semko/utrace01.stp b/testsuite/semko/utrace01.stp
deleted file mode 100755
index a4707008..00000000
--- a/testsuite/semko/utrace01.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! stap -p2
-
-# missing process NAME|PID
-probe process.death { }
diff --git a/testsuite/semko/utrace03.stp b/testsuite/semko/utrace03.stp
index c682410b..92177ffd 100755
--- a/testsuite/semko/utrace03.stp
+++ b/testsuite/semko/utrace03.stp
@@ -1,4 +1,4 @@
#! stap -p2
# invalid probe type
-probe process("/bin/cat").death.return { }
+probe process("/bin/cat").end.return { }
diff --git a/testsuite/semko/utrace04.stp b/testsuite/semko/utrace04.stp
index 6345f9f6..1d26a43c 100755
--- a/testsuite/semko/utrace04.stp
+++ b/testsuite/semko/utrace04.stp
@@ -1,4 +1,4 @@
#! stap -p2
-# death probes don't support target symbols
-probe process("/bin/cat").death.return { print($syscall) }
+# end probes don't support target symbols
+probe process("/bin/cat").end { print($syscall) }
diff --git a/testsuite/semko/utrace08.stp b/testsuite/semko/utrace08.stp
deleted file mode 100755
index a558a5be..00000000
--- a/testsuite/semko/utrace08.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! stap -p2
-
-# process path must be absolute
-probe process("cat").death { }
diff --git a/testsuite/semko/utrace09.stp b/testsuite/semko/utrace09.stp
deleted file mode 100755
index 60c49cd2..00000000
--- a/testsuite/semko/utrace09.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! stap -p2
-
-# process path must be absolute
-probe process("/foo/../bar").death { }
diff --git a/testsuite/semko/utrace10.stp b/testsuite/semko/utrace10.stp
deleted file mode 100755
index b46baea9..00000000
--- a/testsuite/semko/utrace10.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! 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
deleted file mode 100755
index d78b602c..00000000
--- a/testsuite/semko/utrace11.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! stap -p2
-
-# path can't end with '/'
-probe process("/foo/bar/").death { }
diff --git a/testsuite/semko/utrace12.stp b/testsuite/semko/utrace12.stp
deleted file mode 100755
index 478aa1d3..00000000
--- a/testsuite/semko/utrace12.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! stap -p2
-
-# path can't end with '.'
-probe process("/foo/bar/.").death { }
diff --git a/testsuite/semko/utrace13.stp b/testsuite/semko/utrace13.stp
deleted file mode 100755
index 16cc0391..00000000
--- a/testsuite/semko/utrace13.stp
+++ /dev/null
@@ -1,4 +0,0 @@
-#! stap -p2
-
-# path can't end with '..'
-probe process("/foo/bar/..").death { }
diff --git a/testsuite/semok/badvar.stp b/testsuite/semok/badvar.stp
index b3bd2d67..677187a3 100755
--- a/testsuite/semok/badvar.stp
+++ b/testsuite/semok/badvar.stp
@@ -1,7 +1,9 @@
-#! stap --skip-badvars
+#! /bin/sh
+stap -p2 --skip-badvars -e '
probe syscall.read {
if ($foo == 0)
printf ("Voila! It works..\n")
exit ()
}
+'
diff --git a/testsuite/semok/cast.stp b/testsuite/semok/cast.stp
index 93da18ef..14401886 100755
--- a/testsuite/semok/cast.stp
+++ b/testsuite/semok/cast.stp
@@ -10,4 +10,14 @@ probe begin {
// would be nice to test usermode @cast too,
// but who knows what debuginfo is installed...
+
+ // check modules generated from headers
+ println(@cast(0, "task_struct", "kernel<linux/sched.h>")->tgid)
+ println(@cast(0, "timeval", "<sys/time.h>")->tv_sec)
+
+ // make sure that bogus @casts can get optimized away
+ @cast(0, "task_struct")->no_such_field
+ @cast(0, "task_struct")->parent->no_such_field
+ @cast(0, "no_such_type")->tgid
+ @cast(0, "task_struct", "no_such_module")->tgid
}
diff --git a/testsuite/semok/thirtythree.stp b/testsuite/semok/thirtythree.stp
index 90070370..0f0cacf6 100755
--- a/testsuite/semok/thirtythree.stp
+++ b/testsuite/semok/thirtythree.stp
@@ -1,5 +1,9 @@
#! stap -p2
# Per bz3016, this should get through the semantic pass without warnings.
probe kernel.function("do_mpage_readpage") {
- printf("\n page->mapping %p",$page->mapping)
+ printf("\n page->mapping %p",$page->mapping)
+ %( kernel_v >= "2.6.22" %?
+ printf("\n page->first_page->mapping %p",$page->first_page->mapping)
+ %)
+
}
diff --git a/testsuite/semok/thirtytwo.stp b/testsuite/semok/thirtytwo.stp
index 2a69b8cd..0f0334a1 100755
--- a/testsuite/semok/thirtytwo.stp
+++ b/testsuite/semok/thirtytwo.stp
@@ -2,4 +2,4 @@
# PR 6836
-probe kernel.function("sys_open").return { log($$return . $$parms) }
+probe kernel.function("do_sys_open").return { log($$return . $$parms) }
diff --git a/testsuite/semok/twentynine.stp b/testsuite/semok/twentynine.stp
index 05e591ce..4b2e5056 100755
--- a/testsuite/semok/twentynine.stp
+++ b/testsuite/semok/twentynine.stp
@@ -5,7 +5,7 @@ function dummy:long () {return p;}
# alias with a condition
probe alias0 = begin if (3) {p=1}
# alias with a kernel-variable condition -- not valid
-probe alias1 = kernel.function("sys_read").return if (0) { if ($return) {p=0} }
+probe alias1 = kernel.function("vfs_read").return if (0) { if ($return) {p=0} }
# alias with a function-call condition
probe blias0 = timer.s(1) if (1 /* dummy() */) {p=10}
diff --git a/testsuite/semok/utrace01.stp b/testsuite/semok/utrace01.stp
new file mode 100755
index 00000000..864bdf15
--- /dev/null
+++ b/testsuite/semok/utrace01.stp
@@ -0,0 +1,4 @@
+#! stap -p2
+
+# process path doesn't need to be absolute
+probe process("cat").end { }
diff --git a/testsuite/systemtap.base/alternatives.exp b/testsuite/systemtap.base/alternatives.exp
index deaf3bf8..f5dc4513 100644
--- a/testsuite/systemtap.base/alternatives.exp
+++ b/testsuite/systemtap.base/alternatives.exp
@@ -14,11 +14,11 @@
# listed, but that some alternatives are listed.
set local1_script {
- probe kernel.function("sys_getrlimit") { x = $z; }
+ probe kernel.function("vfs_write") { ret = $z; }
}
set struct1_script {
- probe kernel.function("sys_getrlimit") { rlim_cur = $rlim->rlim_cud; }
+ probe kernel.function("vfs_write") { f_pos = $file->f_po; }
}
proc stap_run_alternatives {args} {
@@ -26,10 +26,11 @@ proc stap_run_alternatives {args} {
verbose -log "starting $args"
eval spawn $args
expect {
+ -timeout 60
-re {semantic error: .+ \(alternatives: [a-zA-Z_]} {incr alternatives_found; exp_continue}
-re {[^\r]*\r} { verbose -log $expect_out(0,string); exp_continue }
- eof { }
- timeout { }
+ eof { verbose -log "EOF" }
+ timeout { verbose -log "TIMEOUT" }
}
set results [wait]
verbose -log "wait results: $results"
@@ -37,9 +38,9 @@ proc stap_run_alternatives {args} {
}
set test "LOCAL1"
-set rc [stap_run_alternatives stap -vu -p2 -e $local1_script]
-if {$rc == 1} { pass $test } else { fail "$test ($rc)" }
+set rc [stap_run_alternatives stap -u -p2 -e $local1_script]
+if {$rc >= 1} { pass $test } else { fail "$test ($rc)" }
set test "STRUCT1"
-set rc [stap_run_alternatives stap -vu -p2 -e $struct1_script]
-if {$rc == 1} { pass $test } else { fail "$test ($rc)" }
+set rc [stap_run_alternatives stap -u -p2 -e $struct1_script]
+if {$rc >= 1} { pass $test } else { fail "$test ($rc)" }
diff --git a/testsuite/systemtap.base/badkprobe.exp b/testsuite/systemtap.base/badkprobe.exp
index efc06695..c0815fbe 100644
--- a/testsuite/systemtap.base/badkprobe.exp
+++ b/testsuite/systemtap.base/badkprobe.exp
@@ -1,14 +1,28 @@
-set script "probe kernel.statement(-1).absolute {} probe timer.s(1) { exit() }"
set test "bad kprobe registration"
+set script {
+ probe $1 {}
+ probe timer.s(1) { exit() }
+ probe end { println("cleanup ok") }
+}
if {! [installtest_p]} { untested $test; return }
-spawn stap -g -w -e "$script"
-expect {
- -timeout 60
- -re "^WARNING: probe .*registration error.*" { pass $test }
- eof { fail "$test (eof)" }
- timeout { fail "$test (timeout)" }
+set bad_kprobes {
+ kernel.statement(-1).absolute
+ kprobe.statement(-1).absolute
+ kprobe.function("no_such_function")
+ kprobe.function("no_such_function").return
+}
+
+foreach bk $bad_kprobes {
+ set test "bad kprobe registration: $bk"
+ spawn stap -g -w -e "$script" "$bk"
+ expect {
+ -timeout 60
+ -re "^WARNING: probe .*registration error.*\r\ncleanup ok" { pass $test }
+ eof { fail "$test (eof)" }
+ timeout { fail "$test (timeout)" }
+ }
+ catch {close}
+ catch {wait}
}
-catch {close}
-catch {wait}
diff --git a/testsuite/systemtap.base/bitfield.exp b/testsuite/systemtap.base/bitfield.exp
new file mode 100644
index 00000000..16451369
--- /dev/null
+++ b/testsuite/systemtap.base/bitfield.exp
@@ -0,0 +1,3 @@
+# test that bitfield r/w works correctly
+set test "bitfield"
+stap_run $srcdir/$subdir/$test.stp no_load $all_pass_string -g
diff --git a/testsuite/systemtap.base/bitfield.stp b/testsuite/systemtap.base/bitfield.stp
new file mode 100644
index 00000000..c2ff4929
--- /dev/null
+++ b/testsuite/systemtap.base/bitfield.stp
@@ -0,0 +1,46 @@
+%{
+#include <linux/tcp.h>
+static struct tcphdr foo = {0};
+%}
+
+function get_ptr:long() %{ THIS->__retvalue = (long)&foo; /* pure */ %}
+function get_ack:long() %{ THIS->__retvalue = foo.ack; /* pure */ %}
+function get_urg:long() %{ THIS->__retvalue = foo.urg; /* pure */ %}
+
+function check:long(ack:long, urg:long) {
+ ptr = get_ptr()
+
+ /* set the bits with cast */
+ @cast(ptr, "tcphdr")->ack = ack
+ @cast(ptr, "tcphdr")->urg = urg
+
+ /* check that reading with embedded-C is ok */
+ real_ack = get_ack()
+ real_urg = get_urg()
+ errors = (ack != real_ack) + (urg != real_urg)
+
+ /* check that reading with a cast is ok */
+ cast_ack = @cast(ptr, "tcphdr")->ack
+ cast_urg = @cast(ptr, "tcphdr")->urg
+ errors += (ack != cast_ack) + (urg != cast_urg)
+
+ if (errors)
+ printf("bitfield had %d errors; expect(%d%d), real(%d%d), cast(%d%d)\n",
+ errors, ack, urg, real_ack, real_urg, cast_ack, cast_urg)
+
+ return errors
+}
+
+probe begin {
+ println("systemtap starting probe")
+
+ errors = check(0, 0)
+ errors += check(0, 1)
+ errors += check(1, 0)
+ errors += check(1, 1)
+
+ println("systemtap ending probe")
+ if (errors == 0)
+ println("systemtap test success")
+ exit()
+}
diff --git a/testsuite/systemtap.base/bz10078.c b/testsuite/systemtap.base/bz10078.c
new file mode 100644
index 00000000..9075fbc7
--- /dev/null
+++ b/testsuite/systemtap.base/bz10078.c
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+struct point { int x, y; };
+
+struct point mkpoint2(void)
+{
+ struct point p = { 1, 2 };
+ return p;
+}
+
+struct point mkpoint1(void)
+{
+ return mkpoint2();
+}
+
+main()
+{
+ struct point p = mkpoint1();
+ printf("%d,%d\n", p.x, p.y);
+ exit(0);
+}
diff --git a/testsuite/systemtap.base/bz10078.exp b/testsuite/systemtap.base/bz10078.exp
new file mode 100644
index 00000000..cad3a3a8
--- /dev/null
+++ b/testsuite/systemtap.base/bz10078.exp
@@ -0,0 +1,35 @@
+set test bz10078
+
+catch {exec gcc -g -o $test $srcdir/$subdir/$test.c} err
+if {$err == "" && [file exists $test]} then { pass "$test compile" } else { fail "$test compile" }
+
+if {![utrace_p]} {
+ catch {exec rm -f $test}
+ untested "$test -p4"
+ untested "$test -p5"
+ return
+}
+
+set rc [stap_run_batch $srcdir/$subdir/$test.stp]
+if {$rc == 0} then { pass "$test -p4" } else { fail "$test -p4" }
+
+if {! [installtest_p]} {
+ catch {exec rm -f $test}
+ untested "$test -p5"
+ return
+}
+
+# Pick up the stap being tested.
+set stapexe [exec /usr/bin/which stap]
+spawn sudo $stapexe $srcdir/$subdir/$test.stp -c ./$test
+set ok 0
+expect {
+ -timeout 60
+ -re {mkpoint[^\r\n]* returns\r\n} { incr ok; exp_continue }
+ -re {1,2\r\n} { incr ok; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+wait
+if {$ok == 3} then { pass "$test -p5" } else { fail "$test -p5 ($ok)" }
+exec rm -f $test
diff --git a/testsuite/systemtap.base/bz10078.stp b/testsuite/systemtap.base/bz10078.stp
new file mode 100755
index 00000000..0318e4e9
--- /dev/null
+++ b/testsuite/systemtap.base/bz10078.stp
@@ -0,0 +1,4 @@
+#! stap -p4
+probe process("./bz10078").function("mkpoint*").return {
+ printf("%s returns\n", probefunc())
+}
diff --git a/testsuite/systemtap.base/bz5274.exp b/testsuite/systemtap.base/bz5274.exp
index 92441e9e..2f76a43f 100755
--- a/testsuite/systemtap.base/bz5274.exp
+++ b/testsuite/systemtap.base/bz5274.exp
@@ -17,14 +17,7 @@ if {! [installtest_p]} {
return
}
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
catch {exec rm -f $test}
untested "$test -p5"
return
diff --git a/testsuite/systemtap.base/bz6850.exp b/testsuite/systemtap.base/bz6850.exp
index b96ed95c..32ecdaf5 100644
--- a/testsuite/systemtap.base/bz6850.exp
+++ b/testsuite/systemtap.base/bz6850.exp
@@ -3,14 +3,7 @@ set test bz6850
catch {exec gcc -g -o bz6850 $srcdir/$subdir/bz6850.c} err
if {$err == "" && [file exists bz6850]} then { pass "$test compile" } else { fail "$test compile" }
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
catch {exec rm -f $test}
untested "$test -p4"
untested "$test -p5"
diff --git a/testsuite/systemtap.base/cast.exp b/testsuite/systemtap.base/cast.exp
index df3246e8..374132f0 100644
--- a/testsuite/systemtap.base/cast.exp
+++ b/testsuite/systemtap.base/cast.exp
@@ -1,4 +1,6 @@
set test "cast"
set ::result_string {PID OK
-execname OK}
-stap_run2 $srcdir/$subdir/$test.stp
+PID2 OK
+execname OK
+sa_data OK}
+stap_run2 $srcdir/$subdir/$test.stp -g
diff --git a/testsuite/systemtap.base/cast.stp b/testsuite/systemtap.base/cast.stp
index bec0cc9b..e2505000 100644
--- a/testsuite/systemtap.base/cast.stp
+++ b/testsuite/systemtap.base/cast.stp
@@ -10,6 +10,13 @@ probe begin
else
printf("PID %d != %d\n", pid, cast_pid)
+ // Compare PIDs using a generated kernel module
+ cast_pid = @cast(curr, "task_struct", "kernel<linux/sched.h>")->tgid
+ if (pid == cast_pid)
+ println("PID2 OK")
+ else
+ printf("PID2 %d != %d\n", pid, cast_pid)
+
// Compare execnames
name = execname()
cast_name = kernel_string(@cast(curr, "task_struct")->comm)
@@ -18,5 +25,23 @@ probe begin
else
printf("execname \"%s\" != \"%s\"\n", name, cast_name)
+ // Compare sa_data using a generated user module
+ data = 42
+ cast_data = @cast(get_sockaddr(data), "sockaddr", "<sys/socket.h>")->sa_data[0]
+ if (data == cast_data)
+ println("sa_data OK")
+ else
+ printf("sa_data %d != %d\n", data, cast_data)
+
exit()
}
+
+%{
+#include <linux/socket.h>
+%}
+
+function get_sockaddr:long(data:long) %{
+ static struct sockaddr sa = {0};
+ sa.sa_data[0] = THIS->data;
+ THIS->__retvalue = (long)&sa;
+%}
diff --git a/testsuite/systemtap.base/flightrec1.exp b/testsuite/systemtap.base/flightrec1.exp
new file mode 100644
index 00000000..c32a77f2
--- /dev/null
+++ b/testsuite/systemtap.base/flightrec1.exp
@@ -0,0 +1,43 @@
+set test "flightrec1"
+if {![installtest_p]} { untested $test; return }
+
+# run stapio in background mode
+spawn stap -F -o $test.out -we {probe begin {}}
+# check whether stap outputs stapio pid
+set pid 0
+expect {
+ -timeout 240
+ -re {([0-9]+)\r\n} {
+ pass "$test (flight recorder option)"
+ set pid $expect_out(1,string)
+ exp_continue}
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+wait
+if {$pid == 0} {
+ fail "$test (no pid)"
+ return -1
+}
+
+# check whether stapio is running in background
+spawn ps -o cmd hc $pid
+expect {
+ -timeout 10
+ "stapio" {pass "$test (stapio in background)"} # don't contine
+ timeout { fail "$test (timeout)"}
+ eof { fail "$test (stapio was not found)" }
+}
+wait
+
+exec kill -TERM $pid
+
+# check output file
+if {[catch {exec rm $test.out}]} {
+ fail "$test (no output file)"
+ return -1
+} else {
+ pass "$test (output file)"
+}
+
+
diff --git a/testsuite/systemtap.base/flightrec2.exp b/testsuite/systemtap.base/flightrec2.exp
new file mode 100644
index 00000000..d4481db4
--- /dev/null
+++ b/testsuite/systemtap.base/flightrec2.exp
@@ -0,0 +1,68 @@
+set test "flightrec2"
+if {![installtest_p]} { untested $test; return }
+
+# cleanup
+system "rm -f flightlog.out*"
+
+set pid 0
+# check -S option
+spawn stap -F -o flightlog.out -S 1,3 $srcdir/$subdir/$test.stp
+expect {
+ -timeout 240
+ -re {([0-9]+)\r\n} {
+ pass "$test (-S option)"
+ set pid $expect_out(1,string)
+ exp_continue}
+ timeout { fail "$test (timeout)"}
+ eof { }
+}
+wait
+if {$pid == 0} {
+ fail "$test (no pid)"
+ return -1
+}
+
+exec sleep 4
+set scnt 0
+set cnt1 0
+# wait for log files
+eval spawn stat -c %s [glob flightlog.out.*]
+expect {
+ -timeout 100
+ -re {[0-9]+} {
+ incr cnt1;
+ if {$expect_out(buffer) <= 1048576 } {incr scnt}
+ exp_continue}
+ timeout { fail "$test (logfile timeout)"}
+}
+wait
+exec sleep 3
+set cnt2 0
+# wait for log files
+eval spawn stat -c %s [glob flightlog.out.*]
+expect {
+ -timeout 100
+ -re {[0-9]+} {
+ incr cnt2;
+ if {$expect_out(buffer) <= 1048576 } {incr scnt}
+ exp_continue}
+ timeout { fail "$test (logfile timeout)"}
+}
+wait
+# check logfile number
+if {$cnt1 == 3 && $cnt2 == 3} {
+ pass "$test (log file numbers limitation)"
+} else {
+ fail "$test (log file numbers ($cnt1, $cnt2))"
+}
+# check logfile size
+if {$scnt == $cnt1 + $cnt2 } {
+ pass "$test (log file size limitation)"
+} else {
+ fail "$test (log file size ($scnt != $cnt1 + $cnt2))"
+}
+exec kill -TERM $pid
+# wait for exiting...
+exec sleep 1
+system "rm -f flightlog.out*"
+
diff --git a/testsuite/systemtap.base/flightrec2.stp b/testsuite/systemtap.base/flightrec2.stp
new file mode 100644
index 00000000..f42c9b8e
--- /dev/null
+++ b/testsuite/systemtap.base/flightrec2.stp
@@ -0,0 +1,5 @@
+probe timer.ms(10)
+{
+ for (j = 0; j < 1000; j++)
+ printf("1234567890\n")
+}
diff --git a/testsuite/systemtap.base/flightrec3.exp b/testsuite/systemtap.base/flightrec3.exp
new file mode 100644
index 00000000..5b9d8253
--- /dev/null
+++ b/testsuite/systemtap.base/flightrec3.exp
@@ -0,0 +1,79 @@
+set test "flightrec3"
+if {![installtest_p]} { untested $test; return }
+
+# cleanup
+system "rm -f flightlog.out*"
+
+set pid 0
+# check -S option with bulk(percpu file) mode
+spawn stap -F -o flightlog.out -S 1,3 -b $srcdir/$subdir/$test.stp
+expect {
+ -timeout 240
+ -re {([0-9]+)\r\n} {
+ pass "$test (-S option with bulk mode)"
+ set pid $expect_out(1,string)
+ exp_continue}
+ timeout { fail "$test (timeout)"}
+ eof { }
+}
+wait
+if {$pid == 0} {
+ fail "$test (no pid)"
+ return -1
+}
+
+exec sleep 4
+array set cpus {}
+set scnt 0
+# wait for log files
+exec kill -STOP $pid
+exec sleep 1
+eval spawn stat -c \"%n %s\" [glob flightlog.out_cpu*]
+expect {
+ -timeout 100
+ -re {flightlog.out_cpu([0-9]+).[0-9]+ ([0-9]+)\r\n} {
+ set cpuid $expect_out(1,string)
+ set size $expect_out(2,string)
+ if {[array get cpus $cpuid] == ""} {set cpus($cpuid) 0}
+ incr cpus($cpuid);
+ if {$size <= 1048576 } {incr scnt}
+ exp_continue}
+ timeout { fail "$test (logfile timeout)"}
+}
+wait
+exec kill -CONT $pid
+exec sleep 3
+exec kill -STOP $pid
+eval spawn stat -c \"%n %s\" [glob flightlog.out_cpu*]
+expect {
+ -timeout 100
+ -re {flightlog.out_cpu([0-9]+).[0-9]+ ([0-9]+)\r\n} {
+ set cpuid $expect_out(1,string)
+ set size $expect_out(2,string)
+ if {[array get cpus $cpuid] == ""} {set cpus($cpuid) 0}
+ incr cpus($cpuid);
+ if {$size <= 1048576 } {incr scnt}
+ exp_continue}
+ timeout { fail "$test (logfile timeout)"}
+}
+wait
+exec kill -CONT $pid
+# check logfile number
+set cnt 0
+foreach e [array names cpus] {
+ if {$cpus($e) != 6} {
+ fail "$test (log file numbers cpu:$e, cnt:$cpus($e)))"
+ }
+ set cnt [expr $cnt + $cpus($e)]
+}
+# check logfile size
+if {$scnt == $cnt} {
+ pass "$test (log file size limitation with bulk mode)"
+} else {
+ fail "$test (log file size ($scnt != $cnt))"
+}
+exec kill -TERM $pid
+# wait for exiting...
+exec sleep 1
+system "rm -f flightlog.out*"
+
diff --git a/testsuite/systemtap.base/flightrec3.stp b/testsuite/systemtap.base/flightrec3.stp
new file mode 100644
index 00000000..d660793f
--- /dev/null
+++ b/testsuite/systemtap.base/flightrec3.stp
@@ -0,0 +1,5 @@
+probe kernel.function("update_process_times")
+{
+ for (j = 0; j < 100; j++)
+ printf("1234567890\n")
+}
diff --git a/testsuite/systemtap.base/itrace.exp b/testsuite/systemtap.base/itrace.exp
index f19af977..5da0dfaf 100644
--- a/testsuite/systemtap.base/itrace.exp
+++ b/testsuite/systemtap.base/itrace.exp
@@ -1,17 +1,13 @@
# itrace test
-# temporarily disabled
-return
-
# Initialize variables
-set utrace_support_found 0
set exepath "[pwd]/ls_[pid]"
set itrace1_script {
global instrs = 0
probe begin { printf("systemtap starting probe\n") }
- probe process("%s").itrace
+ probe process("%s").insn
{
instrs += 1
if (instrs == 5)
@@ -28,7 +24,7 @@ set itrace1_script_output "itraced = 5\r\n"
set itrace2_script {
global instrs = 0, itrace_on = 0, start_timer = 0
probe begin { start_timer = 1; printf("systemtap starting probe\n") }
- probe process("%s").itrace if (itrace_on)
+ probe process("%s").insn if (itrace_on)
{
instrs += 1
if (instrs == 5)
@@ -51,6 +47,26 @@ set itrace2_script {
}
set itrace2_script_output "itraced = 5\r\n"
+set itrace3_script {
+ global branches = 0
+ probe begin
+ {
+ printf("systemtap starting probe\n")
+ }
+ probe process("%s").insn.block
+ {
+ branches += 1
+ if (branches == 5)
+ exit()
+ }
+
+
+ probe end { printf("systemtap ending probe\n")
+ printf("itraced block mode = %%d\n", branches)
+ }
+}
+set itrace3_script_output "itraced block mode = 5\r\n"
+
# Set up our own copy of /bin/ls, to make testing for a particular
# executable easy. We can't use 'ln' here, since we might be creating
@@ -75,14 +91,8 @@ proc run_ls_5_sec {} {
}
-# Try to find utrace_attach symbol in /proc/kallsyms
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-
set TEST_NAME "itrace1"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested $TEST_NAME
@@ -93,7 +103,7 @@ if {$utrace_support_found == 0} {
set TEST_NAME "itrace2"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested $TEST_NAME
@@ -102,5 +112,16 @@ if {$utrace_support_found == 0} {
stap_run $TEST_NAME run_ls_5_sec $itrace2_script_output -e $script
}
+set TEST_NAME "itrace3"
+if {![utrace_p]} {
+ untested "$TEST_NAME : no kernel utrace support found"
+} elseif {![installtest_p]} {
+ untested $TEST_NAME
+} else {
+ send_log "ATTENTION: if arch_has_block_step is not defined for this arch, this testcase will fail\n"
+ set script [format $itrace3_script $exepath]
+ stap_run $TEST_NAME run_ls_5_sec $itrace3_script_output -e $script
+}
+
# Cleanup
exec rm -f $exepath
diff --git a/testsuite/systemtap.base/kprobes.exp b/testsuite/systemtap.base/kprobes.exp
new file mode 100644
index 00000000..635930f8
--- /dev/null
+++ b/testsuite/systemtap.base/kprobes.exp
@@ -0,0 +1,2 @@
+set test "kprobes"
+stap_run $srcdir/$subdir/$test.stp no_load "probe point hit"
diff --git a/testsuite/systemtap.base/kprobes.stp b/testsuite/systemtap.base/kprobes.stp
new file mode 100644
index 00000000..884b321c
--- /dev/null
+++ b/testsuite/systemtap.base/kprobes.stp
@@ -0,0 +1,25 @@
+/*
+ * kprobes.stp
+ * Probe to test the functionality of kprobe-based probes
+ * (Dwarfless Probing)
+ */
+global hit_str
+
+probe begin
+{
+ println("systemtap starting probe");
+ hit_str = ""
+}
+
+probe kprobe.function("vfs_read")
+{
+ hit_str = "probe point hit"
+ exit();
+}
+
+probe end
+{
+ println("systemtap ending probe");
+ println(hit_str);
+ delete hit_str;
+}
diff --git a/testsuite/systemtap.base/labels.exp b/testsuite/systemtap.base/labels.exp
index 6db81c54..79e3f483 100644
--- a/testsuite/systemtap.base/labels.exp
+++ b/testsuite/systemtap.base/labels.exp
@@ -1,14 +1,6 @@
set test "labels"
if {![installtest_p]} {untested $test; return}
-
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} { untested "$test"; return }
+if {![utrace_p]} { untested $test; return }
# Compile a C program to use as the user-space probing target
set label_srcpath "[pwd]/labels.c"
@@ -18,15 +10,22 @@ set label_flags "additional_flags=-g"
set fp [open $label_srcpath "w"]
puts $fp "
int
+foo ()
+{
+init_an_int:
+ return 1;
+}
+int
main ()
{
sleep(5);
+ foo();
int a = 0;
int b = 0;
char *c;
init_an_int:
a = 2;
-init_another_int:
+init_an_int_again:
b = 3;
c = \"abc\";
ptr_inited:
@@ -38,8 +37,9 @@ close $fp
set label_stppath "[pwd]/labels.stp"
set fp [open $label_stppath "w"]
puts $fp "
-probe process(\"labels.x\").function(\"main*@labels.c\").label(\"init_*\") {printf (\"VARS %s\\n\",\$\$vars)}
-probe process(\"labels.x\").function(\"main*@labels.c\").label(\"ptr_inited\") {printf (\"VARS %s\\n\",\$\$vars)}
+probe process(\"labels.x\").function(\"main@labels.c\").label(\"init_*\") {printf (\"VARS %s\\n\",\$\$vars)}
+probe process(\"labels.x\").function(\"main@labels.c\").label(\"ptr_inited\") {printf (\"VARS %s\\n\",\$\$vars)}
+probe process(\"labels.x\").function(\"main@labels.c\").label(\"init_an_int\") {printf (\"init_an_int\\n\")}
"
close $fp
@@ -55,20 +55,66 @@ if { $res != "" } {
pass "compiling labels.c -g"
}
+# line number error
+
+set ok 0
+spawn stap -l "process(\"$label_exepath\").function(\"foo@${label_srcpath}:10\").label(\"*\")"
+
+wait
+expect {
+ -timeout 180
+ -re {no match while resolving probe point} { incr ok; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+
+if {$ok == 1} { pass "$test :N .label" } { fail "$test :N .label $ok" }
+
+# line number
+
+set ok 0
+spawn stap -l "process(\"$label_exepath\").function(\"foo@${label_srcpath}:4\").label(\"*\")"
+
+wait
+expect {
+ -timeout 180
+ -re {process.*function.*labels.c:5...label..init_an_int} { incr ok; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+
+if {$ok == 1} { pass "$test :N .label" } { fail "$test :N .label $ok" }
+
+# list of labels
+
+spawn stap -l "process(\"$label_exepath\").function(\"*\").label(\"*\")"
+
+wait
+set ok 0
+expect {
+ -timeout 180
+ -re {process.*function.*labels.c:5...label..init_an_int.*process.*function.*labels.c:16...label..init_an_int.*process.*function.*labels.c:18...label..init_an_int_again} { incr ok; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+
+if {$ok == 1} { pass "$test -l .label" } { fail "$test -l .label $ok" }
+
# label in an executable
+set ok 0
verbose -log "spawn stap -c $label_exepath $label_stppath"
spawn stap -c $label_exepath $label_stppath
wait
expect {
-timeout 180
- -re {VARS a=0x0 b=0x0.*VARS a=0x2 b=0x0.*VARS a=0x2 b=0x3 c=0x[a-f01-9]} { incr ok; exp_continue }
+ -re {VARS a=0x0 b=0x0.*init_an_int.*VARS a=0x2 b=0x0.*VARS a=0x2 b=0x3 c=0x[a-f01-9]} { incr ok; exp_continue }
timeout { fail "$test (timeout)" }
eof { }
}
-if {$ok == 1} { pass "$test exe .label" } { fail "$test exe .label" }
+if {$ok == 1} { pass "$test exe .label" } { fail "$test exe .label $ok" }
# address of label in an executable
@@ -76,7 +122,7 @@ set label_shpath "[pwd]/label.sh"
set fp [open $label_shpath "w"]
puts $fp "
readelf --debug-dump $label_exepath | awk \"
-/init_another_int/ {have_label=1}
+/init_an_int_again/ {have_label=1}
/DW_AT_low_pc/ {if (have_label) {print \$3;exit;}}
\"
"
@@ -111,7 +157,7 @@ if { $res != "" } {
# label in a shared object
-spawn stap -p2 -l "process\(\"$label_sopath\"\).function\(\"\*\"\).label\(\"init_another_int\"\)"
+spawn stap -p2 -l "process\(\"$label_sopath\"\).function\(\"\*\"\).label\(\"init_an_int_again\"\)"
expect {
-timeout 180
-re {process.*function} { incr ok; exp_continue }
@@ -119,7 +165,7 @@ expect {
eof { }
}
-if {$ok == 1} { pass "$test so .label" } { fail "$test so .label" }
+if {$ok == 1} { pass "$test so .label" } { fail "$test so .label $ok" }
# address of label in a shared object
@@ -127,7 +173,7 @@ set label_shpath "[pwd]/label.sh"
set fp [open $label_shpath "w"]
puts $fp "
readelf --debug-dump $label_sopath | awk \"
-/init_another_int/ {have_label=1}
+/init_an_int_again/ {have_label=1}
/DW_AT_low_pc/ {if (have_label) {print \$3;exit;}}
\"
"
diff --git a/testsuite/systemtap.base/maxactive.exp b/testsuite/systemtap.base/maxactive.exp
index 7c03a1bf..79ede897 100644
--- a/testsuite/systemtap.base/maxactive.exp
+++ b/testsuite/systemtap.base/maxactive.exp
@@ -10,12 +10,12 @@ proc sleep_five_sec {} {
return 0;
}
-# Script1. For 5 seconds, probe the return of "sys_select" and
-# "sys_read". See if we skip any probes.
+# Script1. For 5 seconds, probe the return of "vfs_read" and
+# "do_select". See if we skip any probes.
set script1 {
global foo
- probe kernel.function("sys_select").return,
- kernel.function("sys_read").return { foo++ }
+ probe kernel.function("vfs_read").return,
+ kernel.function("do_select").return { foo++ }
probe timer.ms(5000) { exit(); }
probe begin { log("systemtap starting probe"); log("systemtap ending probe");}
@@ -26,13 +26,13 @@ set script1 {
stap_run "MAXACTIVE01" sleep_five_sec "" -e $script1
set skipped1 $skipped_probes
-# Script2. For 5 seconds, probe the return of "sys_select" and
-# "sys_read", with a limit of 1 probe active at a time. See if we
+# Script2. For 5 seconds, probe the return of "vfs_read" and
+# "do_select", 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) { foo++ }
+ probe kernel.function("vfs_read").return.maxactive(1),
+ kernel.function("do_select").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/onoffprobe.stp b/testsuite/systemtap.base/onoffprobe.stp
index f7169039..79c41a3c 100644
--- a/testsuite/systemtap.base/onoffprobe.stp
+++ b/testsuite/systemtap.base/onoffprobe.stp
@@ -10,13 +10,13 @@ probe begin if (switch==0) {
}
#dwarf probe (return)
-probe kernel.function("sys_write").return if (switch == 1) {
+probe kernel.function("vfs_write").return if (switch == 1) {
log("function return probed")
switch = 0
}
#dwarf probe (entry)
-probe kernel.function("sys_write") if (switch == 2) {
+probe kernel.function("vfs_write").return if (switch == 2) {
log("function entry probed")
switch = 0
}
diff --git a/testsuite/systemtap.base/optionalprobe.exp b/testsuite/systemtap.base/optionalprobe.exp
new file mode 100644
index 00000000..5484003c
--- /dev/null
+++ b/testsuite/systemtap.base/optionalprobe.exp
@@ -0,0 +1,9 @@
+set test "optionalprobe"
+spawn stap -p2 -w $srcdir/$subdir/$test.stp
+expect {
+ -timeout 60
+ -re "# probes\r\n" { exp_continue }
+ -re "^begin" { pass $test }
+ eof { fail $test }
+ timeout { fail "$test unexpected timeout" }
+}
diff --git a/testsuite/systemtap.base/optionalprobe.stp b/testsuite/systemtap.base/optionalprobe.stp
new file mode 100644
index 00000000..13918cee
--- /dev/null
+++ b/testsuite/systemtap.base/optionalprobe.stp
@@ -0,0 +1,14 @@
+#! stap
+
+# test optional probe
+
+probe foo ?,
+ process("/do/not/exist").function("main") !,
+ kernel.mark("no such mark") ?,
+ kernel.trace("no trace") !,
+ process.foo ?,
+ kernel.statement("no statement") !,
+ module("no mod").function("*") ?,
+ kernel.function("no such func*") !,
+ begin {
+}
diff --git a/testsuite/systemtap.base/overload.exp b/testsuite/systemtap.base/overload.exp
index cbcbe817..ac9ceb24 100644
--- a/testsuite/systemtap.base/overload.exp
+++ b/testsuite/systemtap.base/overload.exp
@@ -8,7 +8,7 @@ set script {
k["foo"] = 0
}
- probe kernel.function("sys_read"), kernel.function("sys_write") {
+ probe kernel.function("vfs_read"), kernel.function("vfs_write") {
k["foo"]++
}
probe end {
diff --git a/testsuite/systemtap.base/sdt.exp b/testsuite/systemtap.base/sdt.exp
index 74818beb..c3aed91e 100644
--- a/testsuite/systemtap.base/sdt.exp
+++ b/testsuite/systemtap.base/sdt.exp
@@ -10,11 +10,12 @@ set ::result_string {1
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10}
-set extra_flags {{""} {additional_flags=-std=gnu89} {additional_flags=-ansi} {additional_flags=-pedantic}}
+set extra_flags {{""} {additional_flags=-std=gnu89} {additional_flags=-ansi} {additional_flags=-pedantic} {additional_flags=-ansi additional_flags=-pedantic} {additional_flags=-O2} {additional_flags="-O3"}}
# Iterate extra_flags, trying each with C and C++
for {set i 0} {$i < [llength $extra_flags]} {incr i} {
set extra_flag [lindex $extra_flags $i]
+set testprog "sdt.c.exe.$i"
# C
set test_flags "additional_flags=-g"
@@ -23,44 +24,47 @@ set test_flags "$test_flags additional_flags=-Wall"
set test_flags "$test_flags additional_flags=-Wextra"
set test_flags "$test_flags additional_flags=-Werror"
-set res [target_compile $srcdir/$subdir/$test.c $test.prog executable "$test_flags $extra_flag"]
+set saveidx 0
+
+set res [target_compile $srcdir/$subdir/$test.c $testprog executable "$test_flags $extra_flag"]
if { $res != "" } {
verbose "target_compile failed: $res" 2
fail "compiling $test.c $extra_flag"
- return
+ untested "$test $extra_flag"
+ continue
} else {
pass "compiling $test.c $extra_flag"
}
-if {[installtest_p]} {
-# XXX: we need distinct test names for these
- stap_run2 $srcdir/$subdir/$test.stp -c ./$test.prog
+if {[installtest_p] && [utrace_p]} {
+ stap_run3 "$test $extra_flag" $srcdir/$subdir/$test.stp $testprog -c ./$testprog
} else {
untested "$test $extra_flag"
}
# C++
+set testprog "sdt.cxx.exe.$i"
+
set test_flags "additional_flags=-g"
set test_flags "$test_flags additional_flags=-I$srcdir/../includes/sys"
set test_flags "$test_flags additional_flags=-Wall"
set test_flags "$test_flags additional_flags=-Werror"
set test_flags "$test_flags additional_flags=-x additional_flags=c++"
-set res [target_compile $srcdir/$subdir/$test.c $test.prog executable "$test_flags $extra_flag"]
+set res [target_compile $srcdir/$subdir/$test.c $testprog executable "$test_flags $extra_flag"]
if { $res != "" } {
verbose "target_compile failed: $res" 2
fail "compiling $test.c c++ $extra_flag"
- return
+ untested "$test $extra_flag"
+ continue
} else {
pass "compiling $test.c c++ $extra_flag"
}
-if {[installtest_p]} {
-# XXX: we need distinct test names for these
- stap_run2 $srcdir/$subdir/$test.stp -c ./$test.prog
+if {[installtest_p] && [utrace_p]} {
+ stap_run3 "$test c++ $extra_flag" $srcdir/$subdir/$test.stp $testprog -c ./$testprog
} else {
untested "$test c++ $extra_flag"
}
}
-catch {exec rm -f $test.prog}
diff --git a/testsuite/systemtap.base/sdt.stp b/testsuite/systemtap.base/sdt.stp
index 1f075bca..5df1fdc9 100644
--- a/testsuite/systemtap.base/sdt.stp
+++ b/testsuite/systemtap.base/sdt.stp
@@ -1,49 +1,49 @@
-probe process("sdt.prog").mark("mark_a")
+probe process(@1).mark("mark_a")
{
printf("%d\n", $arg1);
}
-probe process("sdt.prog").mark("mark_b")
+probe process(@1).mark("mark_b")
{
printf("%d %d\n", $arg1, $arg2);
}
-probe process("sdt.prog").mark("mark_c")
+probe process(@1).mark("mark_c")
{
printf("%d %d %d\n", $arg1, $arg2, $arg3);
}
-probe process("sdt.prog").mark("mark_d")
+probe process(@1).mark("mark_d")
{
printf("%d %d %d %d\n", $arg1, $arg2, $arg3, $arg4);
}
-probe process("sdt.prog").mark("mark_e")
+probe process(@1).mark("mark_e")
{
printf("%d %d %d %d %d\n", $arg1, $arg2, $arg3, $arg4, $arg5);
}
-probe process("sdt.prog").mark("mark_f")
+probe process(@1).mark("mark_f")
{
printf("%d %d %d %d %d %d\n", $arg1, $arg2, $arg3, $arg4, $arg5, $arg6);
}
-probe process("sdt.prog").mark("mark_g")
+probe process(@1).mark("mark_g")
{
printf("%d %d %d %d %d %d %d\n", $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7);
}
-probe process("sdt.prog").mark("mark_h")
+probe process(@1).mark("mark_h")
{
printf("%d %d %d %d %d %d %d %d\n", $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8);
}
-probe process("sdt.prog").mark("mark_i")
+probe process(@1).mark("mark_i")
{
printf("%d %d %d %d %d %d %d %d %d\n", $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8, $arg9);
}
-probe process("sdt.prog").mark("mark_j")
+probe process(@1).mark("mark_j")
{
printf("%d %d %d %d %d %d %d %d %d %d\n", $arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7, $arg8, $arg9, $arg10);
}
diff --git a/testsuite/systemtap.base/sdt_types.c b/testsuite/systemtap.base/sdt_types.c
new file mode 100644
index 00000000..2e04ec7e
--- /dev/null
+++ b/testsuite/systemtap.base/sdt_types.c
@@ -0,0 +1,168 @@
+#include "sdt.h" /* Really <sys/sdt.h>, but pick current source version. */
+#include <stdint.h>
+#include <values.h>
+
+int
+main (int argc, char **argv)
+{
+ char char_var = '~';
+ STAP_PROBE1(provider,char_var,char_var);
+ const char const_char_var = '!';
+ STAP_PROBE1(provider,const_char_var,const_char_var);
+ volatile char volatile_char_var = '!';
+ STAP_PROBE1(provider,volatile_char_var,volatile_char_var);
+ char *ptr_char_var = &char_var;
+ STAP_PROBE2(provider,ptr_char_var,ptr_char_var,&char_var);
+ const char *ptr_const_char_var = &char_var;
+ STAP_PROBE2(provider,ptr_const_char_var,ptr_const_char_var,&char_var);
+ char * const char_ptr_const_var = &char_var;
+ STAP_PROBE2(provider,char_ptr_const_var,char_ptr_const_var,&char_var);
+ volatile char *ptr_volatile_char_var = &char_var;
+ STAP_PROBE2(provider,ptr_volatile_char_var,ptr_volatile_char_var,&char_var);
+ char * volatile char_ptr_volatile_var = &char_var;
+ STAP_PROBE2(provider,char_ptr_volatile_var,char_ptr_volatile_var,&char_var);
+ short int short_int_var = 32767;
+ STAP_PROBE1(provider,short_int_var,short_int_var);
+ const short int const_short_int_var = -32767;
+ STAP_PROBE1(provider,const_short_int_var,const_short_int_var);
+ volatile short int volatile_short_int_var = -32767;
+ STAP_PROBE1(provider,volatile_short_int_var,volatile_short_int_var);
+ short int *ptr_short_int_var = &short_int_var;
+ STAP_PROBE2(provider,ptr_short_int_var,ptr_short_int_var,&short_int_var);
+ const short int *ptr_const_short_int_var = &short_int_var;
+ STAP_PROBE2(provider,ptr_const_short_int_var,ptr_const_short_int_var,&short_int_var);
+ short int * const short_int_ptr_const_var = &short_int_var;
+ STAP_PROBE2(provider,short_int_ptr_const_var,short_int_ptr_const_var,&short_int_var);
+ volatile short int *ptr_volatile_short_int_var = &short_int_var;
+ STAP_PROBE2(provider,ptr_volatile_short_int_var,ptr_volatile_short_int_var,&short_int_var);
+ short int * volatile short_int_ptr_volatile_var = &short_int_var;
+ STAP_PROBE2(provider,short_int_ptr_volatile_var,short_int_ptr_volatile_var,&short_int_var);
+ int int_var = 65536;
+ STAP_PROBE1(provider,int_var,int_var);
+ const int const_int_var = -65536;
+ STAP_PROBE1(provider,const_int_var,const_int_var);
+ volatile int volatile_int_var = -65536;
+ STAP_PROBE1(provider,volatile_int_var,volatile_int_var);
+ int *ptr_int_var = &int_var;
+ STAP_PROBE2(provider,ptr_int_var,ptr_int_var,&int_var);
+ const int *ptr_const_int_var = &int_var;
+ STAP_PROBE2(provider,ptr_const_int_var,ptr_const_int_var,&int_var);
+ int * const int_ptr_const_var = &int_var;
+ STAP_PROBE2(provider,int_ptr_const_var,int_ptr_const_var,&int_var);
+ volatile int *ptr_volatile_int_var = &int_var;
+ STAP_PROBE2(provider,ptr_volatile_int_var,ptr_volatile_int_var,&int_var);
+ int * volatile int_ptr_volatile_var = &int_var;
+ STAP_PROBE2(provider,int_ptr_volatile_var,int_ptr_volatile_var,&int_var);
+ long int long_int_var = 65536;
+ STAP_PROBE1(provider,long_int_var,long_int_var);
+ const long int const_long_int_var = -65536;
+ STAP_PROBE1(provider,const_long_int_var,const_long_int_var);
+ volatile long int volatile_long_int_var = -65536;
+ STAP_PROBE1(provider,volatile_long_int_var,volatile_long_int_var);
+ long int *ptr_long_int_var = &long_int_var;
+ STAP_PROBE2(provider,ptr_long_int_var,ptr_long_int_var,&long_int_var);
+ const long int *ptr_const_long_int_var = &long_int_var;
+ STAP_PROBE2(provider,ptr_const_long_int_var,ptr_const_long_int_var,&long_int_var);
+ long int * const long_int_ptr_const_var = &long_int_var;
+ STAP_PROBE2(provider,long_int_ptr_const_var,long_int_ptr_const_var,&long_int_var);
+ volatile long int *ptr_volatile_long_int_var = &long_int_var;
+ STAP_PROBE2(provider,ptr_volatile_long_int_var,ptr_volatile_long_int_var,&long_int_var);
+ long int * volatile long_int_ptr_volatile_var = &long_int_var;
+ STAP_PROBE2(provider,long_int_ptr_volatile_var,long_int_ptr_volatile_var,&long_int_var);
+ long long int long_long_int_var = 65536;
+ STAP_PROBE1(provider,long_long_int_var,long_long_int_var);
+ const long long int const_long_long_int_var = -65536;
+ STAP_PROBE1(provider,const_long_long_int_var,const_long_long_int_var);
+ volatile long long int volatile_long_long_int_var = -65536;
+ STAP_PROBE1(provider,volatile_long_long_int_var,volatile_long_long_int_var);
+ long long int *ptr_long_long_int_var = &long_long_int_var;
+ STAP_PROBE2(provider,ptr_long_long_int_var,ptr_long_long_int_var,&long_long_int_var);
+ const long long int *ptr_const_long_long_int_var = &long_long_int_var;
+ STAP_PROBE2(provider,ptr_const_long_long_int_var,ptr_const_long_long_int_var,&long_long_int_var);
+ long long int * const long_long_int_ptr_const_var = &long_long_int_var;
+ STAP_PROBE2(provider,long_long_int_ptr_const_var,long_long_int_ptr_const_var,&long_long_int_var);
+ volatile long long int *ptr_volatile_long_long_int_var = &long_long_int_var;
+ STAP_PROBE2(provider,ptr_volatile_long_long_int_var,ptr_volatile_long_long_int_var,&long_long_int_var);
+ long long int * volatile long_long_int_ptr_volatile_var = &long_long_int_var;
+ STAP_PROBE2(provider,long_long_int_ptr_volatile_var,long_long_int_ptr_volatile_var,&long_long_int_var);
+
+ char arr_char [2] = "!~";
+ STAP_PROBE1(provider,arr_char,&arr_char);
+ struct {
+ int int_var;
+ } arr_struct [2] = {{
+ .int_var=1,
+ },{
+ .int_var=2,
+ }};
+ STAP_PROBE1(provider,arr_struct,&arr_struct);
+ struct {
+ unsigned int bit1_0:1;
+ unsigned int bit1_1:1;
+ char char_2;
+ unsigned int bit1_6:1;
+ unsigned int bit1_7:1;
+ char char_8;
+ unsigned int bit1_9:1;
+ unsigned int bit1_10:1;
+ } bitfields_small_var = {
+ .bit1_0=1,
+ .bit1_1=0,
+ .char_2='a',
+ .bit1_6=1,
+ .bit1_7=0,
+ .char_8='z',
+ .bit1_9=1,
+ .bit1_10=0,
+ };
+ STAP_PROBE8(provider,bitfields_small_var,
+ (int)bitfields_small_var.bit1_0,
+ (int)bitfields_small_var.bit1_1,
+ bitfields_small_var.char_2,
+ (int)bitfields_small_var.bit1_6,
+ (int)bitfields_small_var.bit1_7,
+ bitfields_small_var.char_8,
+ (int)bitfields_small_var.bit1_9,
+ (int)bitfields_small_var.bit1_10);
+ struct {
+ unsigned char char_0;
+ int bit1_4:1;
+ unsigned int bit1_5:1;
+ int bit2_6:2;
+ unsigned int bit2_8:2;
+ int bit3_10:3;
+ unsigned int bit3_13:3;
+ int bit9_16:9;
+ unsigned int bit9_25:9;
+ char char_34;
+ } bitfields_bit_var = {
+ .char_0='A',
+ .bit1_4=-1,
+ .bit1_5=1,
+ .bit2_6=1,
+ .bit2_8=3,
+ .bit3_10=3,
+ .bit3_13=7,
+ .bit9_16=255,
+ .bit9_25=511,
+ .char_34='Z',
+ };
+ STAP_PROBE10(provider,bitfields_bit_var,bitfields_bit_var.char_0,
+ (int)bitfields_bit_var.bit1_4,
+ (int)bitfields_bit_var.bit1_5,
+ (int)bitfields_bit_var.bit2_6,
+ (int)bitfields_bit_var.bit2_8,
+ (int)bitfields_bit_var.bit3_10,
+ (int)bitfields_bit_var.bit3_13,
+ (int)bitfields_bit_var.bit9_16,
+ (int)bitfields_bit_var.bit9_25,
+ bitfields_bit_var.char_34);
+ enum {
+ red = 0,
+ green = 1,
+ blue = 2
+ } primary_colors_var = green;
+ STAP_PROBE1(provider,primary_colors_var,primary_colors_var);
+ return 0;
+}
+
diff --git a/testsuite/systemtap.base/sdt_types.stp b/testsuite/systemtap.base/sdt_types.stp
new file mode 100644
index 00000000..654b0d18
--- /dev/null
+++ b/testsuite/systemtap.base/sdt_types.stp
@@ -0,0 +1,371 @@
+probe process(@1).mark("char_var") {
+ if ($arg1 != 126)
+ printf("FAIL: char_var\n")
+ else
+ printf("PASS: char_var\n")
+}
+
+probe process(@1).mark("const_char_var") {
+ if ($arg1 != 33)
+ printf("FAIL: const_char_var\n")
+ else
+ printf("PASS: const_char_var\n")
+}
+
+probe process(@1).mark("volatile_char_var") {
+ if ($arg1 != 33)
+ printf("FAIL: volatile_char_var\n")
+ else
+ printf("PASS: volatile_char_var\n")
+}
+
+probe process(@1).mark("ptr_char_var") {
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_char_var\n")
+ else
+ printf("PASS: ptr_char_var\n")
+}
+
+probe process(@1).mark("ptr_const_char_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_const_char_var\n")
+ else
+ printf("PASS: ptr_const_char_var\n")
+}
+
+probe process(@1).mark("char_ptr_const_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: char_ptr_const_var\n")
+ else
+ printf("PASS: char_ptr_const_var\n")
+}
+
+probe process(@1).mark("ptr_volatile_char_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_volatile_char_var\n")
+ else
+ printf("PASS: ptr_volatile_char_var\n")
+}
+
+probe process(@1).mark("char_ptr_volatile_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: char_ptr_volatile_var\n")
+ else
+ printf("PASS: char_ptr_volatile_var\n")
+}
+
+probe process(@1).mark("short_int_var")
+{
+ if ($arg1 != 32767)
+ printf("FAIL: short_int_var\n")
+ else
+ printf("PASS: short_int_var\n")
+}
+
+probe process(@1).mark("const_short_int_var")
+{
+ if ($arg1 != -32767)
+ printf("FAIL: const_short_int_var\n")
+ else
+ printf("PASS: const_short_int_var\n")
+}
+
+probe process(@1).mark("volatile_short_int_var")
+{
+ if ($arg1 != -32767)
+ printf("FAIL: volatile_short_int_var\n")
+ else
+ printf("PASS: volatile_short_int_var\n")
+}
+
+probe process(@1).mark("ptr_short_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_short_int_var\n")
+ else
+ printf("PASS: ptr_short_int_var\n")
+}
+
+probe process(@1).mark("ptr_const_short_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_const_short_int_var\n")
+ else
+ printf("PASS: ptr_const_short_int_var\n")
+}
+
+probe process(@1).mark("short_int_ptr_const_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: short_int_ptr_const_var\n")
+ else
+ printf("PASS: short_int_ptr_const_var\n")
+}
+
+probe process(@1).mark("ptr_volatile_short_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_volatile_short_int_var\n")
+ else
+ printf("PASS: ptr_volatile_short_int_var\n")
+}
+
+probe process(@1).mark("short_int_ptr_volatile_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: short_int_ptr_volatile_var\n")
+ else
+ printf("PASS: short_int_ptr_volatile_var\n")
+}
+
+probe process(@1).mark("int_var")
+{
+ if ($arg1 != 65536)
+ printf("FAIL: int_var")
+ else
+ printf("PASS: int_var")
+}
+
+probe process(@1).mark("const_int_var")
+{
+ if ($arg1 != -65536)
+ printf("FAIL: const_int_var\n")
+ else
+ printf("PASS: const_int_var\n")
+}
+
+probe process(@1).mark("volatile_int_var")
+{
+ if ($arg1 != -65536)
+ printf("FAIL: volatile_int_var\n")
+ else
+ printf("PASS: volatile_int_var\n")
+}
+
+probe process(@1).mark("ptr_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_const_int_var\n")
+ else
+ printf("PASS: ptr_const_int_var\n")
+}
+
+probe process(@1).mark("ptr_const_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_const_int_var\n")
+ else
+ printf("PASS: ptr_const_int_var\n")
+}
+
+probe process(@1).mark("int_ptr_const_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: int_ptr_const_var\n")
+ else
+ printf("PASS: int_ptr_const_var\n")
+}
+
+probe process(@1).mark("ptr_volatile_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_volatile_int_var\n")
+ else
+ printf("PASS: ptr_volatile_int_var\n")
+}
+
+probe process(@1).mark("int_ptr_volatile_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: int_ptr_volatile_var\n")
+ else
+ printf("PASS: int_ptr_volatile_var\n")
+}
+
+probe process(@1).mark("long_int_var")
+{
+ if ($arg1 != 65536)
+ printf("FAIL: long_int_var\n")
+ else
+ printf("PASS: long_int_var\n")
+}
+
+probe process(@1).mark("const_long_int_var")
+{
+ if ($arg1 != -65536)
+ printf("FAIL: const_long_int_var\n")
+ else
+ printf("PASS: const_long_int_var\n")
+}
+
+probe process(@1).mark("volatile_long_int_var")
+{
+ if ($arg1 != -65536)
+ printf("FAIL: volatile_long_int_var\n")
+ else
+ printf("PASS: volatile_long_int_var\n")
+}
+
+probe process(@1).mark("ptr_long_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_long_int_var\n")
+ else
+ printf("PASS: ptr_long_int_var\n")
+}
+
+probe process(@1).mark("ptr_const_long_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_const_long_int_var\n")
+ else
+ printf("PASS: ptr_const_long_int_var\n")
+}
+
+probe process(@1).mark("long_int_ptr_const_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: long_int_ptr_const_var\n")
+ else
+ printf("PASS: long_int_ptr_const_var\n")
+}
+
+probe process(@1).mark("ptr_volatile_long_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_volatile_long_int_var\n")
+ else
+ printf("PASS: ptr_volatile_long_int_var\n")
+}
+
+probe process(@1).mark("long_int_ptr_volatile_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: long_int_ptr_volatile_var\n")
+ else
+ printf("PASS: long_int_ptr_volatile_var\n")
+}
+
+probe process(@1).mark("long_long_int_var")
+{
+ if ($arg1 != 65536)
+ printf("FAIL: long_long_int_var\n")
+ else
+ printf("PASS: long_long_int_var\n")
+}
+
+probe process(@1).mark("const_long_long_int_var")
+{
+ if ($arg1 != -65536)
+ printf("FAIL: const_long_long_int_var\n")
+ else
+ printf("PASS: const_long_long_int_var\n")
+}
+
+probe process(@1).mark("volatile_long_long_int_var")
+{
+ if ($arg1 != -65536)
+ printf("FAIL: volatile_long_long_int_var\n")
+ else
+ printf("PASS: volatile_long_long_int_var\n")
+}
+
+probe process(@1).mark("ptr_long_long_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_long_long_int_var\n")
+ else
+ printf("PASS: ptr_long_long_int_var\n")
+}
+
+probe process(@1).mark("ptr_const_long_long_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_const_long_long_int_var\n")
+ else
+ printf("PASS: ptr_const_long_long_int_var\n")
+}
+
+probe process(@1).mark("long_long_int_ptr_const_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: long_long_int_ptr_const_var\n")
+ else
+ printf("PASS: long_long_int_ptr_const_var\n")
+}
+
+probe process(@1).mark("ptr_volatile_long_long_int_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: ptr_volatile_long_long_int_var\n")
+ else
+ printf("PASS: ptr_volatile_long_long_int_var\n")
+}
+
+probe process(@1).mark("long_long_int_ptr_volatile_var")
+{
+ if ($arg1 != $arg2)
+ printf("FAIL: long_long_int_ptr_volatile_var\n")
+ else
+ printf("PASS: long_long_int_ptr_volatile_var\n")
+}
+
+probe process(@1).mark("arr_char")
+{
+ arr_char = user_string ($arg1);
+ if (arr_char != "!~")
+ printf("FAIL: arr_char_var\n")
+ else
+ printf("PASS: arr_char_var\n")
+}
+
+probe process(@1).mark("arr_struct")
+{
+ arr_struct_int_var = user_int ($arg1)
+ if (arr_struct_int_var != 1)
+ printf("FAIL: arr_struct_var\n")
+ else
+ printf("PASS: arr_struct_var\n")
+}
+
+probe process(@1).mark("bitfields_small_var")
+{
+ if ($arg1 != 1 || $arg2 != 0 || $arg3 != 97 || $arg4 != 1
+ || $arg5 != 0 || $arg6 != 122 || $arg7 != 1 || $arg8 != 0)
+ printf("FAIL: bitfields_small_var\n")
+
+}
+
+probe process(@1).mark("bitfields_bit_var")
+{
+ if ($arg1 != 65 || $arg2 != -1 || $arg3 != 1 || $arg4 != 1
+ || $arg5 != 3 || $arg6 != 3 || $arg7 != 7 || $arg8 != 255
+ || $arg9 != 511 || $arg10 != 90)
+ printf("FAIL: bitfields_bit_var\n")
+ else
+ printf("PASS: bitfields_bit_var\n")
+}
+
+
+probe process(@1).mark("primary_colors_var")
+{
+ if ($arg1 != 1)
+ printf("FAIL: primary_colors_var\n")
+ else
+ printf("PASS: primary_colors_var\n")
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testsuite/systemtap.base/skipped.exp b/testsuite/systemtap.base/skipped.exp
index 8c491037..f3048c8a 100644
--- a/testsuite/systemtap.base/skipped.exp
+++ b/testsuite/systemtap.base/skipped.exp
@@ -2,8 +2,8 @@ set test "skip tracking"
if {! [installtest_p]} { untested $test; return }
-set cpus [exec sh -c "grep ^processor /proc/cpuinfo | wc -l"]
-if {$cpus < 2} { unsupported $test; return }
+set nr_cpus [exec sh -c "grep ^processor /proc/cpuinfo | wc -l"]
+if {$nr_cpus < 2} { unsupported $test; return }
set ok 0
spawn stap -e "probe timer.s(5) {exit()} probe timer.profile,syscall.* {f++} global f" -DMAXTRYLOCK=0 -tu
@@ -18,4 +18,4 @@ expect {
catch {close}
catch {wait}
-if {$ok >= 3} { pass "$test ($cpus $ok)" } else { fail "$test ($cpus $ok)" }
+if {$ok >= 3} { pass "$test ($nr_cpus $ok)" } else { fail "$test ($nr_cpus $ok)" }
diff --git a/testsuite/systemtap.base/static_uprobes.exp b/testsuite/systemtap.base/static_uprobes.exp
index a4bd5e2c..1e53d5d3 100644
--- a/testsuite/systemtap.base/static_uprobes.exp
+++ b/testsuite/systemtap.base/static_uprobes.exp
@@ -1,5 +1,6 @@
+set test "static_uprobes"
-set test "sduprobes"
+# Test miscellaneous features of .mark probes
# Compile a C program to use as the user-space probing target
set sup_srcpath "[pwd]/static_uprobes.c"
@@ -81,6 +82,9 @@ provider static_uprobes {
};
"
close $fp
+
+# Test dtrace
+
if {[installtest_p]} {
set dtrace $env(SYSTEMTAP_PATH)/dtrace
} else {
@@ -89,11 +93,10 @@ if {[installtest_p]} {
if {[catch {exec $dtrace -h -s $sup_dpath} res]} {
verbose -log "unable to run $dtrace: $res"
}
-catch {exec rm -f $sup_dpath}
if {[file exists $sup_hpath]} then {
- pass "$test generating header"
+ pass "$test dtrace"
} else {
- fail "$test generating header"
+ fail "$test dtrace"
catch {exec rm -f $sup_srcpath $sup_hpath $sup_stppath}
return
}
@@ -104,7 +107,11 @@ if {[installtest_p]} {
set sdtdir $srcdir/../includes
}
-set sup_flags "additional_flags=-I$sdtdir additional_flags=-g additional_flags=-O additional_flags=-I."
+set sup_flags "additional_flags=-I$srcdir/../includes/sys"
+set sup_flags "$sup_flags additional_flags=-I$sdtdir"
+set sup_flags "$sup_flags additional_flags=-g"
+set sup_flags "$sup_flags additional_flags=-O"
+set sup_flags "$sup_flags additional_flags=-I."
set res [target_compile $sup_srcpath $sup_exepath executable $sup_flags]
if { $res != "" } {
verbose "target_compile failed: $res" 2
@@ -115,34 +122,15 @@ if { $res != "" } {
pass "$test compiling C -g"
}
-spawn mv $sup_srcpath "[pwd]/static_uprobes.cc"
-set sup_srcpath "[pwd]/static_uprobes.cc"
-set sup_flags "$sup_flags c++"
-set res [target_compile $sup_srcpath $supcplus_exepath executable $sup_flags]
-if { $res != "" } {
- verbose "target_compile failed: $res" 2
- fail "$test compiling C++ -g"
- catch {exec rm -f $sup_srcpath $sup_exepath $sup_hpath $sup_stppath}
- return
-} else {
- pass "$test compiling C++ -g"
-}
-
if {![installtest_p]} {untested $test; return}
-
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$test"
catch {exec rm -f $sup_srcpath}
return
}
+# Run stap on executable built with dtrace generated header file
+
set ok 0
verbose -log "spawn stap -c $sup_exepath $sup_stppath"
@@ -161,28 +149,56 @@ wait
if {$ok == 5} { pass "$test C" } { fail "$test C ($ok)" }
-set ok 0
+# Test passing various C types to .mark probes
-# spawn objcopy -R .probes $supcplus_exepath $sup_exepath
-verbose -log "cp $supcplus_exepath $sup_exepath"
-spawn cp $supcplus_exepath $sup_exepath
-verbose -log "spawn stap -c $sup_exepath $sup_stppath"
-spawn stap -c $sup_exepath $sup_stppath
+set sup_flags "$sup_flags additional_flags=-O0"
+set res [target_compile $srcdir/$subdir/sdt_types.c sdt_types.x executable $sup_flags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "$test compiling types -g"
+ return
+} else {
+ pass "$test compiling types -g"
+}
+
+set ok 0
+set fail "types"
+verbose -log "spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x"
+spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x
expect {
-timeout 180
- -re {In test_probe_2 probe 0x2} { incr ok; exp_continue }
- -re {In test_probe_0 probe 0x3} { incr ok; exp_continue }
- -re {In test_probe_3 probe 0x3 0x[0-9a-f][0-9a-f]} { incr ok; exp_continue }
- -re {In test_probe_4 dtrace probe 0x4} { incr ok; exp_continue }
- timeout { fail "$test C++ (timeout)" }
+ -re {FAIL: [a-z_]+var} { regexp " .*$" $expect_out(0,string) s;
+ incr ok; set fail "$fail $s"; exp_continue }
+ timeout { fail "$test C (timeout)" }
eof { }
}
wait
-if {$ok == 5} { pass "$test C++" } { fail "$test C++ ($ok)" }
+if { $ok != 0 } {
+ fail "$test $fail"
+} else {
+ pass "$test types"
+}
+
+# Test .mark probe wildcard matching
+
+set ok 0
+spawn stap -l "process(\"./sdt_types.x\").mark(\"*\")"
+expect {
+ -timeout 180
+ -re {mark\(\"[a-z_]+\"\)} { incr ok; exp_continue }
+ timeout { fail "$test C (timeout)" }
+ eof { }
+}
-# catch {exec rm -f $sup_srcpath $sup_exepath $supcplus_exepath $sup_hpath $sup_stppath}
+if { $ok == 45 } {
+ pass "$test wildcard"
+} else {
+ fail "$test wildcard ($ok)"
+}
+
+if { $verbose == 0 } {
+catch {exec rm -f $sup_srcpath $sup_exepath $supcplus_exepath $sup_dpath $sup_hpath $sup_stppath sdt_types.x}
+}
-# It's not so important to clean up, and it's unhelpful if
-# one needs to diagnose a test failure.
diff --git a/testsuite/systemtap.base/stmt_rel.exp b/testsuite/systemtap.base/stmt_rel.exp
index be51fef9..619c91a5 100644
--- a/testsuite/systemtap.base/stmt_rel.exp
+++ b/testsuite/systemtap.base/stmt_rel.exp
@@ -1,8 +1,42 @@
-# test integer limits. Set and print variables and print constants.
-
set test "stmt_rel"
-set ::result_string {PASS bio_init
-PASS line number
-PASS wildcard}
-stap_run2 $srcdir/$subdir/$test.stp
+set line1 ""
+spawn stap -l "kernel.statement(\"bio_init@fs/bio.c+2\")"
+expect {
+ -timeout 180
+ -re {[0-9][0-9][0-9]} { regexp "\[0-9\]\[0-9\]\[0-9\]" $expect_out(0,string) line1; }
+ timeout { fail "$test C (timeout)" }
+ eof { }
+}
+
+set line2 ""
+spawn stap -l "kernel.statement(\"bio_init@fs/bio.c+3\")"
+expect {
+ -timeout 180
+ -re {[0-9][0-9][0-9]} { regexp "\[0-9\]\[0-9\]\[0-9\]" $expect_out(0,string) line2; }
+ timeout { fail "$test C (timeout)" }
+ eof { }
+}
+
+if { $line1 < $line2 } {
+ pass "$test line numbers"
+} else {
+ fail "$test line numbers"
+}
+
+set ok 0
+spawn stap -l "kernel.statement(\"bio_init@fs/bio.c:*\")"
+expect {
+ -timeout 180
+ -re {[0-9][0-9][0-9]} { incr ok; exp_continue }
+ timeout { fail "$test C (timeout)" }
+ eof { }
+}
+
+# bio_init drifts a bit in different kernels.
+# maybe 3, 4 or 15 lines in it.
+if { $ok >= 3 } {
+ pass "$test wildcard"
+} else {
+ fail "$test wildcard ($ok)"
+}
diff --git a/testsuite/systemtap.base/stmt_rel.stp b/testsuite/systemtap.base/stmt_rel.stp
deleted file mode 100644
index cfe77317..00000000
--- a/testsuite/systemtap.base/stmt_rel.stp
+++ /dev/null
@@ -1,71 +0,0 @@
-global stack2pp, stack2func, stack3pp, stack3func
-global wildcardpp, wild_count
-
-probe kernel.statement("bio_init@fs/bio.c+2") {
- # stack2 = tokenize(backtrace(), " ")
- stack2func = probefunc()
- stack2pp = pp()
-}
-probe kernel.statement("bio_init@fs/bio.c+3") {
- # stack3 = tokenize(backtrace(), " " )
- stack3func = probefunc()
- stack3pp = pp()
-}
-
-probe kernel.statement("bio_put@fs/bio.c:*") {
- line = tokenize(pp(),":")
- line = tokenize("",":")
- line = substr(line,0,strlen(line)-2)
- wildcardpp[strtol(line,10)]++
-
- if (wild_count++ <= 10) {
- next
- }
-
- stack2pp = tokenize(stack2pp,":")
- stack2pp = tokenize("",":")
- stack3pp = tokenize(stack3pp,":")
- stack3pp = tokenize("",":")
-
- stack2line = strtol (substr(stack2pp,0,strlen(stack2pp)-2), 10)
- stack3line = strtol (substr(stack3pp,0,strlen(stack3pp)-2), 10)
-
- # Did functions for both bio_init probes match?
- if (stack2func == stack3func) {
- printf ("PASS %s\n", stack2func)
- }
- else {
- printf ("FAIL %s %s\n", stack2func, stack3func)
- }
-
- # Was line # for bio_init probe +2 < line # for bio_init probe +3?
- if ((stack2line + 1) == stack3line) {
- printf ("PASS line number\n")
- }
- else {
- printf ("FAIL line number %d %d\n", stack2line, stack3line)
- }
-
- # This test does not take optimized code into account
- # Was address for bio_init probe +2 < address for bio_init probe +3?
- # if (stack2 < stack3) {
- # printf ("PASS address\n")
- # }
- # else {
- # printf ("FAIL address %s %s\n", stack2, stack3)
- # }
-
- # Did wildcard probe hit at least 4 different statements?
- foreach ([i] in wildcardpp) {
- statement_count += 1
- }
- if (statement_count >= 4) {
- printf ("PASS wildcard\n")
- }
- else
- {
- printf ("FAIL wildcard %d\n", statement_count)
- }
-
- exit()
-}
diff --git a/testsuite/systemtap.base/stmtvars.exp b/testsuite/systemtap.base/stmtvars.exp
index 822e0d7e..c0099f2d 100644
--- a/testsuite/systemtap.base/stmtvars.exp
+++ b/testsuite/systemtap.base/stmtvars.exp
@@ -3,9 +3,9 @@ set test "stmtvars"
set pc 0
set vars ""
-spawn stap -e "probe kernel.function(\"sys_open\") {\$foo}" -p4 -vv -u
+spawn stap -e "probe kernel.function(\"do_sys_open\") {\$foo}" -p4 -vv -u
expect {
- -re {probe sys_open[^\r\n]*pc=(0x[^\r\n]*)\r\n} { set pc $expect_out(1,string); exp_continue }
+ -re {probe do_sys_open[^\r\n]*pc=(0x[^\r\n]*)\r\n} { set pc $expect_out(1,string); exp_continue }
-re {alternatives: ([^\r\n]*)\): identifier [^\r\n]*\r\n} { set vars $expect_out(1,string); exp_continue }
timeout { fail "$test (timeout)" }
eof
@@ -18,7 +18,7 @@ set pc2 0
set vars2 ""
spawn stap -e "probe kernel.statement($pc) {\$foo}" -p4 -vv -u
expect {
- -re {probe sys_open[^\r\n]*pc=(0x[^\r\n]*)\r\n} { set pc2 $expect_out(1,string); exp_continue }
+ -re {probe do_sys_open[^\r\n]*pc=(0x[^\r\n]*)\r\n} { set pc2 $expect_out(1,string); exp_continue }
-re {alternatives: ([^\r\n]*)\): identifier [^\r\n]*\r\n} { set vars2 $expect_out(1,string); exp_continue }
timeout { fail "$test (timeout)" }
eof
diff --git a/testsuite/systemtap.base/strftime.exp b/testsuite/systemtap.base/strftime.exp
new file mode 100644
index 00000000..ad9e471d
--- /dev/null
+++ b/testsuite/systemtap.base/strftime.exp
@@ -0,0 +1,49 @@
+set test "strftime"
+if {![installtest_p]} { untested $test; return }
+# cleanup
+system "rm -f %*"
+
+# check %S and %T
+set format %%%S_%T
+exec stap -o $format -we {probe begin {println("hello");exit()}}
+
+spawn ls -1
+set ok 0
+expect {
+ -re {%([0-9][0-9])_[0-9][0-9]:[0-9][0-9]:\1} {incr ok}
+ eof { }
+}
+wait
+
+if {$ok == 1} {
+ pass "$test (%S and %T)"
+} else {
+ fail "$test (%S and %T)"
+}
+
+# check except for %S and %T
+set format %%,%C,%Y,%y,%m,%d,%e,%F,%H,%I,%j,%k,%l,%M,%R,%u,%w
+
+set date1 [exec date +$format]
+# run stapio with strftime
+exec stap -o $format -we {probe begin {println("hello");exit()}}
+# check whether stap outputs stapio pid
+set date2 [exec date +$format]
+
+spawn ls -1
+set ok 0
+expect {
+ $date1 {incr ok}
+ $date2 {incr ok}
+ eof { }
+}
+wait
+
+if {$ok == 1} {
+ pass "$test (except %S and %T)"
+} else {
+ fail "$test (except %S and %T)"
+}
+
+# cleanup
+system "rm -f %*"
diff --git a/testsuite/systemtap.base/system_func.stp b/testsuite/systemtap.base/system_func.stp
index d14fb25b..6a6bb04a 100644
--- a/testsuite/systemtap.base/system_func.stp
+++ b/testsuite/systemtap.base/system_func.stp
@@ -4,10 +4,10 @@
global saw_echo, did_cat
-probe kernel.function("sys_open") {
+probe kernel.function("do_sys_open") {
if (!saw_echo) {
# very inefficient. Testing only. DO NOT DO THIS
- msg="echo sys_open"
+ msg="echo do_sys_open"
system(msg)
saw_echo = 1
}
diff --git a/testsuite/systemtap.base/tracepoints.exp b/testsuite/systemtap.base/tracepoints.exp
index bea461c4..cd033908 100644
--- a/testsuite/systemtap.base/tracepoints.exp
+++ b/testsuite/systemtap.base/tracepoints.exp
@@ -1,3 +1,26 @@
+
+set tracepoints {}
+spawn stap -l {kernel.trace("*")}
+expect {
+ -re {^kernel.trace[^\r\n]*\r\n} {
+ append tracepoints $expect_out(0,string)
+ exp_continue
+ }
+ timeout {}
+ eof {}
+}
+catch {close}; catch { wait }
+
+foreach tp $tracepoints {
+ set test "tracepoint $tp -p4"
+ if {[catch {exec stap -w -p4 -e "probe $tp {}"} res]} {
+ fail "$test $res"
+ } else {
+ pass "$test"
+ }
+}
+
set test "tracepoints"
+if {![installtest_p]} { untested $test; return }
set ::result_string {tracepoints OK}
stap_run2 $srcdir/$subdir/$test.stp
diff --git a/testsuite/systemtap.base/uprobes.exp b/testsuite/systemtap.base/uprobes.exp
index 89250e7b..6344cbf0 100644
--- a/testsuite/systemtap.base/uprobes.exp
+++ b/testsuite/systemtap.base/uprobes.exp
@@ -18,14 +18,7 @@ if [file exists $path] then { pass "$test prep" } else { fail "$test prep" }
catch {exec gcc -g -o jennie jennie.c} err
if {$err == "" && [file exists jennie]} then { pass "$test compile" } else { fail "$test compile" }
-# Try to find utrace_attach symbol in /proc/kallsyms
-# copy from utrace_p5.exp
-set utrace_support_found 0
-set path "/proc/kallsyms"
-if {! [catch {exec grep -q utrace_attach $path} dummy]} {
- set utrace_support_found 1
-}
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$test -p4"; untested "$test -p5"
catch {exec rm -f jennie.c jennie}
return
diff --git a/testsuite/systemtap.base/uprobes_exe.c b/testsuite/systemtap.base/uprobes_exe.c
new file mode 100644
index 00000000..b4811335
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_exe.c
@@ -0,0 +1,29 @@
+/* uprobes_lib test case
+ * Copyright (C) 2009, 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 <unistd.h>
+
+// function from our library
+int lib_main (void);
+
+void
+main_func (int foo)
+{
+ if (foo > 1)
+ main_func (foo - 1);
+ else
+ lib_main();
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ main_func (3);
+ return 0;
+}
diff --git a/testsuite/systemtap.base/uprobes_lib.c b/testsuite/systemtap.base/uprobes_lib.c
new file mode 100644
index 00000000..25297b6b
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_lib.c
@@ -0,0 +1,21 @@
+/* uprobes_lib test case - library helper
+ * Copyright (C) 2009, 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.
+ */
+
+void
+lib_func (int bar)
+{
+ if (bar > 1)
+ lib_func (bar - 1);
+}
+
+void
+lib_main ()
+{
+ lib_func (3);
+}
diff --git a/testsuite/systemtap.base/uprobes_lib.exp b/testsuite/systemtap.base/uprobes_lib.exp
new file mode 100644
index 00000000..313c01b6
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_lib.exp
@@ -0,0 +1,46 @@
+set test "uprobes_lib"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/uprobes_exe.c"
+set testsrclib "$testpath/uprobes_lib.c"
+set testexe "./uprobes_exe"
+set testlibname "uprobes_lib"
+set testlibdir "."
+set testso "$testlibdir/lib${testlibname}.so"
+set testflags "additional_flags=-g additional_flags=-O"
+set testlibflags "$testflags additional_flags=-fPIC additional_flags=-shared"
+set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
+
+# Compile our test program and library.
+set res [target_compile $testsrclib $testso executable $testlibflags]
+if { $res != "" } {
+ verbose "target_compile for $testso failed: $res" 2
+ fail "$test compile $testsrclib"
+ return
+} else {
+ pass "$test compile $testsrclib"
+}
+
+set res [target_compile $testsrc $testexe executable $maintestflags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "$test compile $testsrc"
+ return
+} else {
+ pass "$test compile $testsrc"
+}
+
+set ::result_string {main
+main_func
+main_func
+main_func
+lib_main
+lib_func
+lib_func
+lib_func}
+
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test"; return }
+if {! [utrace_p]} { untested $test; return }
+stap_run2 $srcdir/$subdir/$test.stp -c $testexe
+
+#exec rm -f $testexe $testso
diff --git a/testsuite/systemtap.base/uprobes_lib.stp b/testsuite/systemtap.base/uprobes_lib.stp
new file mode 100644
index 00000000..459351a4
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_lib.stp
@@ -0,0 +1,15 @@
+probe process("uprobes_exe").function("main") {
+ printf("main\n");
+}
+
+probe process("uprobes_exe").function("main_func") {
+ printf("main_func\n");
+}
+
+probe process("libuprobes_lib.so").function("lib_main") {
+ printf("lib_main\n");
+}
+
+probe process("libuprobes_lib.so").function("lib_func") {
+ printf("lib_func\n");
+}
diff --git a/testsuite/systemtap.base/uprobes_uname.exp b/testsuite/systemtap.base/uprobes_uname.exp
new file mode 100644
index 00000000..65e1ff70
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_uname.exp
@@ -0,0 +1,46 @@
+set test "uprobes_uname"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/uprobes_exe.c"
+set testsrclib "$testpath/uprobes_lib.c"
+set testexe "./uprobes_exe"
+set testlibname "uprobes_lib"
+set testlibdir "."
+set testso "$testlibdir/lib${testlibname}.so"
+set testflags "additional_flags=-g additional_flags=-O"
+set testlibflags "$testflags additional_flags=-fPIC additional_flags=-shared"
+set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
+
+# Compile our test program and library.
+set res [target_compile $testsrclib $testso executable $testlibflags]
+if { $res != "" } {
+ verbose "target_compile for $testso failed: $res" 2
+ fail "$test compile $testsrclib"
+ return
+} else {
+ pass "$test compile $testsrclib"
+}
+
+set res [target_compile $testsrc $testexe executable $maintestflags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "$test compile $testsrc"
+ return
+} else {
+ pass "$test compile $testsrc"
+}
+
+set ::result_string {exe: main=main
+exe: main_func=main_func
+exe: main_func=main_func
+exe: main_func=main_func
+lib: lib_main=lib_main
+lib: lib_func=lib_func
+lib: lib_func=lib_func
+lib: lib_func=lib_func}
+
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test"; return }
+if {! [utrace_p]} { untested $test; return }
+stap_run2 $srcdir/$subdir/$test.stp -c $testexe
+
+#exec rm -f $testexe $testso
diff --git a/testsuite/systemtap.base/uprobes_uname.stp b/testsuite/systemtap.base/uprobes_uname.stp
new file mode 100644
index 00000000..a44d78d3
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_uname.stp
@@ -0,0 +1,7 @@
+probe process("uprobes_exe").function("*") {
+ printf("exe: %s=%s\n",probefunc(), usymname(uaddr()));
+}
+
+probe process("libuprobes_lib.so").function("*") {
+ printf("lib: %s=%s\n",probefunc(), usymname(uaddr()));
+}
diff --git a/testsuite/systemtap.base/uprobes_ustack.exp b/testsuite/systemtap.base/uprobes_ustack.exp
new file mode 100644
index 00000000..bfc435e9
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_ustack.exp
@@ -0,0 +1,97 @@
+set test "uprobes_ustack"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/uprobes_exe.c"
+set testsrclib "$testpath/uprobes_lib.c"
+set testexe "./uprobes_exe"
+set testlibname "uprobes_lib"
+set testlibdir "."
+set testso "$testlibdir/lib${testlibname}.so"
+set testflags "additional_flags=-g additional_flags=-O"
+set testlibflags "$testflags additional_flags=-fPIC additional_flags=-shared"
+set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
+
+# Compile our test program and library.
+set res [target_compile $testsrclib $testso executable $testlibflags]
+if { $res != "" } {
+ verbose "target_compile for $testso failed: $res" 2
+ fail "$test compile $testsrclib"
+ return
+} else {
+ pass "$test compile $testsrclib"
+}
+
+set res [target_compile $testsrc $testexe executable $maintestflags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "$test compile $testsrc"
+ return
+} else {
+ pass "$test compile $testsrc"
+}
+
+set ::result_string {exe: main=main
+exe: main_func=main_func
+exe: main_func=main_func
+exe: main_func=main_func
+lib: lib_main=lib_main
+lib: lib_func=lib_func
+lib: lib_func=lib_func
+lib: lib_func=lib_func}
+
+# Only run on make installcheck
+if {! [installtest_p]} { untested "$test"; return }
+if {! [utrace_p]} { untested $test; return }
+
+# Output is:
+#print_ubacktrace exe 0
+# 0x080484ba : main_func+0xa/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+#print_ustack exe 1
+# 0x080484ba : main_func+0xa/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+#print_ubacktrace lib 2
+# 0x00db2422 : lib_func+0x16/0x2b [.../libuprobes_lib.so]
+# 0x00db2455 : lib_main+0x1e/0x29 [.../libuprobes_lib.so]
+# 0x080484d0 : main_func+0x20/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+#print_ustack lib 3
+# 0x00db2422 : lib_func+0x16/0x2b [.../libuprobes_lib.so]
+# 0x00db2431 : lib_func+0x25/0x2b [.../libuprobes_lib.so]
+# 0x00db2455 : lib_main+0x1e/0x29 [.../libuprobes_lib.so]
+# 0x080484d0 : main_func+0x20/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484c9 : main_func+0x19/0x29 [.../uprobes_exe]
+# 0x080484f6 : main+0x1d/0x37 [.../uprobes_exe]
+
+set print 0
+set main 0
+set main_func 0
+set lib_main 0
+set lib_func 0
+# Needs extra space since on 64bit the last ubacktrace string is
+# 7 entries * (16 hex + 2 for 0x + 1 space) = 133 chars.
+# Default MAXSTRINGLEN is 128 chars.
+spawn stap -DMAXSTRINGLEN=133 $srcdir/$subdir/$test.stp -c $testexe
+
+wait
+expect {
+ -timeout 60
+ -re {^print_[^\r\n]+\r\n} {incr print; exp_continue}
+ -re {^ 0x[a-f0-9]+ : main\+0x[^\r\n]+\r\n} {incr main; exp_continue}
+ -re {^ 0x[a-f0-9]+ : main_func\+0x[^\r\n]+\r\n} {incr main_func; exp_continue}
+ -re {^ 0x[a-f0-9]+ : lib_main\+0x[^\r\n]+\r\n} {incr lib_main; exp_continue}
+ -re {^ 0x[a-f0-9]+ : lib_func\+0x[^\r\n]+\r\n} {incr lib_func; exp_continue}
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+
+if {$print == 4} {pass "$test print"} {fail "$test print ($print)"}
+if {$main == 4} {pass "$test main"} {fail "$test main ($main)"}
+if {$main_func == 9} {pass "$test main_func"} {fail "$test main_func ($main_func)"}
+if {$lib_main == 2} {pass "$test lib_main"} {fail "$test lib_main ($lib_main)"}
+if {$lib_func == 3} {pass "$test lib_func"} {fail "$test lib_func ($lib_func)"}
+
+#exec rm -f $testexe $testso
diff --git a/testsuite/systemtap.base/uprobes_ustack.stp b/testsuite/systemtap.base/uprobes_ustack.stp
new file mode 100644
index 00000000..6de03b42
--- /dev/null
+++ b/testsuite/systemtap.base/uprobes_ustack.stp
@@ -0,0 +1,35 @@
+// Prints backtrace from lib through exe twice using diffent ustack functions.
+
+global hits = 0;
+
+probe process("uprobes_exe").function("main_func")
+{
+ if (hits == 0)
+ {
+ log("print_ubacktrace exe 0");
+ print_ubacktrace();
+ hits++;
+ }
+ else if (hits == 1)
+ {
+ log("print_ustack exe 1");
+ print_ustack(ubacktrace());
+ hits++;
+ }
+}
+
+probe process("libuprobes_lib.so").function("lib_func")
+{
+ if (hits == 2)
+ {
+ log("print_ubacktrace lib 2");
+ print_ubacktrace();
+ hits++;
+ }
+ else if (hits == 3)
+ {
+ log("print_ustack lib 3");
+ print_ustack(ubacktrace());
+ hits++;
+ }
+}
diff --git a/testsuite/systemtap.base/utrace_p4.exp b/testsuite/systemtap.base/utrace_p4.exp
index 1467d9c8..8d323a8a 100644
--- a/testsuite/systemtap.base/utrace_p4.exp
+++ b/testsuite/systemtap.base/utrace_p4.exp
@@ -7,8 +7,6 @@
# utrace doesn't exist in the kernel, marks the tests as 'untested'.
# Initialize variables
-set utrace_support_found 0
-
set begin_script {"probe process(\"/bin/ls\").begin { print(\"ls begin\") }"}
set end_script {"probe process(\"/bin/ls\").end { print(\"ls end\") }"}
set syscall_script {"probe process(\"/bin/ls\").syscall { printf(\"|%d\", \$syscall) }"}
@@ -24,18 +22,12 @@ set pid_syscall_return_script {"probe process(123).syscall.return { printf(\"|%d
set pid_thread_begin_script {"probe process(123).thread.begin { print(\"123 thread.begin\") }"}
set pid_thread_end_script {"probe process(123).thread.end { print(\"123 thread.end\") }"}
-# 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} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a begin script using a path
@@ -43,7 +35,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_01_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a begin script using a pid
@@ -51,7 +43,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_02"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a end script using a path
@@ -59,7 +51,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_02_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a end script using a pid
@@ -67,7 +59,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_03"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall script using a path
@@ -75,7 +67,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_03_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall script using a pid
@@ -83,7 +75,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_04"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall return script using a path
@@ -91,7 +83,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_04_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling a syscall return script using a pid
@@ -99,7 +91,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_05"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.begin script using a path
@@ -107,7 +99,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_05_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.begin script using a pid
@@ -115,7 +107,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_06"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.end script using a path
@@ -123,7 +115,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_06_pid"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an thread.end script using a pid
@@ -131,7 +123,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P4_07"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} else {
# Try compiling an system-wide begin script
diff --git a/testsuite/systemtap.base/utrace_p5.exp b/testsuite/systemtap.base/utrace_p5.exp
index 33281350..3d432dc3 100644
--- a/testsuite/systemtap.base/utrace_p5.exp
+++ b/testsuite/systemtap.base/utrace_p5.exp
@@ -1,7 +1,6 @@
# Utrace run (pass 5) tests.
# Initialize variables
-set utrace_support_found 0
set exepath "[pwd]/cat_[pid]"
set multi_srcpath "$srcdir/systemtap.base/utrace_p5_multi.c"
set multi_exepath "[pwd]/utrace_p5_multi_[pid]"
@@ -90,12 +89,6 @@ set bz6841_script {
}
set bz6841_script_output ".+ issues syscall \\d+ times\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
@@ -138,7 +131,7 @@ proc run_utrace_p5_multi {} {
}
set TEST_NAME "UTRACE_P5_01"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -148,7 +141,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_02"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -158,7 +151,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_03"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -168,7 +161,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_04"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -178,7 +171,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_05"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -189,7 +182,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_06"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
@@ -200,7 +193,7 @@ if {$utrace_support_found == 0} {
}
set TEST_NAME "UTRACE_P5_07"
-if {$utrace_support_found == 0} {
+if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
diff --git a/testsuite/systemtap.base/utrace_syscall_args.c b/testsuite/systemtap.base/utrace_syscall_args.c
new file mode 100644
index 00000000..2d3da838
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_syscall_args.c
@@ -0,0 +1,67 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h> /* For SYS_xxx definitions */
+
+int main()
+{
+ int fd, ret;
+ struct stat fs;
+ void *r;
+ int rc;
+
+ /* create a file with something in it */
+ fd = open("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ lseek(fd, 1024, SEEK_SET);
+ write(fd, "abcdef", 6);
+ close(fd);
+
+ fd = open("foobar", O_RDONLY);
+
+ /* stat for file size */
+ ret = fstat(fd, &fs);
+
+ /* mmap file file, then unmap it. */
+ r = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (r != MAP_FAILED)
+ munmap(r, fs.st_size);
+ close(fd);
+
+ /* OK, try some system calls to see if we get the arguments
+ * correctly. */
+#if (__LONG_MAX__ > __INT_MAX__)
+ rc = syscall (__NR_dup, (unsigned long)-12345,
+ (unsigned long)0xffffffffffffffff,
+ (unsigned long)0xa5a5a5a5a5a5a5a5,
+ (unsigned long)0xf0f0f0f0f0f0f0f0,
+ (unsigned long)0x5a5a5a5a5a5a5a5a,
+ (unsigned long)0xe38e38e38e38e38e);
+#else
+ rc = syscall (__NR_dup, (unsigned long)-12345,
+ (unsigned long)0xffffffff,
+ (unsigned long)0xa5a5a5a5,
+ (unsigned long)0xf0f0f0f0,
+ (unsigned long)0x5a5a5a5a,
+ (unsigned long)0xe38e38e3);
+#endif
+#if (__LONG_MAX__ > __INT_MAX__)
+ rc = syscall ((unsigned long)-1,
+ (unsigned long)0x1c71c71c71c71c71,
+ (unsigned long)0x0f0f0f0f0f0f0f0f,
+ (unsigned long)0xdb6db6db6db6db6d,
+ (unsigned long)0x2492492492492492,
+ (unsigned long)0xad6b5ad6b5ad6b5a,
+ (unsigned long)0xdef7ddef7ddef7dd);
+#else
+ rc = syscall ((unsigned long)-1,
+ (unsigned long)0x1c71c71c,
+ (unsigned long)0x0f0f0f0f,
+ (unsigned long)0xdb6db6db,
+ (unsigned long)0x24924924,
+ (unsigned long)0xad6b5ad6,
+ (unsigned long)0xdef7ddef);
+#endif
+ return 0;
+}
diff --git a/testsuite/systemtap.base/utrace_syscall_args.exp b/testsuite/systemtap.base/utrace_syscall_args.exp
new file mode 100644
index 00000000..98bc457e
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_syscall_args.exp
@@ -0,0 +1,82 @@
+# Utrace system call argument tests.
+
+set flags ""
+set srcpath "$srcdir/$subdir/utrace_syscall_args.c"
+set exepath "[pwd]/utrace_syscall_args"
+set stppath "$srcdir/$subdir/utrace_syscall_args.stp"
+
+set output_string "mmap\\(\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nmunmap\\(\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nclose\\(\[0-9\]+\\)\\(0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\ndup\\(\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nbad_syscall\\(-?\[0-9\]+\\)\\(0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+, 0x\[0-9a-f]+\\) = 0x\[0-9a-f]+\r\nsystemtap test success\r\n"
+
+# For first pass, force 64-bit compilation for 64-bit systems. Add
+# any other 64-bit architecture you want tested below.
+#
+# To find tcl's platform name for your machine, run the following:
+# echo "puts $::tcl_platform(machine)" | tclsh
+
+switch -regexp $::tcl_platform(machine) {
+ ^ia64$ {
+ set do_64_bit_pass 1
+ set flags ""
+ }
+ ^(x86_64|ppc64|s390x)$ {
+ set do_64_bit_pass 1
+ set flags "additional_flags=-m64"
+ }
+ default {
+ set do_64_bit_pass 0
+ }
+}
+
+if {$do_64_bit_pass} {
+ set testname "64_BIT_UTRACE_SYSCALL_ARGS"
+ if {![installtest_p]} { untested $testname; continue }
+ if {![utrace_p]} { untested $testname; continue }
+ send_log "Testing ${testname}\n"
+
+ # Compile our test program.
+ set res [target_compile $srcpath $exepath executable $flags]
+ if { $res != "" } {
+ verbose "target_compile for $exepath failed: $res" 2
+ fail "$testname: unable to compile $srcpath"
+ return
+ }
+
+ # Run the test.
+ stap_run $testname no_load $output_string -g $stppath -c $exepath
+
+ catch {exec rm -f $exepath foobar}
+}
+
+# The second pass is for systems that support 32-bit executables
+# (either exclusively or in addition to 64-bit executables).
+set do_32_bit_pass 1
+switch -regexp $::tcl_platform(machine) {
+ ^(x86_64|ppc64)$ {
+ set flags "additional_flags=-m32"
+ }
+ ^s390x$ {
+ set flags "additional_flags=-m31"
+ }
+ ^ia64$ {
+ set do_32_bit_pass 0
+ }
+}
+
+if {$do_32_bit_pass} {
+ set testname "32_BIT_UTRACE_SYSCALL_ARGS"
+ if {![installtest_p]} { untested $testname; continue }
+ if {![utrace_p]} { untested $testname; continue }
+ send_log "Testing ${testname}\n"
+
+ # Compile our test program
+ set res [target_compile $srcpath $exepath executable $flags]
+ if { $res != "" } {
+ verbose "target_compile for $exepath failed: $res" 2
+ fail "$testname: unable to compile $srcpath"
+ return
+ }
+
+ stap_run $testname no_load $output_string -g $stppath -c $exepath
+
+ catch {exec rm -f $exepath foobar}
+}
diff --git a/testsuite/systemtap.base/utrace_syscall_args.stp b/testsuite/systemtap.base/utrace_syscall_args.stp
new file mode 100644
index 00000000..6c9e14fc
--- /dev/null
+++ b/testsuite/systemtap.base/utrace_syscall_args.stp
@@ -0,0 +1,406 @@
+%{
+#include "syscall.h"
+%}
+
+function mmap_syscall_no:long () %{
+ THIS->__retvalue = MMAP_SYSCALL_NO(current); /* pure */
+%}
+function mmap2_syscall_no:long () %{
+ THIS->__retvalue = MMAP2_SYSCALL_NO(current); /* pure */
+%}
+function munmap_syscall_no:long () %{
+ THIS->__retvalue = MUNMAP_SYSCALL_NO(current); /* pure */
+%}
+
+global syscalls_seen = 0
+global failures = 0
+
+global mmap_found = 0
+global mmap_args[10]
+
+global munmap_found = 0
+global munmap_args[10]
+
+global close_found = 0
+global close_args[10]
+
+global dup_found = 0
+global dup_args[10]
+
+global bad_syscall_found = 0
+global bad_syscall_args[10]
+
+probe begin
+{
+ printf("systemtap starting probe\n")
+}
+
+probe syscall.open {
+ if (filename == "foobar") {
+ syscalls_seen += 1
+ }
+}
+
+probe process("utrace_syscall_args").syscall {
+ if (syscalls_seen >= 2) {
+ syscalls_seen += 1
+
+ # We skip the fstat() syscall, which is the 1st syscall after
+ # the open() by not looking at 'syscalls_seen == 3'.
+
+ if (syscalls_seen == 4 && ($syscall == mmap_syscall_no()
+ || $syscall == mmap2_syscall_no())) {
+ mmap_found = 1
+ mmap_args[0] = $syscall
+ mmap_args[1] = $arg1
+ mmap_args[2] = $arg2
+ mmap_args[3] = $arg3
+ mmap_args[4] = $arg4
+ mmap_args[5] = $arg5
+ mmap_args[6] = $arg6
+
+%(arch == "s390x" %?
+ # s390 requires this for mmap. Verified by running:
+ # # strace strace utrace_syscall_args
+ addr = mmap_args[1]
+ mmap_args[1] = user_long(addr)
+ addr += 8
+ mmap_args[2] = user_long(addr)
+ addr += 8
+ mmap_args[3] = user_long(addr)
+ addr += 8
+ mmap_args[4] = user_long(addr)
+ addr += 8
+ mmap_args[5] = user_long(addr)
+ addr += 8
+ mmap_args[6] = user_long(addr)
+%)
+ }
+ else if (syscalls_seen == 5 && $syscall == munmap_syscall_no()) {
+ munmap_found = 1
+ munmap_args[0] = $syscall
+ munmap_args[1] = $arg1
+ munmap_args[2] = $arg2
+ }
+ else if (syscalls_seen == 6) {
+ close_found = 1
+ close_args[0] = $syscall
+ close_args[1] = $arg1
+ }
+ else if (syscalls_seen == 7) {
+ dup_found = 1
+ dup_args[0] = $syscall
+ dup_args[1] = $arg1
+ dup_args[2] = $arg2
+ dup_args[3] = $arg3
+ dup_args[4] = $arg4
+ dup_args[5] = $arg5
+ dup_args[6] = $arg6
+ }
+ else if (syscalls_seen == 8) {
+ bad_syscall_found = 1
+ bad_syscall_args[0] = $syscall
+ bad_syscall_args[1] = $arg1
+ bad_syscall_args[2] = $arg2
+ bad_syscall_args[3] = $arg3
+ bad_syscall_args[4] = $arg4
+ bad_syscall_args[5] = $arg5
+ bad_syscall_args[6] = $arg6
+ }
+ }
+}
+probe process("utrace_syscall_args").syscall.return {
+ if (syscalls_seen >= 4) {
+ if (syscalls_seen == 4) {
+ mmap_args[7] = $return
+ mmap_args[8] = $syscall
+ }
+ else if (syscalls_seen == 5) {
+ munmap_args[3] = $return
+ munmap_args[4] = $syscall
+ }
+ else if (syscalls_seen == 6) {
+ close_args[2] = $return
+ close_args[3] = $syscall
+ }
+ else if (syscalls_seen == 7) {
+ dup_args[7] = $return
+ dup_args[8] = $syscall
+ }
+ else if (syscalls_seen == 8) {
+ bad_syscall_args[7] = $return
+ bad_syscall_args[8] = $syscall
+ syscalls_seen = 0
+ }
+ }
+}
+
+probe end
+{
+ printf("systemtap ending probe\n")
+
+ # print mmap info
+ if (mmap_found == 0) {
+ printf("error: no mmap system call found\n")
+ failures += 1
+ }
+ else {
+ printf("mmap(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = 0x%x\n",
+ mmap_args[0], mmap_args[1], mmap_args[2], mmap_args[3],
+ mmap_args[4], mmap_args[5], mmap_args[6], mmap_args[7])
+
+ # Validate arguments. We can only check certain arguments.
+ # It is possible that mmap's 'prot' and 'flags' arguments
+ # could vary per platform, so we'll ignore them.
+ if (mmap_args[1] != 0) {
+ failures += 1
+ printf("mmap bad arg 1: 0x%x vs 0x0\n", mmap_args[1])
+ }
+ if (mmap_args[2] != 0x406) {
+ failures += 1
+ printf("mmap bad arg 2: 0x%x vs 0x406\n", mmap_args[2])
+ }
+ if (mmap_args[6] != 0) {
+ failures += 1
+ printf("mmap bad arg 6: 0x%x vs 0x0\n", mmap_args[6])
+ }
+
+ # Validate syscall number
+ if (mmap_args[0] != mmap_args[8]) {
+ failures += 1
+ printf("mmap $syscall mismatch: %d vs. %d\n",
+ mmap_args[0], mmap_args[8])
+ }
+ }
+
+ # print munmap info
+ if (munmap_found == 0) {
+ printf("error: no munmap system call found\n")
+ failures += 1
+ }
+ else if (munmap_found == 0 || mmap_found == 0) {
+ printf("error: no munmap/mmap system call found\n")
+ failures += 1
+ }
+ else {
+ printf("munmap(%d)(0x%x, 0x%x) = 0x%x\n",
+ munmap_args[0], munmap_args[1], munmap_args[2], munmap_args[3])
+
+ # Validate arguments. munmap()'s first argument should be the
+ # same as the mmap() return value.
+ if (munmap_args[1] != mmap_args[7]) {
+ failures += 1
+ printf("munmap bad arg 1: 0x%x vs 0x%x\n", munmap_args[1],
+ mmap_args[7])
+ }
+ if (munmap_args[2] != mmap_args[2]) {
+ failures += 1
+ printf("munmap bad arg 2: 0x%x vs 0x%x\n", munmap_args[2],
+ mmap_args[2])
+ }
+ # Validate return value
+ if (munmap_args[7] != 0) {
+ failures += 1
+ printf("munmap bad return value: 0x%x vs 0x0\n", munmap_args[7])
+ }
+
+ # Validate syscall number
+ if (munmap_args[0] != munmap_args[4]) {
+ failures += 1
+ printf("munmap $syscall mismatch: %d vs. %d\n",
+ munmap_args[0], munmap_args[4])
+ }
+ }
+
+ # print close info
+ if (close_found == 0) {
+ printf("error: no close system call found\n")
+ failures += 1
+ }
+ else if (close_found == 1) {
+ printf("close(%d)(0x%x) = 0x%x\n",
+ close_args[0], close_args[1], close_args[2])
+
+ if (mmap_args[5] != close_args[1]) {
+ failures += 1
+ printf("close bad arg 1: 0x%x vs 0x%x\n",
+ close_args[0], mmap_args[5])
+ }
+
+ # Validate syscall number
+ if (close_args[0] != close_args[3]) {
+ failures += 1
+ printf("close $syscall mismatch: %d vs. %d\n",
+ close_args[0], close_args[3])
+ }
+ }
+
+ # print dup info
+ if (dup_found == 0) {
+ printf("error: no dup system call found\n")
+ failures += 1
+ }
+ else {
+ printf("dup(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = 0x%x\n",
+ dup_args[0], dup_args[1], dup_args[2], dup_args[3],
+ dup_args[4], dup_args[5], dup_args[6], dup_args[7])
+
+ # Validate arguments - handle 32-bit vs. 64-bit.
+ if ((dup_args[1] & 0xffffffff00000000) != 0) {
+ if (dup_args[1] != 0xffffffffffffcfc7) {
+ failures += 1
+ printf("dup bad arg 1: 0x%x vs 0xffffffffffffcfc7\n",
+ dup_args[1])
+ }
+ if (dup_args[2] != 0xffffffffffffffff) {
+ failures += 1
+ printf("dup bad arg 2: 0x%x vs 0xffffffffffffffff\n",
+ dup_args[2])
+ }
+ if (dup_args[3] != 0xa5a5a5a5a5a5a5a5) {
+ failures += 1
+ printf("dup bad arg 3: 0x%x vs 0xa5a5a5a5a5a5a5a5\n",
+ dup_args[3])
+ }
+ if (dup_args[4] != 0xf0f0f0f0f0f0f0f0) {
+ failures += 1
+ printf("dup bad arg 4: 0x%x vs 0xf0f0f0f0f0f0f0f0\n",
+ dup_args[4])
+ }
+ if (dup_args[5] != 0x5a5a5a5a5a5a5a5a) {
+ failures += 1
+ printf("dup bad arg 5: 0x%x vs 0x5a5a5a5a5a5a5a5a\n",
+ dup_args[5])
+ }
+ if (dup_args[6] != 0xe38e38e38e38e38e) {
+ failures += 1
+ printf("dup bad arg 6: 0x%x vs 0xe38e38e38e38d38e\n",
+ dup_args[6])
+ }
+ }
+ else {
+ if (dup_args[1] != 0xffffcfc7) {
+ failures += 1
+ printf("dup bad arg 1: 0x%x vs 0xffffcfc7\n", dup_args[1])
+ }
+ if (dup_args[2] != 0xffffffff) {
+ failures += 1
+ printf("dup bad arg 2: 0x%x vs 0xffffffff\n", dup_args[2])
+ }
+ if (dup_args[3] != 0xa5a5a5a5) {
+ failures += 1
+ printf("dup bad arg 3: 0x%x vs 0xa5a5a5a5\n", dup_args[3])
+ }
+ if (dup_args[4] != 0xf0f0f0f0) {
+ failures += 4
+ printf("dup bad arg 4: 0x%x vs 0xf0f0f0f0\n", dup_args[4])
+ }
+ if (dup_args[5] != 0x5a5a5a5a) {
+ failures += 1
+ printf("dup bad arg 5: 0x%x vs 0x5a5a5a5a\n", dup_args[5])
+ }
+ if (dup_args[6] != 0xe38e38e3) {
+ failures += 1
+ printf("dup bad arg 6: 0x%x vs 0xe38e38e3\n", dup_args[6])
+ }
+ }
+
+ # Validate syscall number
+ if (dup_args[0] != dup_args[8]) {
+ failures += 1
+ printf("dup $syscall mismatch: %d vs. %d\n",
+ dup_args[0], dup_args[8])
+ }
+ }
+
+ # print bad_syscall info
+ if (bad_syscall_found == 0) {
+ printf("error: no bad_syscall system call found\n")
+ failures += 1
+ }
+ else {
+ printf("bad_syscall(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = 0x%x\n",
+ bad_syscall_args[0], bad_syscall_args[1], bad_syscall_args[2], bad_syscall_args[3],
+ bad_syscall_args[4], bad_syscall_args[5], bad_syscall_args[6], bad_syscall_args[7])
+
+ # Validate arguments - handle 32-bit vs. 64-bit.
+ if (bad_syscall_args[1] > 0xffffffff) {
+ if (bad_syscall_args[1] != 0x1c71c71c71c71c71) {
+ failures += 1
+ printf("bad_syscall bad arg 1: 0x%x vs 0x1c71c71c71c71c71\n",
+ bad_syscall_args[1])
+ }
+ if (bad_syscall_args[2] != 0x0f0f0f0f0f0f0f0f) {
+ failures += 1
+ printf("bad_syscall bad arg 2: 0x%x vs 0x0f0f0f0f0f0f0f0f\n",
+ bad_syscall_args[2])
+ }
+ if (bad_syscall_args[3] != 0xdb6db6db6db6db6d) {
+ failures += 1
+ printf("bad_syscall bad arg 3: 0x%x vs 0xdb6db6db6db6db6d\n",
+ bad_syscall_args[3])
+ }
+ if (bad_syscall_args[4] != 0x2492492492492492) {
+ failures += 1
+ printf("bad_syscall bad arg 4: 0x%x vs 0x2492492492492492\n",
+ bad_syscall_args[4])
+ }
+ if (bad_syscall_args[5] != 0xad6b5ad6b5ad6b5a) {
+ failures += 1
+ printf("bad_syscall bad arg 5: 0x%x vs 0xad6b5ad6b5ad6b5a\n",
+ bad_syscall_args[5])
+ }
+ if (bad_syscall_args[6] != 0xdef7ddef7ddef7dd) {
+ failures += 1
+ printf("bad_syscall bad arg 6: 0x%x vs 0xdef7ddef7ddef7dd\n",
+ bad_syscall_args[6])
+ }
+ }
+ else {
+ if (bad_syscall_args[1] != 0x1c71c71c) {
+ failures += 1
+ printf("bad_syscall bad arg 1: 0x%x vs 0x1c71c71c\n",
+ bad_syscall_args[1])
+ }
+ if (bad_syscall_args[2] != 0x0f0f0f0f) {
+ failures += 1
+ printf("bad_syscall bad arg 2: 0x%x vs 0x0f0f0f0f\n",
+ bad_syscall_args[2])
+ }
+ if (bad_syscall_args[3] != 0xdb6db6db) {
+ failures += 1
+ printf("bad_syscall bad arg 3: 0x%x vs 0xdb6db6db\n",
+ bad_syscall_args[3])
+ }
+ if (bad_syscall_args[4] != 0x24924924) {
+ failures += 4
+ printf("bad_syscall bad arg 4: 0x%x vs 0x24924924\n",
+ bad_syscall_args[4])
+ }
+ if (bad_syscall_args[5] != 0xad6b5ad6) {
+ failures += 1
+ printf("bad_syscall bad arg 5: 0x%x vs 0xad6b5ad6\n",
+ bad_syscall_args[5])
+ }
+ if (bad_syscall_args[6] != 0xdef7ddef) {
+ failures += 1
+ printf("bad_syscall bad arg 6: 0x%x vs 0xdef7ddef\n",
+ bad_syscall_args[6])
+ }
+ }
+
+ # Validate syscall number
+ if (bad_syscall_args[0] != bad_syscall_args[8]) {
+ failures += 1
+ printf("bad_syscall $syscall mismatch: %d vs. %d\n",
+ bad_syscall_args[0], bad_syscall_args[8])
+ }
+ }
+
+ if (failures == 0) {
+ printf("systemtap test success\n")
+ }
+ else {
+ printf("systemtap test failure\n")
+ }
+}
diff --git a/testsuite/systemtap.base/x86_gs.exp b/testsuite/systemtap.base/x86_gs.exp
new file mode 100644
index 00000000..98ab3051
--- /dev/null
+++ b/testsuite/systemtap.base/x86_gs.exp
@@ -0,0 +1,12 @@
+set test "x86_gs"
+if {![installtest_p]} { untested $test; return }
+set arch [exec uname -m]
+if {$arch!="i686"} { untested $test; return }
+spawn stap $srcdir/$subdir/x86_gs.stp
+expect {
+ -timeout 60
+ -re "0\r\n" { pass $test }
+ -re "140\r\n" { pass $test }
+ eof { fail $test }
+ timeout { fail "$test unexpected timeout" }
+}
diff --git a/testsuite/systemtap.base/x86_gs.stp b/testsuite/systemtap.base/x86_gs.stp
new file mode 100644
index 00000000..68b58512
--- /dev/null
+++ b/testsuite/systemtap.base/x86_gs.stp
@@ -0,0 +1,10 @@
+#! stap
+
+# test x86 gs register
+
+probe begin {
+ if (!_stp_regs_registered)
+ _stp_register_regs()
+ printf("%d\n",test_x86_gs() * 100 + _reg_offsets["gs"]) /* 0 or 140 */
+ exit()
+}
diff --git a/testsuite/systemtap.context/args.tcl b/testsuite/systemtap.context/args.tcl
index 7cb79cdf..cffaeaef 100644
--- a/testsuite/systemtap.context/args.tcl
+++ b/testsuite/systemtap.context/args.tcl
@@ -1,6 +1,6 @@
spawn stap $srcdir/$subdir/args.stp
expect {
- -timeout 240
+ -timeout 60
"READY" {
exec echo 1 > /proc/stap_test_cmd
expect {
diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl
index ca60c369..975e6c4d 100644
--- a/testsuite/systemtap.context/backtrace.tcl
+++ b/testsuite/systemtap.context/backtrace.tcl
@@ -5,10 +5,11 @@ set m4 0
set m5 0
set m6 0
+#spawn stap -d kernel -d systemtap_test_module1 -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp
spawn stap -DMAXSTRINGLEN=256 $srcdir/$subdir/backtrace.stp
#exp_internal 1
expect {
- -timeout 240
+ -timeout 60
"Systemtap probe: begin\r\n" {
pass "backtrace of begin probe"
exec echo 0 > /proc/stap_test_cmd
diff --git a/testsuite/systemtap.context/context.exp b/testsuite/systemtap.context/context.exp
index 010db445..52bf260d 100644
--- a/testsuite/systemtap.context/context.exp
+++ b/testsuite/systemtap.context/context.exp
@@ -23,7 +23,7 @@ proc build_modules {} {
global build_dir
global srcdir subdir
- if {[catch {exec mktemp -d staptestXXXXX} build_dir]} {
+ if {[catch {exec mktemp -d staptestXXXXXX} build_dir]} {
puts stderr "Failed to create temporary directory: $build_dir"
return 0
}
@@ -80,6 +80,7 @@ if {[build_modules] == 0} {
}
foreach test $testlist {
+ send_log "sourcing: $srcdir/$subdir/$test.tcl\n"
source $srcdir/$subdir/$test.tcl
}
diff --git a/testsuite/systemtap.context/num_args.tcl b/testsuite/systemtap.context/num_args.tcl
index 7d12b433..62ac8dd3 100644
--- a/testsuite/systemtap.context/num_args.tcl
+++ b/testsuite/systemtap.context/num_args.tcl
@@ -3,7 +3,7 @@ foreach arglist $arglists {
set tag [concat numeric $arglist]
eval spawn stap $arglist $srcdir/$subdir/num_args.stp
expect {
- -timeout 240
+ -timeout 60
"READY" {
exec echo 1 > /proc/stap_test_cmd
expect {
diff --git a/testsuite/systemtap.context/pid.tcl b/testsuite/systemtap.context/pid.tcl
index a2c091f1..70a87345 100644
--- a/testsuite/systemtap.context/pid.tcl
+++ b/testsuite/systemtap.context/pid.tcl
@@ -2,7 +2,7 @@ set tests [list execname pexecname pid ppid tid uid euid gid egid]
spawn stap $srcdir/$subdir/pid.stp
#exp_internal 1
expect {
- -timeout 240
+ -timeout 60
"READY" {
set pid [exec echo 1 > /proc/stap_test_cmd &]
set ppid {[0-9]*}
diff --git a/testsuite/systemtap.context/usymbols.c b/testsuite/systemtap.context/usymbols.c
new file mode 100644
index 00000000..7c590724
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols.c
@@ -0,0 +1,39 @@
+/* usymbol test case
+ * 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.
+ *
+ * Uses signal to tranfer user space addresses into the kernel where a
+ * probe on sigaction will extract them and produce the symbols. To
+ * poke into the executable we get the sa_handler from the main executable,
+ * and then the library through calling signal.
+ *
+ * FIXME. We call into the library to get the right symbol. If we
+ * register the handler from the main executable. We need to handle
+ * @plt symbols (setting a handler in the main executable that is in a
+ * shared library will have the @plt address, not the address inside
+ * the shared library).
+ */
+
+#include <signal.h>
+typedef void (*sighandler_t)(int);
+
+// function from our library
+int lib_main (void);
+
+void
+main_handler (int signum)
+{
+ /* dummy handler, just used for the address... */
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ // Use SIGFPE since we never expect that to be triggered.
+ signal(SIGFPE, main_handler);
+ lib_main();
+}
diff --git a/testsuite/systemtap.context/usymbols.exp b/testsuite/systemtap.context/usymbols.exp
new file mode 100644
index 00000000..39b3b442
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols.exp
@@ -0,0 +1,82 @@
+set test "./usymbols"
+set testpath "$srcdir/$subdir"
+set testsrc "$testpath/usymbols.c"
+set testsrclib "$testpath/usymbols_lib.c"
+set testexe "[pwd]/usymbols"
+set testlibname "usymbols"
+set testlibdir "[pwd]"
+set testso "$testlibdir/lib${testlibname}.so"
+set testflags "additional_flags=-g additional_flags=-O"
+set testlibflags "testflags additional_flags=-fPIC additional_flags=-shared"
+set maintestflags "$testflags additional_flags=-L$testlibdir additional_flags=-l$testlibname additional_flags=-Wl,-rpath,$testlibdir"
+
+# Only run on make installcheck and utrace present.
+if {! [installtest_p]} { untested "$test"; return }
+if {! [utrace_p]} { untested "$test"; return }
+
+# Compile our test program and library.
+set res [target_compile $testsrclib $testso executable $testlibflags]
+if { $res != "" } {
+ verbose "target_compile for $testso failed: $res" 2
+ fail "unable to compile $testsrclib"
+ return
+}
+set res [target_compile $testsrc $testexe executable $maintestflags]
+if { $res != "" } {
+ verbose "target_compile failed: $res" 2
+ fail "unable to compile $testsrc"
+ return
+}
+
+# We need the execname() trick to work around (the workaround of) PR6964
+# otherwise we get also the rt_sigactions of stapio. Get the handler
+# (comes from the executable or the library).
+set testscript {
+ probe syscall.rt_sigaction {
+ if (pid() == target() && execname() == "%s") {
+ handler = $act->sa_handler;
+ printf("handler: %%s\n", usymname(handler));
+ }
+ }
+ /* track through uprobes, so as to make sure we have the symbols */
+ probe process("%s").function("*") { printf(""); }
+}
+
+set output {handler: main_handler
+handler: lib_handler}
+
+# Got to run stap with both the exe and the libraries used as -d args.
+# XXX Note how we need the fully resolved (absolute) path...
+set script [format $testscript usymbols $testexe]
+catch {eval exec [concat ldd $testexe | grep $testlibname]} libpath
+set libpath [lindex [split $libpath " "] 2]
+send_log "libpath: $libpath\n"
+if {[string equal "link" [file type $libpath]]} {
+ set libpath [file join [file dirname $libpath] [file readlink $libpath]]
+}
+send_log "libpath: $libpath\n"
+
+set cmd [concat stap -d $libpath -d $testexe -c $testexe -e {$script}]
+send_log "cmd: $cmd\n"
+catch {eval exec $cmd} res
+send_log "cmd output: $res\n"
+
+set n 0
+set m [llength [split $output "\n"]]
+set expected [split $output "\n"]
+foreach line [split $res "\n"] {
+ if {![string equal $line [lindex $expected $n]]} {
+ fail usymbols
+ send_log "line [expr $n + 1]: expected \"[lindex $expected $n]\", "
+ send_log "Got \"$line\"\n"
+ return
+ }
+ incr n
+}
+if { $n != $m } {
+ fail usymbols
+ send_log "Got \"$n\" lines, expected \"$m\" lines\n"
+} else {
+ pass usymbols
+}
+exec rm -f $testexe $testso
diff --git a/testsuite/systemtap.context/usymbols_lib.c b/testsuite/systemtap.context/usymbols_lib.c
new file mode 100644
index 00000000..faccb39b
--- /dev/null
+++ b/testsuite/systemtap.context/usymbols_lib.c
@@ -0,0 +1,29 @@
+/* usymbol test case - library helper
+ * 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.
+ *
+ * Uses signal to tranfer user space addresses into the kernel where a
+ * probe on sigaction will extract them and produce the symbols. To
+ * poke into the executable we get the sa_handler set through signal
+ * from this library.
+ */
+
+#include <signal.h>
+typedef void (*sighandler_t)(int);
+
+void
+lib_handler (int signum)
+{
+ /* dummy handler, just used for the address... */
+}
+
+void
+lib_main ()
+{
+ // Use SIGFPE since we never expect that to be triggered.
+ signal(SIGFPE, lib_handler);
+}
diff --git a/testsuite/systemtap.examples/README b/testsuite/systemtap.examples/README
index e505bdfb..89586ece 100644
--- a/testsuite/systemtap.examples/README
+++ b/testsuite/systemtap.examples/README
@@ -1,57 +1,105 @@
-This directory contains example scripts.
+This text describes contribution procedures for adding scripts to
+systemtap.examples directory. Please read before submitting SystemTap
+examples. Discussions take place on the
+<systemtap@sources.redhat.com> mailing list.
-Each script should be checked in as executable.
+- general
-The first line should be
-#! /usr/bin/env stap
+ The script should do something that normal users of SystemTap might
+ like to do, such as show which processes have system calls that time
+ out or show which memory accesses cause page faults. Scripts that
+ check that some aspect of SystemTap operates correctly, but would
+ never be used by a regular user should go in one of the other
+ testsuite directories.
-There should be an accompanying ".meta" file describing what the
-script does and how to use it, and how the testsuite should compile
-and run it. The meta files are also used to create a txt and html
-index (by keyword and subsystem) of all the examples by the
-examples-index-gen.pl script.
+- copyright
-The meta file contains the following elements. Each element (key and
-value) are on one line. If a key can have a list of values, the list
-elements are separated by spaces.
+ You must designate the appropriate copyright holder for your
+ contribution. The copyright holder is assumed to agree with the
+ general licensing terms (GPLv2+).
+
+- coding style
-title: Descriptive title for the script (required)
-name: the file name for the script, e.g. iotime.stp (required)
-version: versioning if any fixes and developed can be identified (required)
-author: name of author(s), "anonymous" if unknown (required)
-exclusivearch: Stated if the script can only run on some arches
+ Abide by the general formatting of the code for SystemTap. The
+ code base generally follows the GNU standards in usermode code and
+ the Linux kernel standards in runtime code.
+
+ - Try to keep the lines shorter than 80 characters long.
+ - Make use of SystemTap functions to factor out common idioms in code.
+ - Use tapset probe points rather than raw function names.
+ - No probes by file and line number are allowed in examples.
+ - Avoid using guru mode (-g) in the examples.
+ - Minimize use of globals variables:
+ All associative arrays must be global in SystemTap.
+ Variables used only for the duration of a probe should be local.
+ - Make the file executable and use the following line at the
+ beginning of the script to select the proper interpreter:
+
+ #! /usr/bin/env stap
+
+- Describe the example
+
+ Each example script has a description in a .meta file that provide
+ an easy-to-parse format that describes various aspect of the example
+ script. The .meta file has the same base name as the example script.
+ The .meta file is parsed to generate a web page listing all the
+ available examples; the webpage is available at:
+ http://sourceware.org/systemtap/examples/. The .meta file also
+ describes how to run the compiled example script for testing. This
+ ensures that the example is frequently run to verified it works on a
+ wide range fo platforms.
+
+ The meta file contains the following elements. Each element (key and
+ value) are on one line. If a key can have a list of values, the list
+ elements are separated by spaces.
+
+ title: Descriptive title for the script (required)
+ name: the file name for the script, e.g. iotime.stp (required)
+ version: versioning if any fixes and developed can be identified (required)
+ author: name of author(s), "anonymous" if unknown (required)
+ exclusivearch: Stated if the script can only run on some arches
this concept borrowed from rpm, matches types for rpm:
x86 i386 x86_64 ppc ppc64, s390 (optional)
-requires: Some scripts may require software to be available. In some cases
- may need version numbering, e.g. kernel >= 2.6
- Can have multiple "requires:" tags. (optional)
-keywords: List of likely words to categorize the script (required)
- keywords are separated by spaces.
- #FIXME have list of keyword
-subsystem: List what part of the kernel the instrumentation probes (required)
- audit cpu blockio file filesystem locking memory numa network
- process scheduler or user-space (probes are in the user-space)
-application: when user-space probing becomes available (optional)
- a script might probe a particular application
- this tag indicates the applicaton
-status: describes the state of development for the script (required)
- proposed just an idea
- experimental an implemented idea, but use at own risk
- alpha
- beta
- production should be safe to use
-exit: how long do the script run? (required)
- fixed exits in a fixed amount of time
- user-controlled exits with "cntrl-c"
- event-ended exits with some arbitrary event
-output: what kind of output does the script generate? (required)
- trace histogram graph sorted batch timed
-scope: How much of the processes on the machine does the script watch?
- system-wide or pid
-arg_[0-9]+: Describe what the arguments into the script are. (optional)
-description: A text description what the script does. (required)
-test_check: How to check that the example compiles.
- (e.g. stap -p4 iotime.stp)
-test_installcheck: How to check that the example runs.
- (e.g. stap iotime.stp -c "sleep 1")
+ requires: Some scripts may require software to be available. In some cases
+ may need version numbering, e.g. kernel >= 2.6
+ Can have multiple "requires:" tags. (optional)
+ keywords: List of likely words to categorize the script (required)
+ keywords are separated by spaces.
+ #FIXME have list of keyword
+ subsystem: List what part of the kernel the instrumentation probes (required)
+ audit cpu blockio file filesystem locking memory numa network
+ process scheduler or user-space (probes are in the user-space)
+ application: when user-space probing becomes available (optional)
+ a script might probe a particular application
+ this tag indicates the applicaton
+ status: describes the state of development for the script (required)
+ proposed just an idea
+ experimental an implemented idea, but use at own risk
+ alpha
+ beta
+ production should be safe to use
+ exit: how long do the script run? (required)
+ fixed exits in a fixed amount of time
+ user-controlled exits with "cntrl-c"
+ event-ended exits with some arbitrary event
+ output: what kind of output does the script generate? (required)
+ trace histogram graph sorted batch timed
+ scope: How much of the processes on the machine does the script watch?
+ system-wide or pid
+ arg_[0-9]+: Describe what the arguments into the script are. (optional)
+ description: A text description what the script does. (required)
+ test_check: How to check that the example compiles.
+ (e.g. stap -p4 iotime.stp)
+ test_installcheck: How to check that the example runs.
+ (e.g. stap iotime.stp -c "sleep 1")
+
+
+- Review, revision, and submission of the example script
+
+ When you have a SystemTap script that should be included as an
+ example, submit it to the SystemTap mailing list,
+ systemtap@sources.redhat.com for review. Even if the script is not
+ ready for submission as an example, feel free to ask questions or
+ discuss the work-in-progress script with other people working with
+ SystemTap.
diff --git a/testsuite/systemtap.examples/general/ansi_colors.meta b/testsuite/systemtap.examples/general/ansi_colors.meta
new file mode 100644
index 00000000..2818c235
--- /dev/null
+++ b/testsuite/systemtap.examples/general/ansi_colors.meta
@@ -0,0 +1,13 @@
+title: Color Table for ansi_set_color2() and ansi_set_color3()
+name: ansi_colors.stp
+version: 1.0
+author: Eugene Teo
+keywords: format
+subsystem: none
+status: production
+exit: fixed
+output: text
+scope: system-wide
+description: The script prints a table showing the available color combinations for the ansi_set_color2() and ans_set_color3() functions in the ansi.stp tapset.
+test_check: stap -p4 ansi_colors.stp
+test_installcheck: stap ansi_colors.stp
diff --git a/testsuite/systemtap.examples/general/ansi_colors.stp b/testsuite/systemtap.examples/general/ansi_colors.stp
index ae954e69..01e58b9c 100755
--- a/testsuite/systemtap.examples/general/ansi_colors.stp
+++ b/testsuite/systemtap.examples/general/ansi_colors.stp
@@ -1,21 +1,30 @@
-#! /usr/bin/env stap
+#!/usr/bin/env stap
+# ansi_colors.stp
+# Copyright (C) 2006-2009 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
probe begin {
- printf("a \\ b |");
- for (c = 40; c < 48; c++)
- printf(" %d ", c);
- printf("\12");
- for (l = 0; l < 71; l++)
- printf("-");
- printf("\12");
+ printf("fg,t \\ bg |");
+ for (c = 40; c < 48; c++)
+ printf(" %d ", c);
+ ansi_new_line()
+ for (l = 0; l < 75; l++)
+ printf("-");
+ ansi_new_line()
- for (r = 30; r < 38; r++)
- for (t = 0; t < 2; t++) {
- printf("%d |", r);
- for (c = 40; c < 48; c++)
- printf("\033[%d;%d%s %s \033[0;0m",
- r, c, !t ? "m" : ";1m", !t ? "Normal" : "Bold ");
- printf("\12");
- }
- exit();
+ for (r = 30; r < 38; r++)
+ for (t = 0; t < 2; t++) {
+ printf(" %2d,%1d |", r, t);
+ for (c = 40; c < 48; c++) {
+ ansi_set_color3(r, c, t)
+ printf(" %s ", !t ? "Normal" : "Bold ")
+ ansi_reset_color()
+ }
+ ansi_new_line()
+ }
+ exit();
}
diff --git a/testsuite/systemtap.examples/general/ansi_colors2.meta b/testsuite/systemtap.examples/general/ansi_colors2.meta
new file mode 100644
index 00000000..4ccaf4e3
--- /dev/null
+++ b/testsuite/systemtap.examples/general/ansi_colors2.meta
@@ -0,0 +1,13 @@
+title: Show Attribues in Table for ansi_set_color3()
+name: ansi_colors2.stp
+version: 1.0
+author: Eugene Teo
+keywords: format
+subsystem: none
+status: production
+exit: fixed
+output: text
+scope: system-wide
+description: The script prints a table showing the available attributes (bold, underline, and inverse) with color combinations for the ans_set_color3() function in the ansi.stp tapset.
+test_check: stap -p4 ansi_colors2.stp
+test_installcheck: stap ansi_colors2.stp
diff --git a/testsuite/systemtap.examples/general/ansi_colors2.stp b/testsuite/systemtap.examples/general/ansi_colors2.stp
new file mode 100755
index 00000000..fadcf011
--- /dev/null
+++ b/testsuite/systemtap.examples/general/ansi_colors2.stp
@@ -0,0 +1,31 @@
+#!/usr/bin/env stap
+# ansi_colors2.stp
+# Copyright (C) 2009 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+
+probe begin {
+ printf("fg,t \\ bg |");
+ for (c = 40; c < 48; c++)
+ printf(" %d ", c);
+ ansi_new_line()
+ for (l = 0; l < 75; l++)
+ printf("-");
+ ansi_new_line()
+
+ for (r = 30; r < 38; r++)
+ # this displays more attributes
+ for (t = 0; t < 8; !t ? ++t : t+=3) {
+ printf(" %2d,%1d |", r, t);
+ for (c = 40; c < 48; c++) {
+ ansi_set_color3(r, c, t)
+ printf(" Colors ")
+ ansi_reset_color()
+ }
+ ansi_new_line()
+ }
+ exit();
+}
diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp
new file mode 100644
index 00000000..4f326ec1
--- /dev/null
+++ b/testsuite/systemtap.examples/general/grapher.stp
@@ -0,0 +1,32 @@
+#! /usr/bin/stap
+
+probe begin
+{
+printf ("%%Title:CPU utilization\n");
+printf ("%%XAxisTitle:Time");
+printf ("%%YAxisTitle:Percent");
+printf ("%%DataSet:cpu 100 00ff00 bar");
+printf ("%%DataSet:kbd 100 ff0000 dot");
+}
+
+# CPU utilization
+probe begin { qnames["cpu"] ++; qsq_start ("cpu") }
+probe scheduler.cpu_on { if (!idle) {qs_wait ("cpu") qs_run ("cpu") }}
+probe scheduler.cpu_off { if (!idle) qs_done ("cpu") }
+
+global qnames
+
+function qsq_util_reset(q) {
+ u=qsq_utilization (q, 100)
+ qsq_start (q)
+ return u
+}
+
+probe timer.ms(100) { # collect utilization percentages frequently
+ foreach (q in qnames)
+ printf("cpu %d %d\n", gettimeofday_ms(), qsq_util_reset(q))
+}
+
+probe kernel.function("kbd_event") {
+ printf("kbd %d %d\n", gettimeofday_ms(), 75)
+}
diff --git a/testsuite/systemtap.examples/general/para-callgraph.meta b/testsuite/systemtap.examples/general/para-callgraph.meta
index 87af07cf..84d1c93f 100644
--- a/testsuite/systemtap.examples/general/para-callgraph.meta
+++ b/testsuite/systemtap.examples/general/para-callgraph.meta
@@ -3,5 +3,5 @@ name: para-callgraph.stp
keywords: trace callgraph
subsystem: general
description: Print a timed per-thread callgraph, complete with function parameters and return values. The first parameter names the function probe points to trace. The optional second parameter names the probe points for trigger functions, which acts to enable tracing for only those functions that occur while the current thread is nested within the trigger.
-test_check: stap -p4 para-callgraph.stp kernel.function("*@fs/proc*.c") kernel.function("sys_read")
-test_installcheck: stap para-callgraph.stp kernel.function("*@fs/proc*.c") kernel.function("sys_read") -c "cat /proc/sys/vm/*"
+test_check: stap -p4 para-callgraph.stp kernel.function("*@fs/proc*.c") kernel.function("vfs_read")
+test_installcheck: stap para-callgraph.stp kernel.function("*@fs/proc*.c") kernel.function("vfs_read") -c "cat /proc/sys/vm/*"
diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html
index 7b76baa1..0df681ac 100644
--- a/testsuite/systemtap.examples/index.html
+++ b/testsuite/systemtap.examples/index.html
@@ -40,6 +40,12 @@
<h2>All Examples</h2>
<ul>
+<li><a href="general/ansi_colors.stp">general/ansi_colors.stp</a> - Color Table for ansi_set_color2() and ansi_set_color3()<br>
+keywords: <a href="keyword-index.html#FORMAT">FORMAT</a> <br>
+<p>The script prints a table showing the available color combinations for the ansi_set_color2() and ans_set_color3() functions in the ansi.stp tapset.</p></li>
+<li><a href="general/ansi_colors2.stp">general/ansi_colors2.stp</a> - Show Attribues in Table for ansi_set_color3()<br>
+keywords: <a href="keyword-index.html#FORMAT">FORMAT</a> <br>
+<p>The script prints a table showing the available attributes (bold, underline, and inverse) with color combinations for the ans_set_color3() function in the ansi.stp tapset.</p></li>
<li><a href="general/graphs.stp">general/graphs.stp</a> - Graphing Disk and CPU Utilization<br>
keywords: <a href="keyword-index.html#DISK">DISK</a> <a href="keyword-index.html#CPU">CPU</a> <a href="keyword-index.html#USE">USE</a> <a href="keyword-index.html#GRAPH">GRAPH</a> <br>
<p>The script tracks the disk and CPU utilization. The resulting output of the script can be piped into gnuplot to generate a graph of disk and CPU USE.</p></li>
@@ -58,6 +64,9 @@ keywords: <a href="keyword-index.html#DISK">DISK</a> <br>
<li><a href="io/io_submit.stp">io/io_submit.stp</a> - Tally Reschedule Reason During AIO io_submit Call<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#BACKTRACE">BACKTRACE</a> <br>
<p>When a reschedule occurs during an AIO io_submit call, accumulate the traceback in a histogram. When the script exits prints out a sorted list from most common to least common backtrace.</p></li>
+<li><a href="io/ioblktime.stp">io/ioblktime.stp</a> - Average Time Block IO Requests Spend in Queue <br>
+keywords: <a href="keyword-index.html#IO">IO</a> <br>
+<p>The ioblktime.stp script tracks the amount of time that each block IO requests spend waiting for completion. The script computes the average time waiting time for block IO per device and prints list every 10 seconds. In some cases there can be too many oustanding block IO operations and the script may exceed the default number of MAXMAPENTRIES allowed. In this case the allowed number can be increased with "-DMAXMAPENTRIES=10000" option on the stap command line.</p></li>
<li><a href="io/iostats.stp">io/iostats.stp</a> - List Executables Reading and Writing the Most Data<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
<p> The iostat.stp script measures the amount of data successfully read and written by all the executables on the system. The output is sorted from most greatest sum of bytes read and written by an executable to the least. The output contains the count of operations (opens, reads, and writes), the totals and averages for the number of bytes read and written.</p></li>
@@ -79,6 +88,9 @@ keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<li><a href="memory/pfaults.stp">memory/pfaults.stp</a> - Generate Log of Major and Minor Page Faults<br>
keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
<p>The pfaults.stp script generates a simple log for each major and minor page fault that occurs on the system. Each line contains a timestamp (in microseconds) when the page fault servicing was completed, the pid of the process, the address of the page fault, the type of access (read or write), the type of fault (major or minor), and the elapsed time for page fault. This log can be examined to determine where the page faults are occuring.</p></li>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
<li><a href="network/nettop.stp">network/nettop.stp</a> - Periodic Listing of Processes Using Network Interfaces<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <a href="keyword-index.html#PER-PROCESS">PER-PROCESS</a> <br>
<p>Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.</p></li>
@@ -88,6 +100,12 @@ keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-inde
<li><a href="network/tcp_connections.stp">network/tcp_connections.stp</a> - Track Creation of Incoming TCP Connections<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TCP">TCP</a> <a href="keyword-index.html#SOCKET">SOCKET</a> <br>
<p>The tcp_connections.stp script prints information for each new incoming TCP connection accepted by the computer. The information includes the UID, the command accepting the connection, the PID of the command, the port the connection is on, and the IP address of the originator of the request.</p></li>
+<li><a href="network/tcpdumplike.stp">network/tcpdumplike.stp</a> - Dump of Received TCP Packets<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <br>
+<p>The tcpdumplike.stp prints out a line for each TCP packet received. Each line includes the source and destination IP addresses, the source and destination ports, and flags.</p></li>
+<li><a href="process/errsnoop.stp">process/errsnoop.stp</a> - tabulate system call errors<br>
+keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-index.html#SYSCALL">SYSCALL</a> <br>
+<p>The script prints a periodic tabular report about failing system calls, by process and by syscall failure. The first optional argument specifies the reporting interval (in seconds, default 5); the second optional argument gives a screen height (number of lines in the report, default 20).</p></li>
<li><a href="process/futexes.stp">process/futexes.stp</a> - System-Wide Futex Contention<br>
keywords: <a href="keyword-index.html#SYSCALL">SYSCALL</a> <a href="keyword-index.html#LOCKING">LOCKING</a> <a href="keyword-index.html#FUTEX">FUTEX</a> <br>
<p>The script watches the futex syscall on the system. On exit the futexes address, the number of contentions, and the average time for each contention on the futex are printed from lowest pid number to highest.</p></li>
@@ -103,7 +121,7 @@ keywords: <a href="keyword-index.html#SIGNALS">SIGNALS</a> <br>
<li><a href="process/sigkill.stp">process/sigkill.stp</a> - Track SIGKILL Signals<br>
keywords: <a href="keyword-index.html#SIGNALS">SIGNALS</a> <br>
<p>The script traces any SIGKILL signals. When that SIGKILL signal is sent to a process, the script prints out the signal name, the desination executable and process ID, the executable name user ID that sent the signal.</p></li>
-<li><a href="process/syscalls_by_pid.stp">process/syscalls_by_pid.stp</a> - System-Wide Count of Syscalls by PID<br>
+<li><a href="process/sigmon.stp">process/sigmon.stp</a> - Track a particular signal to a specific process<br>
keywords: <a href="keyword-index.html#SIGNALS">SIGNALS</a> <br>
<p>The script watches for a particular signal sent to a specific process. When that signal is sent to the specified process, the script prints out the PID and executable of the process sending the signal, the PID and executable name of the process receiving the signal, and the signal number and name.</p></li>
<li><a href="process/sleepingBeauties.stp">process/sleepingBeauties.stp</a> - Generating Backtraces of Threads Waiting for IO Operations<br>
diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt
index fdcd3b31..fa344933 100644
--- a/testsuite/systemtap.examples/index.txt
+++ b/testsuite/systemtap.examples/index.txt
@@ -1,6 +1,22 @@
SYSTEMTAP EXAMPLES INDEX
(see also keyword-index.txt)
+general/ansi_colors.stp - Color Table for ansi_set_color2() and ansi_set_color3()
+keywords: format
+
+ The script prints a table showing the available color combinations
+ for the ansi_set_color2() and ans_set_color3() functions in the
+ ansi.stp tapset.
+
+
+general/ansi_colors2.stp - Show Attribues in Table for ansi_set_color3()
+keywords: format
+
+ The script prints a table showing the available attributes (bold,
+ underline, and inverse) with color combinations for the
+ ans_set_color3() function in the ansi.stp tapset.
+
+
general/graphs.stp - Graphing Disk and CPU Utilization
keywords: disk cpu use graph
@@ -52,6 +68,19 @@ keywords: io backtrace
list from most common to least common backtrace.
+io/ioblktime.stp - Average Time Block IO Requests Spend in Queue
+keywords: io
+
+ The ioblktime.stp script tracks the amount of time that each block IO
+ requests spend waiting for completion. The script computes the
+ average time waiting time for block IO per device and prints list
+ every 10 seconds. In some cases there can be too many oustanding
+ block IO operations and the script may exceed the default number of
+ MAXMAPENTRIES allowed. In this case the allowed number can be
+ increased with "-DMAXMAPENTRIES=10000" option on the stap command
+ line.
+
+
io/iostats.stp - List Executables Reading and Writing the Most Data
keywords: io profiling
@@ -123,6 +152,13 @@ keywords: memory
determine where the page faults are occuring.
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
keywords: network traffic per-process
@@ -153,6 +189,24 @@ keywords: network tcp socket
originator of the request.
+network/tcpdumplike.stp - Dump of Received TCP Packets
+keywords: network traffic
+
+ The tcpdumplike.stp prints out a line for each TCP packet received.
+ Each line includes the source and destination IP addresses, the
+ source and destination ports, and flags.
+
+
+process/errsnoop.stp - tabulate system call errors
+keywords: process syscall
+
+ The script prints a periodic tabular report about failing system
+ calls, by process and by syscall failure. The first optional
+ argument specifies the reporting interval (in seconds, default 5);
+ the second optional argument gives a screen height (number of lines
+ in the report, default 20).
+
+
process/futexes.stp - System-Wide Futex Contention
keywords: syscall locking futex
@@ -191,7 +245,7 @@ keywords: signals
that sent the signal.
-process/syscalls_by_pid.stp - System-Wide Count of Syscalls by PID
+process/sigmon.stp - Track a particular signal to a specific process
keywords: signals
The script watches for a particular signal sent to a specific
diff --git a/testsuite/systemtap.examples/io/ioblktime.meta b/testsuite/systemtap.examples/io/ioblktime.meta
new file mode 100644
index 00000000..18a8b168
--- /dev/null
+++ b/testsuite/systemtap.examples/io/ioblktime.meta
@@ -0,0 +1,13 @@
+title: Average Time Block IO Requests Spend in Queue
+name: ioblktime.stp
+version: 1.0
+author: William Cohen
+keywords: io
+subsystem: kernel
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The ioblktime.stp script tracks the amount of time that each block IO requests spend waiting for completion. The script computes the average time waiting time for block IO per device and prints list every 10 seconds. In some cases there can be too many oustanding block IO operations and the script may exceed the default number of MAXMAPENTRIES allowed. In this case the allowed number can be increased with "-DMAXMAPENTRIES=10000" option on the stap command line.
+test_check: stap -p4 ioblktime.stp
+test_installcheck: stap ioblktime.stp -c "sleep 1"
diff --git a/testsuite/systemtap.examples/io/ioblktime.stp b/testsuite/systemtap.examples/io/ioblktime.stp
new file mode 100755
index 00000000..d6267b3e
--- /dev/null
+++ b/testsuite/systemtap.examples/io/ioblktime.stp
@@ -0,0 +1,29 @@
+#! /usr/bin/env stap
+
+global req_time, etimes
+
+probe ioblock.request
+{
+ req_time[$bio] = gettimeofday_us()
+}
+
+probe ioblock.end
+{
+ t = gettimeofday_us()
+ s = req_time[$bio]
+ delete req_time[$bio]
+ if (s) {
+ etimes[devname, bio_rw_str(rw)] <<< t - s
+ }
+}
+
+probe timer.s(10), end {
+ ansi_clear_screen()
+ printf("%10s %3s %10s %10s %10s\n",
+ "device", "rw", "total (us)", "count", "avg (us)")
+ foreach ([dev,rw] in etimes - limit 20) {
+ printf("%10s %3s %10d %10d %10d\n", dev, rw,
+ @sum(etimes[dev,rw]), @count(etimes[dev,rw]), @avg(etimes[dev,rw]))
+ }
+ delete etimes
+}
diff --git a/testsuite/systemtap.examples/io/traceio.stp b/testsuite/systemtap.examples/io/traceio.stp
index 9e2deec6..875000cb 100755
--- a/testsuite/systemtap.examples/io/traceio.stp
+++ b/testsuite/systemtap.examples/io/traceio.stp
@@ -1,6 +1,9 @@
#! /usr/bin/env stap
# traceio.stp
# Copyright (C) 2007 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
+# Copyright (C) 2009 Kai Meyer <kai@unixlords.com>
+# Fixed a bug that allows this to run longer
+# And added the humanreadable function
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
@@ -10,22 +13,32 @@
global reads, writes, total_io
probe vfs.read.return {
- reads[execname()] += $return
+ reads[pid(),execname()] += $return
+ total_io[pid(),execname()] += $return
}
probe vfs.write.return {
- writes[execname()] += $return
+ writes[pid(),execname()] += $return
+ total_io[pid(),execname()] += $return
+}
+
+function humanreadable(bytes) {
+ if (bytes > 1024*1024*1024) {
+ return sprintf("%d GiB", bytes/1024/1024/1024)
+ } else if (bytes > 1024*1024) {
+ return sprintf("%d MiB", bytes/1024/1024)
+ } else if (bytes > 1024) {
+ return sprintf("%d KiB", bytes/1024)
+ } else {
+ return sprintf("%d B", bytes)
+ }
}
probe timer.s(1) {
- foreach (p in reads)
- total_io[p] += reads[p]
- foreach (p in writes)
- total_io[p] += writes[p]
- foreach(p in total_io- limit 10)
- printf("%15s r: %8d KiB w: %8d KiB\n",
- p, reads[p]/1024,
- writes[p]/1024)
+ foreach([p,e] in total_io- limit 10)
+ printf("%8d %15s r: %12s w: %12s\n",
+ p, e, humanreadable(reads[p,e]),
+ humanreadable(writes[p,e]))
printf("\n")
# Note we don't zero out reads, writes and total_io,
# so the values are cumulative since the script started.
diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html
index b3ea0943..7edbec21 100644
--- a/testsuite/systemtap.examples/keyword-index.html
+++ b/testsuite/systemtap.examples/keyword-index.html
@@ -39,7 +39,7 @@
</ul>
<h2>Examples by Keyword</h2>
-<p><tt><a href="#BACKTRACE">BACKTRACE</a> <a href="#CALLGRAPH">CALLGRAPH</a> <a href="#CPU">CPU</a> <a href="#DISK">DISK</a> <a href="#FUNCTIONS">FUNCTIONS</a> <a href="#FUTEX">FUTEX</a> <a href="#GRAPH">GRAPH</a> <a href="#INTERRUPT">INTERRUPT</a> <a href="#IO">IO</a> <a href="#LOCKING">LOCKING</a> <a href="#MEMORY">MEMORY</a> <a href="#NETWORK">NETWORK</a> <a href="#PER-PROCESS">PER-PROCESS</a> <a href="#PROFILING">PROFILING</a> <a href="#READ">READ</a> <a href="#SCHEDULER">SCHEDULER</a> <a href="#SIGNALS">SIGNALS</a> <a href="#SIMPLE">SIMPLE</a> <a href="#SLEEP">SLEEP</a> <a href="#SOCKET">SOCKET</a> <a href="#SYSCALL">SYSCALL</a> <a href="#TCP">TCP</a> <a href="#TIME">TIME</a> <a href="#TRACE">TRACE</a> <a href="#TRAFFIC">TRAFFIC</a> <a href="#USE">USE</a> <a href="#WAIT4">WAIT4</a> <a href="#WRITE">WRITE</a> </tt></p>
+<p><tt><a href="#BACKTRACE">BACKTRACE</a> <a href="#BUFFER">BUFFER</a> <a href="#CALLGRAPH">CALLGRAPH</a> <a href="#CPU">CPU</a> <a href="#DISK">DISK</a> <a href="#FORMAT">FORMAT</a> <a href="#FREE">FREE</a> <a href="#FUNCTIONS">FUNCTIONS</a> <a href="#FUTEX">FUTEX</a> <a href="#GRAPH">GRAPH</a> <a href="#INTERRUPT">INTERRUPT</a> <a href="#IO">IO</a> <a href="#LOCKING">LOCKING</a> <a href="#MEMORY">MEMORY</a> <a href="#NETWORK">NETWORK</a> <a href="#PER-PROCESS">PER-PROCESS</a> <a href="#PROCESS">PROCESS</a> <a href="#PROFILING">PROFILING</a> <a href="#READ">READ</a> <a href="#SCHEDULER">SCHEDULER</a> <a href="#SIGNALS">SIGNALS</a> <a href="#SIMPLE">SIMPLE</a> <a href="#SLEEP">SLEEP</a> <a href="#SOCKET">SOCKET</a> <a href="#SYSCALL">SYSCALL</a> <a href="#TCP">TCP</a> <a href="#TIME">TIME</a> <a href="#TRACE">TRACE</a> <a href="#TRACEPOINT">TRACEPOINT</a> <a href="#TRAFFIC">TRAFFIC</a> <a href="#USE">USE</a> <a href="#WAIT4">WAIT4</a> <a href="#WRITE">WRITE</a> </tt></p>
<h3><a name="BACKTRACE">BACKTRACE</a></h3>
<ul>
<li><a href="interrupt/scf.stp">interrupt/scf.stp</a> - Tally Backtraces for Inter-Processor Interrupt (IPI)<br>
@@ -52,6 +52,12 @@ keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#BAC
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#SCHEDULER">SCHEDULER</a> <a href="keyword-index.html#BACKTRACE">BACKTRACE</a> <br>
<p>The script monitors the time that threads spend waiting for IO operations (in "D" state) in the wait_for_completion function. If a thread spends over 10ms, its name and backtrace is printed, and later so is the total delay.</p></li>
</ul>
+<h3><a name="BUFFER">BUFFER</a></h3>
+<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
+</ul>
<h3><a name="CALLGRAPH">CALLGRAPH</a></h3>
<ul>
<li><a href="general/para-callgraph.stp">general/para-callgraph.stp</a> - Callgraph tracing with arguments<br>
@@ -73,6 +79,21 @@ keywords: <a href="keyword-index.html#DISK">DISK</a> <a href="keyword-index.html
keywords: <a href="keyword-index.html#DISK">DISK</a> <br>
<p>Get the status of reading/writing disk every 5 seconds, output top ten entries during that period.</p></li>
</ul>
+<h3><a name="FORMAT">FORMAT</a></h3>
+<ul>
+<li><a href="general/ansi_colors.stp">general/ansi_colors.stp</a> - Color Table for ansi_set_color2() and ansi_set_color3()<br>
+keywords: <a href="keyword-index.html#FORMAT">FORMAT</a> <br>
+<p>The script prints a table showing the available color combinations for the ansi_set_color2() and ans_set_color3() functions in the ansi.stp tapset.</p></li>
+<li><a href="general/ansi_colors2.stp">general/ansi_colors2.stp</a> - Show Attribues in Table for ansi_set_color3()<br>
+keywords: <a href="keyword-index.html#FORMAT">FORMAT</a> <br>
+<p>The script prints a table showing the available attributes (bold, underline, and inverse) with color combinations for the ans_set_color3() function in the ansi.stp tapset.</p></li>
+</ul>
+<h3><a name="FREE">FREE</a></h3>
+<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
+</ul>
<h3><a name="FUNCTIONS">FUNCTIONS</a></h3>
<ul>
<li><a href="profiling/functioncallcount.stp">profiling/functioncallcount.stp</a> - Count Times Functions Called<br>
@@ -102,6 +123,9 @@ keywords: <a href="keyword-index.html#INTERRUPT">INTERRUPT</a> <a href="keyword-
<li><a href="io/io_submit.stp">io/io_submit.stp</a> - Tally Reschedule Reason During AIO io_submit Call<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#BACKTRACE">BACKTRACE</a> <br>
<p>When a reschedule occurs during an AIO io_submit call, accumulate the traceback in a histogram. When the script exits prints out a sorted list from most common to least common backtrace.</p></li>
+<li><a href="io/ioblktime.stp">io/ioblktime.stp</a> - Average Time Block IO Requests Spend in Queue <br>
+keywords: <a href="keyword-index.html#IO">IO</a> <br>
+<p>The ioblktime.stp script tracks the amount of time that each block IO requests spend waiting for completion. The script computes the average time waiting time for block IO per device and prints list every 10 seconds. In some cases there can be too many oustanding block IO operations and the script may exceed the default number of MAXMAPENTRIES allowed. In this case the allowed number can be increased with "-DMAXMAPENTRIES=10000" option on the stap command line.</p></li>
<li><a href="io/iostats.stp">io/iostats.stp</a> - List Executables Reading and Writing the Most Data<br>
keywords: <a href="keyword-index.html#IO">IO</a> <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
<p> The iostat.stp script measures the amount of data successfully read and written by all the executables on the system. The output is sorted from most greatest sum of bytes read and written by an executable to the least. The output contains the count of operations (opens, reads, and writes), the totals and averages for the number of bytes read and written.</p></li>
@@ -138,6 +162,9 @@ keywords: <a href="keyword-index.html#MEMORY">MEMORY</a> <br>
</ul>
<h3><a name="NETWORK">NETWORK</a></h3>
<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
<li><a href="network/nettop.stp">network/nettop.stp</a> - Periodic Listing of Processes Using Network Interfaces<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <a href="keyword-index.html#PER-PROCESS">PER-PROCESS</a> <br>
<p>Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.</p></li>
@@ -147,6 +174,9 @@ keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-inde
<li><a href="network/tcp_connections.stp">network/tcp_connections.stp</a> - Track Creation of Incoming TCP Connections<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TCP">TCP</a> <a href="keyword-index.html#SOCKET">SOCKET</a> <br>
<p>The tcp_connections.stp script prints information for each new incoming TCP connection accepted by the computer. The information includes the UID, the command accepting the connection, the PID of the command, the port the connection is on, and the IP address of the originator of the request.</p></li>
+<li><a href="network/tcpdumplike.stp">network/tcpdumplike.stp</a> - Dump of Received TCP Packets<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <br>
+<p>The tcpdumplike.stp prints out a line for each TCP packet received. Each line includes the source and destination IP addresses, the source and destination ports, and flags.</p></li>
</ul>
<h3><a name="PER-PROCESS">PER-PROCESS</a></h3>
<ul>
@@ -154,6 +184,12 @@ keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-inde
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <a href="keyword-index.html#PER-PROCESS">PER-PROCESS</a> <br>
<p>Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.</p></li>
</ul>
+<h3><a name="PROCESS">PROCESS</a></h3>
+<ul>
+<li><a href="process/errsnoop.stp">process/errsnoop.stp</a> - tabulate system call errors<br>
+keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-index.html#SYSCALL">SYSCALL</a> <br>
+<p>The script prints a periodic tabular report about failing system calls, by process and by syscall failure. The first optional argument specifies the reporting interval (in seconds, default 5); the second optional argument gives a screen height (number of lines in the report, default 20).</p></li>
+</ul>
<h3><a name="PROFILING">PROFILING</a></h3>
<ul>
<li><a href="io/iostats.stp">io/iostats.stp</a> - List Executables Reading and Writing the Most Data<br>
@@ -198,7 +234,7 @@ keywords: <a href="keyword-index.html#SIGNALS">SIGNALS</a> <br>
<li><a href="process/sigkill.stp">process/sigkill.stp</a> - Track SIGKILL Signals<br>
keywords: <a href="keyword-index.html#SIGNALS">SIGNALS</a> <br>
<p>The script traces any SIGKILL signals. When that SIGKILL signal is sent to a process, the script prints out the signal name, the desination executable and process ID, the executable name user ID that sent the signal.</p></li>
-<li><a href="process/syscalls_by_pid.stp">process/syscalls_by_pid.stp</a> - System-Wide Count of Syscalls by PID<br>
+<li><a href="process/sigmon.stp">process/sigmon.stp</a> - Track a particular signal to a specific process<br>
keywords: <a href="keyword-index.html#SIGNALS">SIGNALS</a> <br>
<p>The script watches for a particular signal sent to a specific process. When that signal is sent to the specified process, the script prints out the PID and executable of the process sending the signal, the PID and executable name of the process receiving the signal, and the signal number and name.</p></li>
</ul>
@@ -228,6 +264,9 @@ keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-inde
<li><a href="io/iotime.stp">io/iotime.stp</a> - Trace Time Spent in Read and Write for Files <br>
keywords: <a href="keyword-index.html#SYSCALL">SYSCALL</a> <a href="keyword-index.html#READ">READ</a> <a href="keyword-index.html#WRITE">WRITE</a> <a href="keyword-index.html#TIME">TIME</a> <a href="keyword-index.html#IO">IO</a> <br>
<p>The script watches each open, close, read, and write syscalls on the system. For each file the scripts observes opened it accumulates the amount of wall clock time spend in read and write operations and the number of bytes read and written. When a file is closed the script prints out a pair of lines for the file. Both lines begin with a timestamp in microseconds, the PID number, and the executable name in parenthesese. The first line with the "access" keyword lists the file name, the attempted number of bytes for the read and write operations. The second line with the "iotime" keyword list the file name and the number of microseconds accumulated in the read and write syscalls.</p></li>
+<li><a href="process/errsnoop.stp">process/errsnoop.stp</a> - tabulate system call errors<br>
+keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-index.html#SYSCALL">SYSCALL</a> <br>
+<p>The script prints a periodic tabular report about failing system calls, by process and by syscall failure. The first optional argument specifies the reporting interval (in seconds, default 5); the second optional argument gives a screen height (number of lines in the report, default 20).</p></li>
<li><a href="process/futexes.stp">process/futexes.stp</a> - System-Wide Futex Contention<br>
keywords: <a href="keyword-index.html#SYSCALL">SYSCALL</a> <a href="keyword-index.html#LOCKING">LOCKING</a> <a href="keyword-index.html#FUTEX">FUTEX</a> <br>
<p>The script watches the futex syscall on the system. On exit the futexes address, the number of contentions, and the average time for each contention on the futex are printed from lowest pid number to highest.</p></li>
@@ -262,11 +301,20 @@ keywords: <a href="keyword-index.html#SYSCALL">SYSCALL</a> <a href="keyword-inde
keywords: <a href="keyword-index.html#TRACE">TRACE</a> <a href="keyword-index.html#CALLGRAPH">CALLGRAPH</a> <br>
<p>Print a timed per-thread callgraph, complete with function parameters and return values. The first parameter names the function probe points to trace. The optional second parameter names the probe points for trigger functions, which acts to enable tracing for only those functions that occur while the current thread is nested within the trigger.</p></li>
</ul>
+<h3><a name="TRACEPOINT">TRACEPOINT</a></h3>
+<ul>
+<li><a href="network/dropwatch.stp">network/dropwatch.stp</a> - Watch Where Socket Buffers are Freed in the Kernel<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <a href="keyword-index.html#BUFFER">BUFFER</a> <a href="keyword-index.html#FREE">FREE</a> <br>
+<p>Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.</p></li>
+</ul>
<h3><a name="TRAFFIC">TRAFFIC</a></h3>
<ul>
<li><a href="network/nettop.stp">network/nettop.stp</a> - Periodic Listing of Processes Using Network Interfaces<br>
keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <a href="keyword-index.html#PER-PROCESS">PER-PROCESS</a> <br>
<p>Every five seconds the nettop.stp script prints out a list of processed (PID and command) with the number of packets sent/received and the amount of data sent/received by the process during that interval.</p></li>
+<li><a href="network/tcpdumplike.stp">network/tcpdumplike.stp</a> - Dump of Received TCP Packets<br>
+keywords: <a href="keyword-index.html#NETWORK">NETWORK</a> <a href="keyword-index.html#TRAFFIC">TRAFFIC</a> <br>
+<p>The tcpdumplike.stp prints out a line for each TCP packet received. Each line includes the source and destination IP addresses, the source and destination ports, and flags.</p></li>
</ul>
<h3><a name="USE">USE</a></h3>
<ul>
diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt
index 5f382e75..b53e776f 100644
--- a/testsuite/systemtap.examples/keyword-index.txt
+++ b/testsuite/systemtap.examples/keyword-index.txt
@@ -30,6 +30,15 @@ keywords: io scheduler backtrace
so is the total delay.
+= BUFFER =
+
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
= CALLGRAPH =
general/para-callgraph.stp - Callgraph tracing with arguments
@@ -70,6 +79,33 @@ keywords: disk
ten entries during that period.
+= FORMAT =
+
+general/ansi_colors.stp - Color Table for ansi_set_color2() and ansi_set_color3()
+keywords: format
+
+ The script prints a table showing the available color combinations
+ for the ansi_set_color2() and ans_set_color3() functions in the
+ ansi.stp tapset.
+
+
+general/ansi_colors2.stp - Show Attribues in Table for ansi_set_color3()
+keywords: format
+
+ The script prints a table showing the available attributes (bold,
+ underline, and inverse) with color combinations for the
+ ans_set_color3() function in the ansi.stp tapset.
+
+
+= FREE =
+
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
= FUNCTIONS =
profiling/functioncallcount.stp - Count Times Functions Called
@@ -125,6 +161,19 @@ keywords: io backtrace
list from most common to least common backtrace.
+io/ioblktime.stp - Average Time Block IO Requests Spend in Queue
+keywords: io
+
+ The ioblktime.stp script tracks the amount of time that each block IO
+ requests spend waiting for completion. The script computes the
+ average time waiting time for block IO per device and prints list
+ every 10 seconds. In some cases there can be too many oustanding
+ block IO operations and the script may exceed the default number of
+ MAXMAPENTRIES allowed. In this case the allowed number can be
+ increased with "-DMAXMAPENTRIES=10000" option on the stap command
+ line.
+
+
io/iostats.stp - List Executables Reading and Writing the Most Data
keywords: io profiling
@@ -220,6 +269,13 @@ keywords: memory
= NETWORK =
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
keywords: network traffic per-process
@@ -250,6 +306,14 @@ keywords: network tcp socket
originator of the request.
+network/tcpdumplike.stp - Dump of Received TCP Packets
+keywords: network traffic
+
+ The tcpdumplike.stp prints out a line for each TCP packet received.
+ Each line includes the source and destination IP addresses, the
+ source and destination ports, and flags.
+
+
= PER-PROCESS =
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
@@ -261,6 +325,18 @@ keywords: network traffic per-process
interval.
+= PROCESS =
+
+process/errsnoop.stp - tabulate system call errors
+keywords: process syscall
+
+ The script prints a periodic tabular report about failing system
+ calls, by process and by syscall failure. The first optional
+ argument specifies the reporting interval (in seconds, default 5);
+ the second optional argument gives a screen height (number of lines
+ in the report, default 20).
+
+
= PROFILING =
io/iostats.stp - List Executables Reading and Writing the Most Data
@@ -373,7 +449,7 @@ keywords: signals
that sent the signal.
-process/syscalls_by_pid.stp - System-Wide Count of Syscalls by PID
+process/sigmon.stp - Track a particular signal to a specific process
keywords: signals
The script watches for a particular signal sent to a specific
@@ -445,6 +521,16 @@ keywords: syscall read write time io
syscalls.
+process/errsnoop.stp - tabulate system call errors
+keywords: process syscall
+
+ The script prints a periodic tabular report about failing system
+ calls, by process and by syscall failure. The first optional
+ argument specifies the reporting interval (in seconds, default 5);
+ the second optional argument gives a screen height (number of lines
+ in the report, default 20).
+
+
process/futexes.stp - System-Wide Futex Contention
keywords: syscall locking futex
@@ -533,6 +619,15 @@ keywords: trace callgraph
the trigger.
+= TRACEPOINT =
+
+network/dropwatch.stp - Watch Where Socket Buffers are Freed in the Kernel
+keywords: network tracepoint buffer free
+
+ Every five seconds the dropwatch.stp script lists the number of
+ socket buffers freed at locations in the kernel.
+
+
= TRAFFIC =
network/nettop.stp - Periodic Listing of Processes Using Network Interfaces
@@ -544,6 +639,14 @@ keywords: network traffic per-process
interval.
+network/tcpdumplike.stp - Dump of Received TCP Packets
+keywords: network traffic
+
+ The tcpdumplike.stp prints out a line for each TCP packet received.
+ Each line includes the source and destination IP addresses, the
+ source and destination ports, and flags.
+
+
= USE =
general/graphs.stp - Graphing Disk and CPU Utilization
diff --git a/testsuite/systemtap.examples/network/dropwatch.meta b/testsuite/systemtap.examples/network/dropwatch.meta
new file mode 100644
index 00000000..176ba236
--- /dev/null
+++ b/testsuite/systemtap.examples/network/dropwatch.meta
@@ -0,0 +1,13 @@
+title: Watch Where Socket Buffers are Freed in the Kernel
+name: dropwatch.stp
+version: 1.0
+author: Neil Horman
+keywords: network tracepoint buffer free
+subsystem: network
+status: production
+exit: user-controlled
+output: timed
+scope: system-wide
+description: Every five seconds the dropwatch.stp script lists the number of socket buffers freed at locations in the kernel.
+test_check: stap -p4 dropwatch.stp
+test_installcheck: stap dropwatch.stp -c "sleep 1"
diff --git a/testsuite/systemtap.examples/network/dropwatch.stp b/testsuite/systemtap.examples/network/dropwatch.stp
new file mode 100755
index 00000000..79d50a4e
--- /dev/null
+++ b/testsuite/systemtap.examples/network/dropwatch.stp
@@ -0,0 +1,30 @@
+#! /usr/bin/env stap
+
+############################################################
+# Dropwatch.stp
+# Author: Neil Horman <nhorman@redhat.com>
+# An example script to mimic the behavior of the dropwatch utility
+# http://fedorahosted.org/dropwatch
+############################################################
+
+# Array to hold the list of drop points we find
+global locations
+
+# Note when we turn the monitor on and off
+probe begin { printf("Monitoring for dropped packets\n") }
+probe end { printf("Stopping dropped packet monitor\n") }
+
+# increment a drop counter for every location we drop at
+probe kernel.trace("kfree_skb") { locations[$location] <<< 1 }
+
+# Every 5 seconds report our drop locations
+probe timer.sec(5)
+{
+ printf("\n")
+ foreach (l in locations-) {
+ printf("%d packets dropped at location %p\n",
+ @count(locations[l]), l)
+ }
+ delete locations
+}
+
diff --git a/testsuite/systemtap.examples/network/nettop.stp b/testsuite/systemtap.examples/network/nettop.stp
index 15b4d62a..e96548f1 100755
--- a/testsuite/systemtap.examples/network/nettop.stp
+++ b/testsuite/systemtap.examples/network/nettop.stp
@@ -1,6 +1,7 @@
#! /usr/bin/env stap
global ifxmit, ifrecv
+global ifmerged
probe netdev.transmit
{
@@ -18,7 +19,13 @@ function print_activity()
"PID", "UID", "DEV", "XMIT_PK", "RECV_PK",
"XMIT_KB", "RECV_KB", "COMMAND")
- foreach ([pid, dev, exec, uid] in ifrecv-) {
+ foreach ([pid, dev, exec, uid] in ifrecv) {
+ ifmerged[pid, dev, exec, uid] += @count(ifrecv[pid,dev,exec,uid]);
+ }
+ foreach ([pid, dev, exec, uid] in ifxmit) {
+ ifmerged[pid, dev, exec, uid] += @count(ifxmit[pid,dev,exec,uid]);
+ }
+ foreach ([pid, dev, exec, uid] in ifmerged-) {
n_xmit = @count(ifxmit[pid, dev, exec, uid])
n_recv = @count(ifrecv[pid, dev, exec, uid])
printf("%5d %5d %-7s %7d %7d %7d %7d %-15s\n",
@@ -32,6 +39,7 @@ function print_activity()
delete ifxmit
delete ifrecv
+ delete ifmerged
}
probe timer.ms(5000), end, error
diff --git a/testsuite/systemtap.examples/network/tcp.stp b/testsuite/systemtap.examples/network/tcp.stp
new file mode 100755
index 00000000..01db9d2d
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcp.stp
@@ -0,0 +1,13 @@
+#! /usr/bin/env stap
+
+//A simple TCP tapset example
+
+probe begin {
+ printf("Expected IP 7.91.205.21 .... %s\n", ip_ntop(123456789))
+ printf("Expected IP 58.222.104.177 .... %s\n", ip_ntop(987654321))
+ printf("Expected IP 9.3.191.111 ... %s\n", ip_ntop(151240559))
+}
+
+probe tcp.recvmsg {
+ printf("received a message from %s on port %d from port %d\n", saddr, dport, sport)
+}
diff --git a/testsuite/systemtap.examples/network/tcpdumplike.meta b/testsuite/systemtap.examples/network/tcpdumplike.meta
new file mode 100644
index 00000000..8fb9fccb
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcpdumplike.meta
@@ -0,0 +1,12 @@
+title: Dump of Received TCP Packets
+name: tcpdumplike.stp
+version: 1.0
+author: anonymous
+keywords: network traffic
+subsystem: network
+status: production
+exit: user-controlled
+output: timed
+scope: system-wide
+description: The tcpdumplike.stp prints out a line for each TCP packet received. Each line includes the source and destination IP addresses, the source and destination ports, and flags.
+test_installcheck: stap tcpdumplike.stp -c "sleep 1"
diff --git a/testsuite/systemtap.examples/network/tcpdumplike.stp b/testsuite/systemtap.examples/network/tcpdumplike.stp
new file mode 100755
index 00000000..de3899d6
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcpdumplike.stp
@@ -0,0 +1,14 @@
+#! /usr/bin/env stap
+
+// A TCP dump like example
+
+probe begin, timer.s(1) {
+ printf("-----------------------------------------------------------------\n")
+ printf(" Source IP Dest IP SPort DPort U A P R S F \n")
+ printf("-----------------------------------------------------------------\n")
+}
+
+probe tcp.receive {
+ printf(" %15s %15s %5d %5d %d %d %d %d %d %d\n",
+ saddr, daddr, sport, dport, urg, ack, psh, rst, syn, fin)
+}
diff --git a/testsuite/systemtap.examples/process/errsnoop.meta b/testsuite/systemtap.examples/process/errsnoop.meta
new file mode 100644
index 00000000..34b8cb7c
--- /dev/null
+++ b/testsuite/systemtap.examples/process/errsnoop.meta
@@ -0,0 +1,7 @@
+title: tabulate system call errors
+name: errsnoop.stp
+keywords: process syscall
+subsystem: general
+description: The script prints a periodic tabular report about failing system calls, by process and by syscall failure. The first optional argument specifies the reporting interval (in seconds, default 5); the second optional argument gives a screen height (number of lines in the report, default 20).
+test_check: stap -p4 errsnoop.stp
+test_installcheck: stap errsnoop.stp 1 10 -c "sleep 3"
diff --git a/testsuite/systemtap.examples/process/errsnoop.stp b/testsuite/systemtap.examples/process/errsnoop.stp
new file mode 100755
index 00000000..a3f17b77
--- /dev/null
+++ b/testsuite/systemtap.examples/process/errsnoop.stp
@@ -0,0 +1,44 @@
+#!/bin/sh
+//usr/bin/env stap -DMAXMAPENTRIES=20480 $0 $@; exit $?
+# errsnoop.stp
+# Copyright (C) 2009 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# attack "stupid userspace" apps
+#
+
+global error, trace
+
+probe syscall.* {
+ # assume syscall don't nest
+ trace[tid()] = argstr
+}
+
+probe syscall.*.return {
+ errno = errno_p(returnval())
+ if (errno != 0) {
+ t = tid()
+ argstr = trace[t]
+ delete trace[t]
+
+ error[name, execname(), pid(), errno, argstr] <<< 1
+ }
+}
+
+probe timer.s(%( $# > 0 %? $1 %: 5 %)) {
+ ansi_clear_screen()
+ printf("%17s %15s %5s %4s %-12s %s\n",
+ "SYSCALL", "PROCESS", "PID", "HITS", "ERRSTR", "ARGSTR")
+ foreach([fn, comm, pid, errno, argstr] in error- limit %( $# > 1 %? $2 %: 20 %)) {
+ errstr = sprintf("%3d (%s)", errno, errno_str(errno))
+ printf("%17s %15s %5d %4d %-12s %s\n", fn, comm, pid,
+ @count(error[fn, comm, pid, errno, argstr]),
+# errstr, substr(argstr,0,22)) # within cols#80
+ errstr, argstr)
+
+ }
+ delete error
+}
diff --git a/testsuite/systemtap.examples/process/proc_snoop.stp b/testsuite/systemtap.examples/process/proc_snoop.stp
index 06425d45..9a3768c2 100755
--- a/testsuite/systemtap.examples/process/proc_snoop.stp
+++ b/testsuite/systemtap.examples/process/proc_snoop.stp
@@ -18,30 +18,30 @@ function id:string(task:long) {
task_execname(task))
}
-probe process.create {
+probe kprocess.create {
report(sprintf("create %s", id(task)))
}
-probe process.start {
+probe kprocess.start {
report("start")
}
-probe process.exec {
+probe kprocess.exec {
report(sprintf("exec %s", filename))
}
-probe process.exec_complete {
+probe kprocess.exec_complete {
if (success)
report("exec success")
else
report(sprintf("exec failed %d (%s)", errno, errno_str(errno)))
}
-probe process.exit {
+probe kprocess.exit {
report(sprintf("exit %d", code))
}
-probe process.release {
+probe kprocess.release {
report(sprintf("remove %s", id(task)))
}
diff --git a/testsuite/systemtap.examples/process/sigmon.meta b/testsuite/systemtap.examples/process/sigmon.meta
index 18834997..fe192248 100644
--- a/testsuite/systemtap.examples/process/sigmon.meta
+++ b/testsuite/systemtap.examples/process/sigmon.meta
@@ -1,5 +1,5 @@
-title: System-Wide Count of Syscalls by PID
-name: syscalls_by_pid.stp
+title: Track a particular signal to a specific process
+name: sigmon.stp
version: 1.0
author: IBM
keywords: signals
diff --git a/testsuite/systemtap.examples/profiling/latencytap.stp b/testsuite/systemtap.examples/profiling/latencytap.stp
index 28956129..d202ec81 100755
--- a/testsuite/systemtap.examples/profiling/latencytap.stp
+++ b/testsuite/systemtap.examples/profiling/latencytap.stp
@@ -23,7 +23,7 @@ function _get_sleep_time:long(rq_param:long, p_param:long)
function task_backtrace:string (task:long)
%{
_stp_stack_snprint_tsk(THIS->__retvalue, MAXSTRINGLEN,
- (struct task_struct *)THIS->task, 0, MAXTRACE);
+ (struct task_struct *)(unsigned long)THIS->task, 0, MAXTRACE);
%}
probe kernel.function("enqueue_task_fair") {
diff --git a/testsuite/systemtap.examples/profiling/timeout.stp b/testsuite/systemtap.examples/profiling/timeout.stp
index 48d6d21d..8054b364 100755
--- a/testsuite/systemtap.examples/profiling/timeout.stp
+++ b/testsuite/systemtap.examples/profiling/timeout.stp
@@ -90,8 +90,8 @@ probe syscall.exit {
}
probe timer.s(1) {
- printf("\033[2J\033[1;1H") /* clear screen */
- printf (" uid | poll select epoll itimer futex nanosle signal| process\n")
+ ansi_clear_screen()
+ printf (" pid | poll select epoll itimer futex nanosle signal| process\n")
foreach (p in timeout_count- limit 20) {
printf ("%5d |%7d %7d %7d %7d %7d %7d %7d| %-.38s\n", p,
poll_timeout[p], select_timeout[p],
diff --git a/testsuite/systemtap.pass1-4/buildok.exp b/testsuite/systemtap.pass1-4/buildok.exp
index 08d50fb5..12275c1d 100644
--- a/testsuite/systemtap.pass1-4/buildok.exp
+++ b/testsuite/systemtap.pass1-4/buildok.exp
@@ -6,12 +6,12 @@ foreach file [lsort [glob -nocomplain $srcdir/$self/*.stp]] {
# some tests are known to fail.
switch $test {
buildok/perfmon01.stp {setup_kfail 909 *-*-*}
- buildok/twentysix.stp {setup_kfail 4105 *-*-*}
buildok/twentyseven.stp {setup_kfail 4166 *-*-*}
buildok/sched_test.stp {setup_kfail 1155 *-*-*}
buildok/process_test.stp {setup_kfail 1155 *-*-*}
buildok/rpc-all-probes.stp {setup_kfail 4413 *-*-*}
buildok/nfs-all-probes.stp {setup_kfail 4413 *-*-*}
+ buildok/per-process-syscall.stp {if {![utrace_p]} { setup_kfail 9999 *-*-*} }
}
if {$rc == 0} { pass $test } else { fail $test }
}
diff --git a/testsuite/systemtap.printf/basic6.exp b/testsuite/systemtap.printf/basic6.exp
new file mode 100644
index 00000000..72bf8f57
--- /dev/null
+++ b/testsuite/systemtap.printf/basic6.exp
@@ -0,0 +1,3 @@
+set test "basic6"
+set ::result_string {Hello%World}
+stap_run2 $srcdir/$subdir/$test.stp
diff --git a/testsuite/systemtap.printf/basic6.stp b/testsuite/systemtap.printf/basic6.stp
new file mode 100644
index 00000000..69721188
--- /dev/null
+++ b/testsuite/systemtap.printf/basic6.stp
@@ -0,0 +1,5 @@
+probe begin
+{
+ printf("Hello%%World");
+ exit()
+}
diff --git a/testsuite/systemtap.printf/char1.exp b/testsuite/systemtap.printf/char1.exp
index 35aa479f..f9343c0e 100644
--- a/testsuite/systemtap.printf/char1.exp
+++ b/testsuite/systemtap.printf/char1.exp
@@ -1,3 +1,3 @@
set test "char1"
-set ::result_string {stap}
+set ::result_string {stapok}
stap_run2 $srcdir/$subdir/$test.stp
diff --git a/testsuite/systemtap.printf/char1.stp b/testsuite/systemtap.printf/char1.stp
index 207d1bc5..564c416b 100644
--- a/testsuite/systemtap.printf/char1.stp
+++ b/testsuite/systemtap.printf/char1.stp
@@ -3,6 +3,7 @@ probe begin
printf("%c", 115)
printf("%c", 116)
printf("%c%c", 97, 112)
+ printf("%c%c", stringat("ok", 0), stringat("ok", 1))
print("\n")
exit()
}
diff --git a/testsuite/systemtap.printf/end1.exp b/testsuite/systemtap.printf/end1.exp
index e4f164f5..ab1de590 100644
--- a/testsuite/systemtap.printf/end1.exp
+++ b/testsuite/systemtap.printf/end1.exp
@@ -4,7 +4,7 @@ set TEST_NAME "$subdir/$test"
if {![installtest_p]} { untested $TEST_NAME; return }
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested $TEST_NAME
return
diff --git a/testsuite/systemtap.printf/end1b.exp b/testsuite/systemtap.printf/end1b.exp
index 08cfa648..46cdc9c7 100644
--- a/testsuite/systemtap.printf/end1b.exp
+++ b/testsuite/systemtap.printf/end1b.exp
@@ -9,7 +9,7 @@ if (![file executable $stap_merge_path]) {
return
}
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested "$TEST_NAME : failed to create temporary file"
return
diff --git a/testsuite/systemtap.printf/memory1.stp b/testsuite/systemtap.printf/memory1.stp
index f9cbf60b..15aa565b 100644
--- a/testsuite/systemtap.printf/memory1.stp
+++ b/testsuite/systemtap.printf/memory1.stp
@@ -113,6 +113,20 @@ probe syscall.open {
success = 0;
}
+ expected_16_actual = sprintf (" %02x%02x%02x%02x%02x%02x",
+ stringat(filename, 0),
+ stringat(filename, 1),
+ stringat(filename, 2),
+ stringat(filename, 3),
+ stringat(filename, 4),
+ stringat(filename, 5));
+ testName = "%M dynamic width larger than dynamic precision";
+ result = sprintf ("%*.*M", 14, 6, $filename);
+ if (result != expected_16_actual) {
+ printf ("Test %s failed\n", testName);
+ success = 0;
+ }
+
if (success)
print ("Test passed\n");
diff --git a/testsuite/systemtap.printf/mixed_out.exp b/testsuite/systemtap.printf/mixed_out.exp
index d73a55a6..55320e80 100644
--- a/testsuite/systemtap.printf/mixed_out.exp
+++ b/testsuite/systemtap.printf/mixed_out.exp
@@ -4,7 +4,7 @@ set TEST_NAME "$subdir/$test"
if {![installtest_p]} { untested $TEST_NAME; return }
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested $TEST_NAME
return
diff --git a/testsuite/systemtap.printf/mixed_outb.exp b/testsuite/systemtap.printf/mixed_outb.exp
index 30c0c92f..c15520b1 100644
--- a/testsuite/systemtap.printf/mixed_outb.exp
+++ b/testsuite/systemtap.printf/mixed_outb.exp
@@ -9,7 +9,7 @@ if (![file executable $stap_merge_path]) {
return
}
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested "$TEST_NAME : failed to create temporary file"
return
diff --git a/testsuite/systemtap.printf/out1.exp b/testsuite/systemtap.printf/out1.exp
index d5728c0f..f973ae00 100644
--- a/testsuite/systemtap.printf/out1.exp
+++ b/testsuite/systemtap.printf/out1.exp
@@ -4,7 +4,7 @@ set TEST_NAME "$subdir/$test"
if {![installtest_p]} { untested $TEST_NAME; return }
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested $TEST_NAME
return
diff --git a/testsuite/systemtap.printf/out1b.exp b/testsuite/systemtap.printf/out1b.exp
index 2f702a2f..24efbf4c 100644
--- a/testsuite/systemtap.printf/out1b.exp
+++ b/testsuite/systemtap.printf/out1b.exp
@@ -9,7 +9,7 @@ if (![file executable $stap_merge_path]) {
return
}
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested "$TEST_NAME : failed to create temporary file"
return
diff --git a/testsuite/systemtap.printf/out2.exp b/testsuite/systemtap.printf/out2.exp
index dd96f394..8c66e73d 100644
--- a/testsuite/systemtap.printf/out2.exp
+++ b/testsuite/systemtap.printf/out2.exp
@@ -4,7 +4,7 @@ set TEST_NAME "$subdir/$test"
if {![installtest_p]} { untested $TEST_NAME; return }
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested $TEST_NAME
return
diff --git a/testsuite/systemtap.printf/out2b.exp b/testsuite/systemtap.printf/out2b.exp
index 0b56c940..70a98ea2 100644
--- a/testsuite/systemtap.printf/out2b.exp
+++ b/testsuite/systemtap.printf/out2b.exp
@@ -9,7 +9,7 @@ if (![file executable $stap_merge_path]) {
return
}
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested "$TEST_NAME : failed to create temporary file"
return
diff --git a/testsuite/systemtap.printf/out3.exp b/testsuite/systemtap.printf/out3.exp
index 96ca2bc5..63a67d8f 100644
--- a/testsuite/systemtap.printf/out3.exp
+++ b/testsuite/systemtap.printf/out3.exp
@@ -4,7 +4,7 @@ set TEST_NAME "$subdir/$test"
if {![installtest_p]} { untested $TEST_NAME; return }
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested $TEST_NAME
return
diff --git a/testsuite/systemtap.printf/out3b.exp b/testsuite/systemtap.printf/out3b.exp
index c42d03b7..d49625e9 100644
--- a/testsuite/systemtap.printf/out3b.exp
+++ b/testsuite/systemtap.printf/out3b.exp
@@ -9,7 +9,7 @@ if (![file executable $stap_merge_path]) {
return
}
-if {[catch {exec mktemp -t staptestXXXXX} tmpfile]} {
+if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} {
puts stderr "Failed to create temporary file: $tmpfile"
untested "$TEST_NAME : failed to create temporary file"
return
diff --git a/testsuite/systemtap.samples/ioblocktest.exp b/testsuite/systemtap.samples/ioblocktest.exp
deleted file mode 100644
index b5ab54c7..00000000
--- a/testsuite/systemtap.samples/ioblocktest.exp
+++ /dev/null
@@ -1,11 +0,0 @@
-# Test the functionality of the various ioblock probes.
-
-set test "ioblocktest"
-
-proc sleep_ten_secs {} {
- after 10000;
- return 0;
-}
-
-set output_string "ioblock: \\S+\t\\d+\t\[RW]\t\[01]\r\n"
-stap_run $srcdir/$subdir/$test.stp sleep_ten_secs $output_string
diff --git a/testsuite/systemtap.samples/ioblocktest.stp b/testsuite/systemtap.samples/ioblocktest.stp
deleted file mode 100644
index f8a1c568..00000000
--- a/testsuite/systemtap.samples/ioblocktest.stp
+++ /dev/null
@@ -1,12 +0,0 @@
-#! stap
-global teststr
-probe begin { println("systemtap starting probe") }
-
-probe ioblock.request, ioblock.end {
- teststr = sprintf("ioblock: %s\t%d\t%s\t%d\n", devname, sector,
- bio_rw_str(rw), bio_rw_num(rw))
-}
-probe end {
- println("systemtap ending probe")
- printf("%s", teststr)
-}
diff --git a/testsuite/systemtap.server/server.exp b/testsuite/systemtap.server/server.exp
index c2c60b97..d2dd0f16 100644
--- a/testsuite/systemtap.server/server.exp
+++ b/testsuite/systemtap.server/server.exp
@@ -16,7 +16,6 @@ foreach file [lsort [glob -nocomplain $srcdir/$self/*.stp]] {
# some tests are known to fail.
switch $test {
"buildok/perfmon01.stp with server" {setup_kfail 909 *-*-*}
- "buildok/twentysix.stp with server" {setup_kfail 4105 *-*-*}
"buildok/twentyseven.stp with server" {setup_kfail 4166 *-*-*}
"buildok/sched_test.stp with server" {setup_kfail 1155 *-*-*}
"buildok/process_test.stp with server" {setup_kfail 1155 *-*-*}
diff --git a/testsuite/systemtap.stress/whitelist.exp b/testsuite/systemtap.stress/whitelist.exp
index 4a31c124..70973978 100644
--- a/testsuite/systemtap.stress/whitelist.exp
+++ b/testsuite/systemtap.stress/whitelist.exp
@@ -96,6 +96,7 @@ set init_probes_all_script {
udp.*.return,
tcp.*,
tcp.*.return,
+ kprocess.*,
process.*,
nfs.fop.*,
nfs.aop.*,
diff --git a/testsuite/systemtap.syscall/access.c b/testsuite/systemtap.syscall/access.c
index 682424d4..45066015 100644
--- a/testsuite/systemtap.syscall/access.c
+++ b/testsuite/systemtap.syscall/access.c
@@ -13,28 +13,28 @@ int main()
fd1 = creat("foobar1",S_IREAD|S_IWRITE);
access("foobar1", F_OK);
- // access ("foobar1", F_OK)
- // faccessat (AT_FDCWD, "foobar1", F_OK) = 0
+ //staptest// access ("foobar1", F_OK)
+ //staptest// faccessat (AT_FDCWD, "foobar1", F_OK) = 0
access("foobar1", R_OK);
- // access ("foobar1", R_OK)
- // faccessat (AT_FDCWD, "foobar1", R_OK) = 0
+ //staptest// access ("foobar1", R_OK)
+ //staptest// faccessat (AT_FDCWD, "foobar1", R_OK) = 0
access("foobar1", W_OK);
- // access ("foobar1", W_OK)
- // faccessat (AT_FDCWD, "foobar1", W_OK) = 0
+ //staptest// access ("foobar1", W_OK)
+ //staptest// faccessat (AT_FDCWD, "foobar1", W_OK) = 0
access("foobar1", X_OK);
- // access ("foobar1", X_OK)
- // faccessat (AT_FDCWD, "foobar1", X_OK) = -NNNN (EACCES)
+ //staptest// access ("foobar1", X_OK)
+ //staptest// faccessat (AT_FDCWD, "foobar1", X_OK) = -NNNN (EACCES)
access("foobar1", R_OK|W_OK);
- // access ("foobar1", W_OK |R_OK)
- // faccessat (AT_FDCWD, "foobar1", W_OK |R_OK) = 0
+ //staptest// access ("foobar1", W_OK |R_OK)
+ //staptest// faccessat (AT_FDCWD, "foobar1", W_OK |R_OK) = 0
access("foobar1", R_OK|W_OK|X_OK);
- // access ("foobar1", X_OK |W_OK |R_OK)
- // faccessat (AT_FDCWD, "foobar1", X_OK |W_OK |R_OK) = -NNNN (EACCES)
+ //staptest// access ("foobar1", X_OK |W_OK |R_OK)
+ //staptest// faccessat (AT_FDCWD, "foobar1", X_OK |W_OK |R_OK) = -NNNN (EACCES)
return 0;
}
diff --git a/testsuite/systemtap.syscall/acct.c b/testsuite/systemtap.syscall/acct.c
index 927e40c9..47f87961 100644
--- a/testsuite/systemtap.syscall/acct.c
+++ b/testsuite/systemtap.syscall/acct.c
@@ -4,7 +4,7 @@
int main()
{
acct("foobar");
- // acct ("foobar") = -NNNN
+ //staptest// acct ("foobar") = -NNNN
return 0;
}
diff --git a/testsuite/systemtap.syscall/alarm.c b/testsuite/systemtap.syscall/alarm.c
index 7cb17164..6f1bedce 100755..100644
--- a/testsuite/systemtap.syscall/alarm.c
+++ b/testsuite/systemtap.syscall/alarm.c
@@ -20,36 +20,36 @@ int main()
alarm(1);
#ifdef __ia64__
- // setitimer (ITIMER_REAL, \[0.000000,1.000000\], XXXX) = 0
+ //staptest// setitimer (ITIMER_REAL, \[0.000000,1.000000\], XXXX) = 0
#else
- // alarm (1) = 0
+ //staptest// alarm (1) = 0
#endif
pause();
#ifdef __ia64__
- // rt_sigsuspend () =
+ //staptest// rt_sigsuspend () =
#else
- // pause () =
+ //staptest// pause () =
#endif
alarm(0);
#ifdef __ia64__
- // setitimer (ITIMER_REAL, \[0.000000,0.000000\], XXXX) = 0
+ //staptest// setitimer (ITIMER_REAL, \[0.000000,0.000000\], XXXX) = 0
#else
- // alarm (0) = 0
+ //staptest// alarm (0) = 0
#endif
sleep(1);
- // nanosleep (\[1.000000000\], XXXX) = 0
+ //staptest// nanosleep (\[1.000000000\], XXXX) = 0
usleep(1234);
- // nanosleep (\[0.001234000\], 0x[0]+) = 0
+ //staptest// nanosleep (\[0.001234000\], 0x[0]+) = 0
nanosleep(&t, &rem);
- // nanosleep (\[0.000000789\], XXXX) = 0
+ //staptest// nanosleep (\[0.000000789\], XXXX) = 0
nanosleep(&t, NULL);
- // nanosleep (\[0.000000789\], 0x[0]+) = 0
+ //staptest// nanosleep (\[0.000000789\], 0x[0]+) = 0
return 0;
}
diff --git a/testsuite/systemtap.syscall/chmod.c b/testsuite/systemtap.syscall/chmod.c
index 9b0c58e1..724b86c4 100644
--- a/testsuite/systemtap.syscall/chmod.c
+++ b/testsuite/systemtap.syscall/chmod.c
@@ -11,70 +11,70 @@ int main()
int fd;
fd = open("foobar",O_WRONLY|O_CREAT, 0666);
- // open ("foobar", O_WRONLY|O_CREAT, 0666) = NNNN
+ //staptest// open ("foobar", O_WRONLY|O_CREAT, 0666) = NNNN
chmod("foobar", 0644);
- // chmod ("foobar", 0644)
- // fchmodat (AT_FDCWD, "foobar", 0644) = 0
+ //staptest// chmod ("foobar", 0644)
+ //staptest// fchmodat (AT_FDCWD, "foobar", 0644) = 0
fchmod(fd, 0444);
- // fchmod (NNNN, 0444) = 0
+ //staptest// fchmod (NNNN, 0444) = 0
chown("foobar", 5000, -1);
#ifdef __i386__
- // chown ("foobar", 5000, -1) =
+ //staptest// chown ("foobar", 5000, -1) =
#else
- // chown ("foobar", 5000, NNNN) =
+ //staptest// chown ("foobar", 5000, NNNN) =
#endif
chown("foobar", -1, 5001);
#ifdef __i386__
- // chown ("foobar", -1, 5001) =
+ //staptest// chown ("foobar", -1, 5001) =
#else
- // chown ("foobar", NNNN, 5001) =
+ //staptest// chown ("foobar", NNNN, 5001) =
#endif
fchown(fd, 5002, -1);
#ifdef __i386__
- // fchown (NNNN, 5002, -1) =
+ //staptest// fchown (NNNN, 5002, -1) =
#else
- // fchown (NNNN, 5002, NNNN) =
+ //staptest// fchown (NNNN, 5002, NNNN) =
#endif
fchown(fd, -1, 5003);
#ifdef __i386__
- // fchown (NNNN, -1, 5003) =
+ //staptest// fchown (NNNN, -1, 5003) =
#else
- // fchown (NNNN, NNNN, 5003) =
+ //staptest// fchown (NNNN, NNNN, 5003) =
#endif
lchown("foobar", 5004, -1);
#ifdef __i386__
- // lchown ("foobar", 5004, -1) =
+ //staptest// lchown ("foobar", 5004, -1) =
#else
- // lchown ("foobar", 5004, NNNN) =
+ //staptest// lchown ("foobar", 5004, NNNN) =
#endif
lchown("foobar", -1, 5005);
#ifdef __i386__
- // lchown ("foobar", -1, 5005) =
+ //staptest// lchown ("foobar", -1, 5005) =
#else
- // lchown ("foobar", NNNN, 5005) =
+ //staptest// lchown ("foobar", NNNN, 5005) =
#endif
#ifdef __i386__
syscall(SYS_chown, "foobar", 5000, -1);
- // chown16 ("foobar", 5000, -1) =
+ //staptest// chown16 ("foobar", 5000, -1) =
syscall(SYS_chown, "foobar", -1, 5001);
- // chown16 ("foobar", -1, 5001) =
+ //staptest// chown16 ("foobar", -1, 5001) =
syscall(SYS_fchown, fd, 5002, -1);
- // fchown16 (NNNN, 5002, -1) =
+ //staptest// fchown16 (NNNN, 5002, -1) =
syscall(SYS_fchown, fd, -1, 5003);
- // fchown16 (NNNN, -1, 5003) =
+ //staptest// fchown16 (NNNN, -1, 5003) =
syscall(SYS_lchown, "foobar", 5004, -1);
- // lchown16 ("foobar", 5004, -1) =
+ //staptest// lchown16 ("foobar", 5004, -1) =
syscall(SYS_lchown, "foobar", -1, 5005);
- // lchown16 ("foobar", -1, 5005) =
+ //staptest// lchown16 ("foobar", -1, 5005) =
#endif
close(fd);
diff --git a/testsuite/systemtap.syscall/clock.c b/testsuite/systemtap.syscall/clock.c
index bc84871d..995d59df 100644
--- a/testsuite/systemtap.syscall/clock.c
+++ b/testsuite/systemtap.syscall/clock.c
@@ -14,64 +14,64 @@ int main()
#ifdef SYS_time
syscall(SYS_time, &tt);
- // time (XXXX) = NNNN
+ //staptest// time (XXXX) = NNNN
syscall(SYS_time, NULL);
- // time (0x[0]+) = NNNN
+ //staptest// time (0x[0]+) = NNNN
#endif
t = syscall(SYS_gettimeofday, &tv, NULL);
- // gettimeofday (XXXX, 0x[0]+) = 0
+ //staptest// gettimeofday (XXXX, 0x[0]+) = 0
settimeofday(&tv, NULL);
- // settimeofday (\[NNNN.NNNN\], NULL) =
+ //staptest// settimeofday (\[NNNN.NNNN\], NULL) =
syscall(SYS_clock_gettime, CLOCK_REALTIME, &ts);
- // clock_gettime (CLOCK_REALTIME, XXXX) = 0
+ //staptest// clock_gettime (CLOCK_REALTIME, XXXX) = 0
syscall(SYS_clock_settime, CLOCK_REALTIME, &ts);
- // clock_settime (CLOCK_REALTIME, \[NNNN.NNNN\]) =
+ //staptest// clock_settime (CLOCK_REALTIME, \[NNNN.NNNN\]) =
syscall(SYS_clock_getres, CLOCK_REALTIME, &ts);
- // clock_getres (CLOCK_REALTIME, XXXX) = 0
+ //staptest// clock_getres (CLOCK_REALTIME, XXXX) = 0
syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts);
- // clock_gettime (CLOCK_MONOTONIC, XXXX) = 0
+ //staptest// clock_gettime (CLOCK_MONOTONIC, XXXX) = 0
syscall(SYS_clock_settime, CLOCK_MONOTONIC, &ts);
- // clock_settime (CLOCK_MONOTONIC, \[NNNN.NNNN\]) =
+ //staptest// clock_settime (CLOCK_MONOTONIC, \[NNNN.NNNN\]) =
syscall(SYS_clock_getres, CLOCK_MONOTONIC, &ts);
- // clock_getres (CLOCK_MONOTONIC, XXXX) = 0
+ //staptest// clock_getres (CLOCK_MONOTONIC, XXXX) = 0
syscall(SYS_clock_gettime, CLOCK_PROCESS_CPUTIME_ID, &ts);
- // clock_gettime (CLOCK_PROCESS_CPUTIME_ID, XXXX) =
+ //staptest// clock_gettime (CLOCK_PROCESS_CPUTIME_ID, XXXX) =
syscall(SYS_clock_settime, CLOCK_PROCESS_CPUTIME_ID, &ts);
- // clock_settime (CLOCK_PROCESS_CPUTIME_ID, \[NNNN.NNNN\]) =
+ //staptest// clock_settime (CLOCK_PROCESS_CPUTIME_ID, \[NNNN.NNNN\]) =
syscall(SYS_clock_getres, CLOCK_PROCESS_CPUTIME_ID, &ts);
- // clock_getres (CLOCK_PROCESS_CPUTIME_ID, XXXX) =
+ //staptest// clock_getres (CLOCK_PROCESS_CPUTIME_ID, XXXX) =
syscall(SYS_clock_gettime, CLOCK_THREAD_CPUTIME_ID, &ts);
- // clock_gettime (CLOCK_THREAD_CPUTIME_ID, XXXX) =
+ //staptest// clock_gettime (CLOCK_THREAD_CPUTIME_ID, XXXX) =
syscall(SYS_clock_settime, CLOCK_THREAD_CPUTIME_ID, &ts);
- // clock_settime (CLOCK_THREAD_CPUTIME_ID, \[NNNN.NNNN\]) =
+ //staptest// clock_settime (CLOCK_THREAD_CPUTIME_ID, \[NNNN.NNNN\]) =
syscall(SYS_clock_getres, CLOCK_THREAD_CPUTIME_ID, &ts);
- // clock_getres (CLOCK_THREAD_CPUTIME_ID, XXXX) =
+ //staptest// clock_getres (CLOCK_THREAD_CPUTIME_ID, XXXX) =
syscall(SYS_clock_gettime, CLOCK_REALTIME, &ts);
- // clock_gettime (CLOCK_REALTIME, XXXX) = 0
+ //staptest// clock_gettime (CLOCK_REALTIME, XXXX) = 0
ts.tv_sec++;
syscall(SYS_clock_nanosleep, CLOCK_REALTIME, TIMER_ABSTIME, &ts);
- // clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, \[NNNN.NNNN\], XXXX) = 0
+ //staptest// clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, \[NNNN.NNNN\], XXXX) = 0
ts.tv_sec = 0; ts.tv_nsec = 10000;
syscall(SYS_clock_nanosleep, CLOCK_REALTIME, 0x0, &ts);
- // clock_nanosleep (CLOCK_REALTIME, 0x0, \[NNNN.NNNN\], XXXX) = 0
+ //staptest// clock_nanosleep (CLOCK_REALTIME, 0x0, \[NNNN.NNNN\], XXXX) = 0
return 0;
}
diff --git a/testsuite/systemtap.syscall/dir.c b/testsuite/systemtap.syscall/dir.c
index 5de4ce35..3eda8175 100644
--- a/testsuite/systemtap.syscall/dir.c
+++ b/testsuite/systemtap.syscall/dir.c
@@ -11,43 +11,43 @@ int main()
int fd;
mkdir("foobar", 0765);
- // mkdir ("foobar", 0765) =
+ //staptest// mkdir ("foobar", 0765) =
chdir("foobar");
- // chdir ("foobar") = 0
+ //staptest// chdir ("foobar") = 0
chdir("..");
- // chdir ("..") = 0
+ //staptest// chdir ("..") = 0
fd = open("foobar", O_RDONLY);
- // open ("foobar", O_RDONLY) = NNNN
+ //staptest// open ("foobar", O_RDONLY) = NNNN
fchdir(fd);
- // fchdir (NNNN) = 0
+ //staptest// fchdir (NNNN) = 0
chdir("..");
- // chdir ("..") = 0
+ //staptest// chdir ("..") = 0
close(fd);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
rmdir("foobar");
- // rmdir ("foobar") = 0
+ //staptest// rmdir ("foobar") = 0
fd = open(".", O_RDONLY);
- // open (".", O_RDONLY) = NNNN
+ //staptest// open (".", O_RDONLY) = NNNN
#ifdef SYS_mkdirat
mkdirat(fd, "xyzzy", 0765);
- // mkdirat (NNNN, "xyzzy", 0765) = 0
+ //staptest// mkdirat (NNNN, "xyzzy", 0765) = 0
#endif
close(fd);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
rmdir("xyzzy");
- // rmdir ("xyzzy") =
+ //staptest// rmdir ("xyzzy") =
return 0;
}
diff --git a/testsuite/systemtap.syscall/forkwait.c b/testsuite/systemtap.syscall/forkwait.c
index bf7516f6..b7df4923 100644
--- a/testsuite/systemtap.syscall/forkwait.c
+++ b/testsuite/systemtap.syscall/forkwait.c
@@ -12,14 +12,14 @@ int main ()
int status;
child = fork();
- // fork () = NNNN
+ //staptest// fork () = NNNN
if (!child) {
int i = 0xfffff;
while (i > 0) i--;
exit(0);
}
wait4(child, &status, WNOHANG, NULL);
- // wait4 (NNNN, XXXX, WNOHANG, XXXX) = NNNN
+ //staptest// wait4 (NNNN, XXXX, WNOHANG, XXXX) = NNNN
return 0;
}
diff --git a/testsuite/systemtap.syscall/futimes.c b/testsuite/systemtap.syscall/futimes.c
index eca1efc7..4b812513 100644
--- a/testsuite/systemtap.syscall/futimes.c
+++ b/testsuite/systemtap.syscall/futimes.c
@@ -31,20 +31,20 @@ int main()
times.actime = 1000000000;
times.modtime = 2000000000;
syscall(__NR_utime, "foobar", &times );
- // utime ("foobar", \[Sun Sep 9 01:46:40 2001, Wed May 18 03:33:20 2033])
+ //staptest// utime ("foobar", \[Sun Sep 9 01:46:40 2001, Wed May 18 03:33:20 2033])
#endif /* __NR_utimes */
#ifdef __NR_utimes
syscall(__NR_utimes, "foobar", tv);
- // utimes ("foobar", \[1000000000.001234\]\[2000000000.005678\])
+ //staptest// utimes ("foobar", \[1000000000.001234\]\[2000000000.005678\])
#endif /* __NR_utimes */
#ifdef __NR_futimesat
syscall(__NR_futimesat, 7, "foobar", tv);
- // futimesat (7, "foobar", \[1000000000.001234\]\[2000000000.005678\])
+ //staptest// futimesat (7, "foobar", \[1000000000.001234\]\[2000000000.005678\])
syscall(__NR_futimesat, AT_FDCWD, "foobar", tv);
- // futimesat (AT_FDCWD, "foobar", \[1000000000.001234\]\[2000000000.005678\])
+ //staptest// futimesat (AT_FDCWD, "foobar", \[1000000000.001234\]\[2000000000.005678\])
#endif /* __NR_futimesat */
#ifdef __NR_utimensat
@@ -53,17 +53,17 @@ int main()
ts[1].tv_sec = 2000000000;
ts[1].tv_nsec = 56780000;
syscall(__NR_utimensat, AT_FDCWD, "foobar", ts, 0);
- // utimensat (AT_FDCWD, "foobar", \[1000000000.123456789\]\[2000000000.056780000\], 0x0)
+ //staptest// utimensat (AT_FDCWD, "foobar", \[1000000000.123456789\]\[2000000000.056780000\], 0x0)
ts[0].tv_sec = 0;
ts[0].tv_nsec = UTIME_NOW;
ts[1].tv_sec = 0;
ts[1].tv_nsec = UTIME_OMIT;
syscall(__NR_utimensat, AT_FDCWD, "foobar", ts, AT_SYMLINK_NOFOLLOW);
- // utimensat (AT_FDCWD, "foobar", \[UTIME_NOW\]\[UTIME_OMIT\], AT_SYMLINK_NOFOLLOW)
+ //staptest// utimensat (AT_FDCWD, "foobar", \[UTIME_NOW\]\[UTIME_OMIT\], AT_SYMLINK_NOFOLLOW)
syscall(__NR_utimensat, 22, "foobar", ts, 0x42);
- // utimensat (22, "foobar", \[UTIME_NOW\]\[UTIME_OMIT\], 0x42)
+ //staptest// utimensat (22, "foobar", \[UTIME_NOW\]\[UTIME_OMIT\], 0x42)
#endif
diff --git a/testsuite/systemtap.syscall/itimer.c b/testsuite/systemtap.syscall/itimer.c
index 5cebc902..ec2c8f5f 100644
--- a/testsuite/systemtap.syscall/itimer.c
+++ b/testsuite/systemtap.syscall/itimer.c
@@ -28,27 +28,27 @@ int main()
itv.it_value.tv_sec = 1;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, &old_itv);
- // setitimer (ITIMER_REAL, \[0.500000,1.000000\], XXXX) = 0
+ //staptest// setitimer (ITIMER_REAL, \[0.500000,1.000000\], XXXX) = 0
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, NULL);
- // setitimer (ITIMER_REAL, \[0.500000,0.000000\], 0x[0]+) = 0
+ //staptest// setitimer (ITIMER_REAL, \[0.500000,0.000000\], 0x[0]+) = 0
setitimer(ITIMER_VIRTUAL, &itv, NULL);
- // setitimer (ITIMER_VIRTUAL, \[0.500000,0.000000\], 0x[0]+) = 0
+ //staptest// setitimer (ITIMER_VIRTUAL, \[0.500000,0.000000\], 0x[0]+) = 0
setitimer(ITIMER_PROF, &itv, NULL);
- // setitimer (ITIMER_PROF, \[0.500000,0.000000\], 0x[0]+) = 0
+ //staptest// setitimer (ITIMER_PROF, \[0.500000,0.000000\], 0x[0]+) = 0
getitimer(ITIMER_REAL, &itv);
- // getitimer (ITIMER_REAL, XXXX) = 0
+ //staptest// getitimer (ITIMER_REAL, XXXX) = 0
getitimer(ITIMER_VIRTUAL, &itv);
- // getitimer (ITIMER_VIRTUAL, XXXX) = 0
+ //staptest// getitimer (ITIMER_VIRTUAL, XXXX) = 0
getitimer(ITIMER_PROF, &itv);
- // getitimer (ITIMER_PROF, XXXX) = 0
+ //staptest// getitimer (ITIMER_PROF, XXXX) = 0
return 0;
}
diff --git a/testsuite/systemtap.syscall/link.c b/testsuite/systemtap.syscall/link.c
index 81280bf2..72f422cd 100644
--- a/testsuite/systemtap.syscall/link.c
+++ b/testsuite/systemtap.syscall/link.c
@@ -13,24 +13,24 @@ int main()
close(fd);
link("foobar", "foobar2");
- // link ("foobar", "foobar2")
- // linkat (AT_FDCWD, "foobar", AT_FDCWD, "foobar2", 0x0) = 0
+ //staptest// link ("foobar", "foobar2")
+ //staptest// linkat (AT_FDCWD, "foobar", AT_FDCWD, "foobar2", 0x0) = 0
link("foobar", "foobar");
- // link ("foobar", "foobar")
- // linkat (AT_FDCWD, "foobar", AT_FDCWD, "foobar", 0x0) = -NNNN (EEXIST)
+ //staptest// link ("foobar", "foobar")
+ //staptest// linkat (AT_FDCWD, "foobar", AT_FDCWD, "foobar", 0x0) = -NNNN (EEXIST)
link("nonexist", "foo");
- // link ("nonexist", "foo")
- // linkat (AT_FDCWD, "nonexist", AT_FDCWD, "foo", 0x0) = -NNNN (ENOENT)
+ //staptest// link ("nonexist", "foo")
+ //staptest// linkat (AT_FDCWD, "nonexist", AT_FDCWD, "foo", 0x0) = -NNNN (ENOENT)
symlink("foobar", "Sfoobar");
- // symlink ("foobar", "Sfoobar")
- // symlinkat ("foobar", AT_FDCWD, "Sfoobar") = 0
+ //staptest// symlink ("foobar", "Sfoobar")
+ //staptest// symlinkat ("foobar", AT_FDCWD, "Sfoobar") = 0
readlink("Sfoobar", buf, sizeof(buf));
- // readlink ("Sfoobar", XXXX, 128)
- // readlinkat (AT_FDCWD, "Sfoobar", XXXX, 128)
+ //staptest// readlink ("Sfoobar", XXXX, 128)
+ //staptest// readlinkat (AT_FDCWD, "Sfoobar", XXXX, 128)
return 0;
}
diff --git a/testsuite/systemtap.syscall/mmap.c b/testsuite/systemtap.syscall/mmap.c
index a3a0dc34..13145fb2 100644
--- a/testsuite/systemtap.syscall/mmap.c
+++ b/testsuite/systemtap.syscall/mmap.c
@@ -13,41 +13,41 @@ int main()
/* create a file with something in it */
fd = open("foobar",O_WRONLY|O_CREAT|O_TRUNC, 0600);
- // open ("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
+ //staptest// open ("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
lseek(fd, 1024, SEEK_SET);
write(fd, "abcdef", 6);
close(fd);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
fd = open("foobar", O_RDONLY);
- // open ("foobar", O_RDONLY) = NNNN
+ //staptest// open ("foobar", O_RDONLY) = NNNN
/* stat for file size */
ret = fstat(fd, &fs);
- // fstat (NNNN, XXXX) = 0
+ //staptest// fstat (NNNN, XXXX) = 0
r = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, fd, 0);
- // mmap[2]* (XXXX, 1030, PROT_READ, MAP_SHARED, NNNN, XXXX) = XXXX
+ //staptest// mmap[2]* (XXXX, 1030, PROT_READ, MAP_SHARED, NNNN, XXXX) = XXXX
close(fd);
mlock(r, fs.st_size);
- // mlock (XXXX, 1030) = 0
+ //staptest// mlock (XXXX, 1030) = 0
msync(r, fs.st_size, MS_SYNC);
- // msync (XXXX, 1030, MS_SYNC) = 0
+ //staptest// msync (XXXX, 1030, MS_SYNC) = 0
munlock(r, fs.st_size);
- // munlock (XXXX, 1030) = 0
+ //staptest// munlock (XXXX, 1030) = 0
mlockall(MCL_CURRENT);
- // mlockall (MCL_CURRENT) =
+ //staptest// mlockall (MCL_CURRENT) =
munlockall();
- // munlockall () = 0
+ //staptest// munlockall () = 0
munmap(r, fs.st_size);
- // munmap (XXXX, 1030) = 0
+ //staptest// munmap (XXXX, 1030) = 0
return 0;
}
diff --git a/testsuite/systemtap.syscall/mount.c b/testsuite/systemtap.syscall/mount.c
index 57ae030f..a59582dd 100644
--- a/testsuite/systemtap.syscall/mount.c
+++ b/testsuite/systemtap.syscall/mount.c
@@ -17,19 +17,19 @@
int main()
{
mount ("mount_source", "mount_target", "ext2", MS_BIND|MS_NOATIME|MS_NODIRATIME|MS_NOSUID, "some arguments");
- // mount ("mount_source", "mount_target", "ext2", MS_BIND|MS_NOATIME|MS_NODIRATIME|MS_NOSUID, "some arguments") = -NNNN (ENOENT)
+ //staptest// mount ("mount_source", "mount_target", "ext2", MS_BIND|MS_NOATIME|MS_NODIRATIME|MS_NOSUID, "some arguments") = -NNNN (ENOENT)
umount("umount_target");
- // umount ("umount_target", 0) = -NNNN (ENOENT)
+ //staptest// umount ("umount_target", 0) = -NNNN (ENOENT)
umount2("umount2_target", MNT_FORCE);
- // umount ("umount2_target", MNT_FORCE) = -NNNN (ENOENT)
+ //staptest// umount ("umount2_target", MNT_FORCE) = -NNNN (ENOENT)
umount2("umount2_target", MNT_DETACH);
- // umount ("umount2_target", MNT_DETACH) = -NNNN (ENOENT)
+ //staptest// umount ("umount2_target", MNT_DETACH) = -NNNN (ENOENT)
umount2("umount2_target", MNT_EXPIRE);
- // umount ("umount2_target", MNT_EXPIRE) = -NNNN (ENOENT)
+ //staptest// umount ("umount2_target", MNT_EXPIRE) = -NNNN (ENOENT)
return 0;
}
diff --git a/testsuite/systemtap.syscall/net1.c b/testsuite/systemtap.syscall/net1.c
index 219a3860..f8079ffd 100644
--- a/testsuite/systemtap.syscall/net1.c
+++ b/testsuite/systemtap.syscall/net1.c
@@ -13,12 +13,12 @@ int main()
listenfd = socket(AF_INET, SOCK_STREAM, 0);
- // socket (PF_INET, SOCK_STREAM, 0) = NNNN
+ //staptest// socket (PF_INET, SOCK_STREAM, 0) = NNNN
flags = fcntl(listenfd, F_GETFL, 0);
- // fcntl[64]* (NNNN, F_GETFL, 0x[0]+) = NNNN
+ //staptest// fcntl[64]* (NNNN, F_GETFL, 0x[0]+) = NNNN
fcntl(listenfd, F_SETFL, flags | O_NONBLOCK);
- // fcntl[64]* (NNNN, F_SETFL, XXXX) = 0
+ //staptest// fcntl[64]* (NNNN, F_SETFL, XXXX) = 0
bzero(&sa, sizeof(sa));
sa.sin_family=AF_INET;
@@ -26,13 +26,13 @@ int main()
sa.sin_port = htons(8765);
bind(listenfd, (struct sockaddr *)&sa, sizeof(sa));
- // bind (NNNN, {AF_INET, 0.0.0.0, 8765}, 16) = 0
+ //staptest// bind (NNNN, {AF_INET, 0.0.0.0, 8765}, 16) = 0
listen (listenfd, 7);
- // listen (NNNN, 7) = 0
+ //staptest// listen (NNNN, 7) = 0
cfd = accept(listenfd, (struct sockaddr *)NULL, NULL);
- // accept (NNNN, 0x[0]+, 0x[0]+) = -NNNN (EAGAIN)
+ //staptest// accept (NNNN, 0x[0]+, 0x[0]+) = -NNNN (EAGAIN)
close(cfd);
close(listenfd);
diff --git a/testsuite/systemtap.syscall/openclose.c b/testsuite/systemtap.syscall/openclose.c
index a35f1a59..cb003a9e 100644
--- a/testsuite/systemtap.syscall/openclose.c
+++ b/testsuite/systemtap.syscall/openclose.c
@@ -13,46 +13,46 @@ int main()
int fd1, fd2;
fd2 = creat("foobar1",S_IREAD|S_IWRITE);
- // open ("foobar1", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
+ //staptest// open ("foobar1", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
fd1 = open("foobar2",O_WRONLY|O_CREAT, S_IRWXU);
- // open ("foobar2", O_WRONLY|O_CREAT, 0700) = NNNN
+ //staptest// open ("foobar2", O_WRONLY|O_CREAT, 0700) = NNNN
close(fd1);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
fd1 = open("foobar2",O_RDONLY);
- // open ("foobar2", O_RDONLY) = NNNN
+ //staptest// open ("foobar2", O_RDONLY) = NNNN
close(fd1);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
fd1 = open("foobar2",O_RDWR);
- // open ("foobar2", O_RDWR) = NNNN
+ //staptest// open ("foobar2", O_RDWR) = NNNN
close(fd1);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
fd1 = open("foobar2",O_APPEND|O_WRONLY);
- // open ("foobar2", O_WRONLY|O_APPEND) = NNNN
+ //staptest// open ("foobar2", O_WRONLY|O_APPEND) = NNNN
close(fd1);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
fd1 = open("foobar2",O_DIRECT|O_RDWR);
- // open ("foobar2", O_RDWR|O_DIRECT) = NNNN
+ //staptest// open ("foobar2", O_RDWR|O_DIRECT) = NNNN
close(fd1);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
fd1 = open("foobar2",O_NOATIME|O_SYNC|O_RDWR);
- // open ("foobar2", O_RDWR|O_NOATIME|O_SYNC) = NNNN
+ //staptest// open ("foobar2", O_RDWR|O_NOATIME|O_SYNC) = NNNN
close(fd1);
- // close (NNNN) = 0
+ //staptest// close (NNNN) = 0
/* Now test some bad opens */
fd1 = open("/",O_WRONLY);
- // open ("/", O_WRONLY) = -NNNN (EISDIR)
+ //staptest// open ("/", O_WRONLY) = -NNNN (EISDIR)
close (fd1);
- // close (NNNN) = -NNNN (EBADF)
+ //staptest// close (NNNN) = -NNNN (EBADF)
fd1 = open("foobar2",O_WRONLY|O_CREAT|O_EXCL, S_IRWXU);
- // open ("foobar2", O_WRONLY|O_CREAT|O_EXCL, 0700) = -NNNN (EEXIST)
+ //staptest// open ("foobar2", O_WRONLY|O_CREAT|O_EXCL, 0700) = -NNNN (EEXIST)
return 0;
}
diff --git a/testsuite/systemtap.syscall/poll.c b/testsuite/systemtap.syscall/poll.c
index 591c1f74..3caa2b14 100644
--- a/testsuite/systemtap.syscall/poll.c
+++ b/testsuite/systemtap.syscall/poll.c
@@ -17,21 +17,21 @@ int main()
sigaddset(&sigs,SIGUSR2);
fd = epoll_create(32);
- // epoll_create (32)
+ //staptest// epoll_create (32)
epoll_ctl(fd, EPOLL_CTL_ADD, 13, &ev);
- // epoll_ctl (NNNN, EPOLL_CTL_ADD, 13, XXXX)
+ //staptest// epoll_ctl (NNNN, EPOLL_CTL_ADD, 13, XXXX)
epoll_wait(fd, &ev, 17,0);
- // epoll_wait (NNNN, XXXX, 17, 0)
+ //staptest// epoll_wait (NNNN, XXXX, 17, 0)
close(fd);
poll(&pfd, 1, 0);
- // poll (XXXX, 1, 0)
+ //staptest// poll (XXXX, 1, 0)
#ifdef SYS_ppoll
ppoll(&pfd, 1, &tim, &sigs);
- // ppoll (XXXX, 1, \[0.200000000\], XXXX, 8)
+ //staptest// ppoll (XXXX, 1, \[0.200000000\], XXXX, 8)
#endif
return 0;
diff --git a/testsuite/systemtap.syscall/readwrite.c b/testsuite/systemtap.syscall/readwrite.c
index aacd68f2..bd0914cc 100644
--- a/testsuite/systemtap.syscall/readwrite.c
+++ b/testsuite/systemtap.syscall/readwrite.c
@@ -26,56 +26,56 @@ int main()
v[2].iov_len = sizeof(STRING3);
fd = open("foobar1",O_WRONLY|O_CREAT, 0666);
- // open ("foobar1", O_WRONLY|O_CREAT, 0666) = NNNN
+ //staptest// open ("foobar1", O_WRONLY|O_CREAT, 0666) = NNNN
write(fd,"Hello world", 11);
- // write (NNNN, "Hello world", 11) = 11
+ //staptest// write (NNNN, "Hello world", 11) = 11
write(fd,"Hello world abcdefghijklmnopqrstuvwxyz 01234567890123456789", 59);
- // write (NNNN, "Hello world abcdefghijklmnopqrstuvwxyz 012345"..., 59) = 59
+ //staptest// write (NNNN, "Hello world abcdefghijklmnopqrstuvwxyz 012345"..., 59) = 59
pwrite(fd,"Hello Again",11,12);
- // pwrite (NNNN, "Hello Again", 11, 12) = 11
+ //staptest// pwrite (NNNN, "Hello Again", 11, 12) = 11
writev(fd, v, 3);
- // writev (NNNN, XXXX, 3) = 15
+ //staptest// writev (NNNN, XXXX, 3) = 15
lseek(fd, 0, SEEK_SET);
- // lseek (NNNN, 0, SEEK_SET) = 0
+ //staptest// lseek (NNNN, 0, SEEK_SET) = 0
lseek(fd, 1, SEEK_CUR);
- // lseek (NNNN, 1, SEEK_CUR) = 1
+ //staptest// lseek (NNNN, 1, SEEK_CUR) = 1
lseek(fd, -1, SEEK_END);
- // lseek (NNNN, -1, SEEK_END) = 84
+ //staptest// lseek (NNNN, -1, SEEK_END) = 84
#ifdef SYS__llseek
syscall(SYS__llseek, fd, 1, 0, &res, SEEK_SET);
- // llseek (NNNN, 0x1, 0x0, XXXX, SEEK_SET) = 0
+ //staptest// llseek (NNNN, 0x1, 0x0, XXXX, SEEK_SET) = 0
syscall(SYS__llseek, fd, 0, 0, &res, SEEK_SET);
- // llseek (NNNN, 0x0, 0x0, XXXX, SEEK_SET) = 0
+ //staptest// llseek (NNNN, 0x0, 0x0, XXXX, SEEK_SET) = 0
syscall(SYS__llseek, fd, 0, 12, &res, SEEK_CUR);
- // llseek (NNNN, 0x0, 0xc, XXXX, SEEK_CUR) = 0
+ //staptest// llseek (NNNN, 0x0, 0xc, XXXX, SEEK_CUR) = 0
syscall(SYS__llseek, fd, 8, 1, &res, SEEK_END);
- // llseek (NNNN, 0x8, 0x1, XXXX, SEEK_END) = 0
+ //staptest// llseek (NNNN, 0x8, 0x1, XXXX, SEEK_END) = 0
#endif
close (fd);
fd = open("foobar1",O_RDONLY);
- // open ("foobar1", O_RDONLY) = NNNN
+ //staptest// open ("foobar1", O_RDONLY) = NNNN
read(fd, buf, 11);
- // read (NNNN, XXXX, 11) = 11
+ //staptest// read (NNNN, XXXX, 11) = 11
read(fd, buf, 50);
- // read (NNNN, XXXX, 50) = 50
+ //staptest// read (NNNN, XXXX, 50) = 50
pread(fd, buf, 11, 10);
- // pread (NNNN, XXXX, 11, 10) = 11
+ //staptest// pread (NNNN, XXXX, 11, 10) = 11
x[0].iov_base = buf1;
x[0].iov_len = sizeof(STRING1);
@@ -84,7 +84,7 @@ int main()
x[2].iov_base = buf3;
x[2].iov_len = sizeof(STRING3);
readv(fd, x, 3);
- // readv (NNNN, XXXX, 3) = 15
+ //staptest// readv (NNNN, XXXX, 3) = 15
close (fd);
diff --git a/testsuite/systemtap.syscall/rt_signal.c b/testsuite/systemtap.syscall/rt_signal.c
index f25633b7..537b7706 100644
--- a/testsuite/systemtap.syscall/rt_signal.c
+++ b/testsuite/systemtap.syscall/rt_signal.c
@@ -20,30 +20,30 @@ int main()
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, NULL);
- // rt_sigprocmask (SIG_BLOCK, \[SIGUSR1|SIGUSR2\], 0x[0]+, 8) = 0
+ //staptest// rt_sigprocmask (SIG_BLOCK, \[SIGUSR1|SIGUSR2\], 0x[0]+, 8) = 0
sigdelset(&mask, SIGUSR2);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
- // rt_sigprocmask (SIG_UNBLOCK, \[SIGUSR1\], 0x[0]+, 8) = 0
+ //staptest// rt_sigprocmask (SIG_UNBLOCK, \[SIGUSR1\], 0x[0]+, 8) = 0
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGALRM);
sa.sa_flags = 0;
sigaction(SIGUSR1, &sa, NULL);
- // rt_sigaction (SIGUSR1, {SIG_IGN}, 0x[0]+, 8) = 0
+ //staptest// rt_sigaction (SIGUSR1, {SIG_IGN}, 0x[0]+, 8) = 0
sa.sa_handler = SIG_DFL;
sigaction(SIGUSR1, &sa, NULL);
- // rt_sigaction (SIGUSR1, {SIG_DFL}, 0x[0]+, 8) = 0
+ //staptest// rt_sigaction (SIGUSR1, {SIG_DFL}, 0x[0]+, 8) = 0
sa.sa_handler = sig_act_handler;
sigaction(SIGUSR1, &sa, NULL);
#ifdef __ia64__
- // rt_sigaction (SIGUSR1, {XXXX, [^,]+, \[SIGALRM\]}, 0x[0]+, 8) = 0
+ //staptest// rt_sigaction (SIGUSR1, {XXXX, [^,]+, \[SIGALRM\]}, 0x[0]+, 8) = 0
#else
- // rt_sigaction (SIGUSR1, {XXXX, [^,]+, XXXX, \[SIGALRM\]}, 0x[0]+, 8) = 0
+ //staptest// rt_sigaction (SIGUSR1, {XXXX, [^,]+, XXXX, \[SIGALRM\]}, 0x[0]+, 8) = 0
#endif
return 0;
diff --git a/testsuite/systemtap.syscall/select.c b/testsuite/systemtap.syscall/select.c
index 6ea13a01..088211e2 100644
--- a/testsuite/systemtap.syscall/select.c
+++ b/testsuite/systemtap.syscall/select.c
@@ -17,20 +17,20 @@ int main()
sigaddset(&sigs,SIGUSR2);
select( 1, &rfds, NULL, NULL, &tv);
- // select (1, XXXX, 0x[0]+, 0x[0]+, \[0.000117\])
+ //staptest// select (1, XXXX, 0x[0]+, 0x[0]+, \[0.000117\])
tv.tv_sec = 0;
tv.tv_usec = 113;
select( 1, NULL, NULL, NULL, &tv);
- // select (1, 0x[0]+, 0x[0]+, 0x[0]+, \[0.000113\])
+ //staptest// select (1, 0x[0]+, 0x[0]+, 0x[0]+, \[0.000113\])
#ifdef SYS_pselect6
pselect( 1, &rfds, NULL, NULL, &tim, &sigs);
- //pselect[67] (1, XXXX, 0x[0]+, 0x[0]+, \[0.200000000\], XXXX)
+ //staptest//pselect[67] (1, XXXX, 0x[0]+, 0x[0]+, \[0.200000000\], XXXX)
pselect( 0, NULL, NULL, NULL, &tim, &sigs);
- // pselect[67] (0, 0x[0]+, 0x[0]+, 0x[0]+, \[0.200000000\], XXXX) =
+ //staptest// pselect[67] (0, 0x[0]+, 0x[0]+, 0x[0]+, \[0.200000000\], XXXX) =
#endif
return 0;
diff --git a/testsuite/systemtap.syscall/sendfile.c b/testsuite/systemtap.syscall/sendfile.c
index 06c6b260..690d078e 100644
--- a/testsuite/systemtap.syscall/sendfile.c
+++ b/testsuite/systemtap.syscall/sendfile.c
@@ -36,7 +36,7 @@ int main ()
* sendfile will fail. So we test for failure here.
*/
ret = sendfile (write_fd, read_fd, &offset, stat_buf.st_size);
- // sendfile (NNNN, NNNN, XXXX, 512) = -22 (EINVAL)
+ //staptest// sendfile (NNNN, NNNN, XXXX, 512) = -22 (EINVAL)
close (read_fd);
close (write_fd);
diff --git a/testsuite/systemtap.syscall/signal.c b/testsuite/systemtap.syscall/signal.c
index 2c0abe38..e450c6d2 100644
--- a/testsuite/systemtap.syscall/signal.c
+++ b/testsuite/systemtap.syscall/signal.c
@@ -18,13 +18,13 @@ int main()
#ifdef SYS_signal
syscall(SYS_signal, SIGUSR1, SIG_IGN);
- // signal (SIGUSR1, SIG_IGN)
+ //staptest// signal (SIGUSR1, SIG_IGN)
syscall (SYS_signal, SIGUSR1, SIG_DFL);
- // signal (SIGUSR1, SIG_DFL) = 1
+ //staptest// signal (SIGUSR1, SIG_DFL) = 1
syscall (SYS_signal, SIGUSR1, sig_act_handler);
- // signal (SIGUSR1, XXXX) = 0
+ //staptest// signal (SIGUSR1, XXXX) = 0
#endif
sigemptyset(&mask);
@@ -32,10 +32,10 @@ int main()
#ifdef SYS_sigprocmask
syscall (SYS_sigprocmask, SIG_BLOCK, &mask, NULL);
- // sigprocmask (SIG_BLOCK, XXXX, 0x0+) = 0
+ //staptest// sigprocmask (SIG_BLOCK, XXXX, 0x0+) = 0
syscall (SYS_sigprocmask, SIG_UNBLOCK, &mask, NULL);
- // sigprocmask (SIG_UNBLOCK, XXXX, 0x0+) = 0
+ //staptest// sigprocmask (SIG_UNBLOCK, XXXX, 0x0+) = 0
#endif
memset(&sa, 0, sizeof(sa));
@@ -44,12 +44,12 @@ int main()
#ifdef SYS_sigaction
syscall (SYS_sigaction, SIGUSR1, &sa, NULL);
- // sigaction (SIGUSR1, {SIG_IGN}, 0x0+) = 0
+ //staptest// sigaction (SIGUSR1, {SIG_IGN}, 0x0+) = 0
#endif
#ifdef SYS_tgkill
syscall(SYS_tgkill, 1234, 5678, 0);
- // tgkill (1234, 5678, SIG_0)
+ //staptest// tgkill (1234, 5678, SIG_0)
#endif
return 0;
diff --git a/testsuite/systemtap.syscall/stat.c b/testsuite/systemtap.syscall/stat.c
index 6be5cc79..d47c1440 100644
--- a/testsuite/systemtap.syscall/stat.c
+++ b/testsuite/systemtap.syscall/stat.c
@@ -17,38 +17,38 @@ int main()
struct utimbuf ubuf;
getcwd(cwd, 128);
- // getcwd (XXXX, 128) = NNNN
+ //staptest// getcwd (XXXX, 128) = NNNN
fd = creat("foobar",S_IREAD|S_IWRITE);
- // open ("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
+ //staptest// open ("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
fstat(fd, &sbuf);
- // fstat (NNNN, XXXX) = 0
+ //staptest// fstat (NNNN, XXXX) = 0
close(fd);
stat("foobar",&sbuf);
- // stat ("foobar", XXXX) = 0
+ //staptest// stat ("foobar", XXXX) = 0
lstat("foobar",&sbuf);
- // lstat ("foobar", XXXX) = 0
+ //staptest// lstat ("foobar", XXXX) = 0
ubuf.actime = 1;
ubuf.modtime = 1135641600;
utime("foobar", &ubuf);
#ifdef __ia64__
- // utimes ("foobar", \[1.000000\]\[1135641600.000000\]) =
+ //staptest// utimes ("foobar", \[1.000000\]\[1135641600.000000\]) =
#else
- // utime ("foobar", \[Thu Jan 1 00:00:01 1970, Tue Dec 27 00:00:00 2005\]) = 0
+ //staptest// utime ("foobar", \[Thu Jan 1 00:00:01 1970, Tue Dec 27 00:00:00 2005\]) = 0
#endif
ubuf.actime = 1135690000;
ubuf.modtime = 1135700000;
utime("foobar", &ubuf);
#ifdef __ia64__
- // utimes ("foobar", \[1135690000.000000\]\[1135700000.000000\]) =
+ //staptest// utimes ("foobar", \[1135690000.000000\]\[1135700000.000000\]) =
#else
- // utime ("foobar", \[Tue Dec 27 13:26:40 2005, Tue Dec 27 16:13:20 2005\]) = 0
+ //staptest// utime ("foobar", \[Tue Dec 27 13:26:40 2005, Tue Dec 27 16:13:20 2005\]) = 0
#endif
return 0;
}
diff --git a/testsuite/systemtap.syscall/statfs.c b/testsuite/systemtap.syscall/statfs.c
index ea33193b..eafce77e 100644
--- a/testsuite/systemtap.syscall/statfs.c
+++ b/testsuite/systemtap.syscall/statfs.c
@@ -8,13 +8,13 @@ int main()
{
ustat(42, (struct ustat *)0x12345678);
- // ustat (42, 0x0*12345678) =
+ //staptest// ustat (42, 0x0*12345678) =
statfs("abc", (struct statfs *)0x12345678);
- // statfs ("abc", 0x0*12345678) =
+ //staptest// statfs ("abc", 0x0*12345678) =
fstatfs(77, (struct statfs *)0x12345678);
- // fstatfs (77, 0x0*12345678) =
+ //staptest// fstatfs (77, 0x0*12345678) =
return 0;
}
diff --git a/testsuite/systemtap.syscall/swap.c b/testsuite/systemtap.syscall/swap.c
index 3708a477..8fcf9946 100755..100644
--- a/testsuite/systemtap.syscall/swap.c
+++ b/testsuite/systemtap.syscall/swap.c
@@ -6,22 +6,22 @@
int main()
{
swapon("foobar_swap", 0);
- // swapon ("foobar_swap", 0) =
+ //staptest// swapon ("foobar_swap", 0) =
swapon("foobar_swap", ((1 << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER);
- // swapon ("foobar_swap", 32769) =
+ //staptest// swapon ("foobar_swap", 32769) =
swapon("foobar_swap", ((7 << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER);
- // swapon ("foobar_swap", 32775) =
+ //staptest// swapon ("foobar_swap", 32775) =
swapon(0, 0);
- // swapon (NULL, 0) =
+ //staptest// swapon (NULL, 0) =
swapoff("foobar_swap");
- // swapoff ("foobar_swap") =
+ //staptest// swapoff ("foobar_swap") =
swapoff(0);
- // swapoff (NULL) =
+ //staptest// swapoff (NULL) =
return 0;
}
diff --git a/testsuite/systemtap.syscall/sync.c b/testsuite/systemtap.syscall/sync.c
index 637bc197..d6e22203 100644
--- a/testsuite/systemtap.syscall/sync.c
+++ b/testsuite/systemtap.syscall/sync.c
@@ -13,13 +13,13 @@ int main()
fd = creat("foobar",S_IREAD|S_IWRITE);
sync();
- // sync () = 0
+ //staptest// sync () = 0
fsync(fd);
- // fsync (NNNN) = 0
+ //staptest// fsync (NNNN) = 0
fdatasync(fd);
- // fdatasync (NNNN) = 0
+ //staptest// fdatasync (NNNN) = 0
close(fd);
diff --git a/testsuite/systemtap.syscall/syscall.exp b/testsuite/systemtap.syscall/syscall.exp
index 2313403f..22e9dc07 100644
--- a/testsuite/systemtap.syscall/syscall.exp
+++ b/testsuite/systemtap.syscall/syscall.exp
@@ -48,15 +48,9 @@ proc test_procedure {} {
set do_32_bit_pass 1
switch -regexp $::tcl_platform(machine) {
- ^(x86_64|ppc64)$ {
- set flags "additional_flags=-m32"
- }
- ^s390x$ {
- set flags "additional_flags=-m31"
- }
- ^ia64$ {
- set do_32_bit_pass 0
- }
+ {^(x86_64|ppc64)$} { set flags "additional_flags=-m32" }
+ {^s390x$} { set flags "additional_flags=-m31" }
+ {^ia64$} { set do_32_bit_pass 0 }
}
if {$do_32_bit_pass} {
diff --git a/testsuite/systemtap.syscall/test-debug.tcl b/testsuite/systemtap.syscall/test-debug.tcl
index 13e0ad54..eb730459 100755
--- a/testsuite/systemtap.syscall/test-debug.tcl
+++ b/testsuite/systemtap.syscall/test-debug.tcl
@@ -68,7 +68,7 @@ if {$ind == 0} {
exit
}
-if {[catch {exec mktemp -d staptestXXXXX} dir]} {
+if {[catch {exec mktemp -d staptestXXXXXX} dir]} {
puts stderr "Failed to create temporary directory: $dir"
cleanup
}
diff --git a/testsuite/systemtap.syscall/test.tcl b/testsuite/systemtap.syscall/test.tcl
index db0df138..8a5801af 100755
--- a/testsuite/systemtap.syscall/test.tcl
+++ b/testsuite/systemtap.syscall/test.tcl
@@ -32,7 +32,7 @@ proc run_one_test {filename flags} {
set testname [file tail [string range $filename 0 end-2]]
set result "UNSUPP"
- if {[catch {exec mktemp -d [pwd]/staptestXXXXX} dir]} {
+ if {[catch {exec mktemp -d [pwd]/staptestXXXXXX} dir]} {
puts stderr "Failed to create temporary directory: $dir"
cleanup
}
@@ -40,22 +40,28 @@ proc run_one_test {filename flags} {
target_compile $filename $dir/$testname executable $flags
set sys_prog "[file dirname [file normalize $filename]]/sys.stp"
- set cmd "stap -c $dir/${testname} ${sys_prog}"
+ set cmd "stap --skip-badvars -c $dir/${testname} ${sys_prog}"
# Extract the expected results
# Use the preprocessor so we can ifdef tests in and out
set ccmd "gcc -E -C -P $filename"
+ # XXX: but note, this will expand all system headers too!
catch {eval exec $ccmd} output
set ind 0
foreach line [split $output "\n"] {
- if {[regsub {//} $line {} line]} {
+ if {[regsub {//staptest//} $line {} line]} {
set line "$testname: [string trimleft $line]"
-
+
+ # We need to quote all these metacharacters
regsub -all {\(} $line {\\(} line
- regsub -all {\)} $line {\\)} line
+ regsub -all {\)} $line {\\)} line
regsub -all {\|} $line {\|} line
+ # + and * are metacharacters, but should always be used
+ # as metacharacters in the expressions, don't escape them.
+ #regsub -all {\+} $line {\\+} line
+ #regsub -all {\*} $line {\\*} line
regsub -all NNNN $line {[\-0-9]+} line
regsub -all XXXX $line {[x0-9a-fA-F]+} line
@@ -78,6 +84,7 @@ proc run_one_test {filename flags} {
set i 0
foreach line [split $output "\n"] {
+ # send_log "Comparing $results($i) against $line"
if {[regexp $results($i) $line]} {
incr i
if {$i >= $ind} {break}
diff --git a/testsuite/systemtap.syscall/timer.c b/testsuite/systemtap.syscall/timer.c
index 947f6a77..9a55b2e8 100644
--- a/testsuite/systemtap.syscall/timer.c
+++ b/testsuite/systemtap.syscall/timer.c
@@ -13,19 +13,19 @@ int main()
struct itimerspec val, oval;
syscall(SYS_timer_create, CLOCK_REALTIME, NULL, &tid);
- // timer_create (CLOCK_REALTIME, 0x[0]+, XXXX)
+ //staptest// timer_create (CLOCK_REALTIME, 0x[0]+, XXXX)
syscall(SYS_timer_gettime, tid, &val);
- // timer_gettime (NNNN, XXXX)
+ //staptest// timer_gettime (NNNN, XXXX)
syscall(SYS_timer_settime, 0, tid, &val, &oval);
- // timer_settime (0, NNNN, \[0.000000,0.000000\], XXXX)
+ //staptest// timer_settime (0, NNNN, \[0.000000,0.000000\], XXXX)
syscall(SYS_timer_getoverrun, tid);
- // timer_getoverrun (NNNN)
+ //staptest// timer_getoverrun (NNNN)
syscall(SYS_timer_delete, tid);
- // timer_delete (NNNN)
+ //staptest// timer_delete (NNNN)
return 0;
}
diff --git a/testsuite/systemtap.syscall/trunc.c b/testsuite/systemtap.syscall/trunc.c
index 39a524a7..ef2b0c68 100644
--- a/testsuite/systemtap.syscall/trunc.c
+++ b/testsuite/systemtap.syscall/trunc.c
@@ -13,11 +13,11 @@ int main()
fd = creat("foobar",S_IREAD|S_IWRITE);
ftruncate(fd, 1024);
- // ftruncate (NNNN, 1024) = 0
+ //staptest// ftruncate (NNNN, 1024) = 0
close(fd);
truncate("foobar", 2048);
- // truncate ("foobar", 2048) = 0
+ //staptest// truncate ("foobar", 2048) = 0
return 0;
}
diff --git a/testsuite/systemtap.syscall/uid.c b/testsuite/systemtap.syscall/uid.c
index 3acb4cb8..6ccf8cdd 100644
--- a/testsuite/systemtap.syscall/uid.c
+++ b/testsuite/systemtap.syscall/uid.c
@@ -11,54 +11,54 @@ int main ()
gid_t rgid, egid, sgid;
ruid = getuid();
- // getuid () = NNNN
+ //staptest// getuid () = NNNN
euid = geteuid();
- // geteuid () = NNNN
+ //staptest// geteuid () = NNNN
rgid = getgid();
- // getgid () = NNNN
+ //staptest// getgid () = NNNN
egid = getegid();
- // getegid () = NNNN
+ //staptest// getegid () = NNNN
setuid(4096);
- // setuid (4096) = NNNN
+ //staptest// setuid (4096) = NNNN
seteuid(4097);
- // setresuid (-1, 4097, -1) = NNNN
+ //staptest// setresuid (-1, 4097, -1) = NNNN
getresuid(&ruid, &euid, &suid);
- // getresuid (XXXX, XXXX, XXXX) = 0
+ //staptest// getresuid (XXXX, XXXX, XXXX) = 0
setgid(4098);
- // setgid (4098) = NNNN
+ //staptest// setgid (4098) = NNNN
setegid(4099);
- // setresgid (-1, 4099, -1) = NNNN
+ //staptest// setresgid (-1, 4099, -1) = NNNN
getresgid(&rgid, &egid, &sgid);
- // getresgid (XXXX, XXXX, XXXX) = 0
+ //staptest// getresgid (XXXX, XXXX, XXXX) = 0
setreuid(-1, 5000);
- // setreuid (NNNN, 5000) =
+ //staptest// setreuid (NNNN, 5000) =
setreuid(5001, -1);
- // setreuid (5001, NNNN) =
+ //staptest// setreuid (5001, NNNN) =
setregid(-1, 5002);
- // setregid (NNNN, 5002) =
+ //staptest// setregid (NNNN, 5002) =
setregid(5003, -1);
- // setregid (5003, NNNN) =
+ //staptest// setregid (5003, NNNN) =
setfsuid(5004);
- // setfsuid (5004) =
+ //staptest// setfsuid (5004) =
setfsgid(5005);
- // setfsgid (5005) =
+ //staptest// setfsgid (5005) =
return 0;
}
diff --git a/testsuite/systemtap.syscall/uid16.c b/testsuite/systemtap.syscall/uid16.c
index 2d7d3349..4f2fcff1 100644
--- a/testsuite/systemtap.syscall/uid16.c
+++ b/testsuite/systemtap.syscall/uid16.c
@@ -17,54 +17,54 @@ int main ()
gid_t gid, rgid, egid, sgid;
uid = syscall(__NR_getuid);
- // getuid () = NNNN
+ //staptest// getuid () = NNNN
uid = syscall(__NR_geteuid);
- // geteuid () = NNNN
+ //staptest// geteuid () = NNNN
gid = syscall(__NR_getgid);
- // getgid () = NNNN
+ //staptest// getgid () = NNNN
gid = syscall(__NR_getegid);
- // getegid () = NNNN
+ //staptest// getegid () = NNNN
syscall(__NR_setuid, 4096);
- // setuid (4096) =
+ //staptest// setuid (4096) =
syscall(__NR_setresuid, -1, 4097, -1);
- // setresuid (-1, 4097, -1) =
+ //staptest// setresuid (-1, 4097, -1) =
syscall(__NR_getresuid, &ruid, &euid, &suid);
- // getresuid (XXXX, XXXX, XXXX) =
+ //staptest// getresuid (XXXX, XXXX, XXXX) =
syscall(__NR_setgid, 4098);
- // setgid (4098) =
+ //staptest// setgid (4098) =
syscall(__NR_setresgid, -1, 4099, -1);
- // setresgid (-1, 4099, -1) =
+ //staptest// setresgid (-1, 4099, -1) =
syscall(__NR_getresgid, &rgid, &egid, &sgid);
- // getresgid (XXXX, XXXX, XXXX) =
+ //staptest// getresgid (XXXX, XXXX, XXXX) =
syscall(__NR_setreuid, -1, 5000);
- // setreuid (-1, 5000) =
+ //staptest// setreuid (-1, 5000) =
syscall(__NR_setreuid, 5001, -1);
- // setreuid (5001, -1) =
+ //staptest// setreuid (5001, -1) =
syscall(__NR_setregid, -1, 5002);
- // setregid (-1, 5002) =
+ //staptest// setregid (-1, 5002) =
syscall(__NR_setregid, 5003, -1);
- // setregid (5003, -1) =
+ //staptest// setregid (5003, -1) =
syscall(__NR_setfsuid, 5004);
- // setfsuid (5004) =
+ //staptest// setfsuid (5004) =
syscall(__NR_setfsgid, 5005);
- // setfsgid (5005) =
+ //staptest// setfsgid (5005) =
#endif /* __i386__ */
diff --git a/testsuite/systemtap.syscall/umask.c b/testsuite/systemtap.syscall/umask.c
index 5d13575f..0a3d0534 100644
--- a/testsuite/systemtap.syscall/umask.c
+++ b/testsuite/systemtap.syscall/umask.c
@@ -5,16 +5,16 @@
int main()
{
umask (0);
- // umask (00) = NNNN
+ //staptest// umask (00) = NNNN
umask (7);
- // umask (07) = 00
+ //staptest// umask (07) = 00
umask (077);
- // umask (077) = 07
+ //staptest// umask (077) = 07
umask (0666);
- // umask (0666) = 077
+ //staptest// umask (0666) = 077
umask (0777);
- // umask (0777) = 0666
+ //staptest// umask (0777) = 0666
umask (01777);
- // umask (01777) = 0777
+ //staptest// umask (01777) = 0777
return 0;
}
diff --git a/testsuite/systemtap.syscall/unlink.c b/testsuite/systemtap.syscall/unlink.c
index b0d00be8..33fe6157 100644
--- a/testsuite/systemtap.syscall/unlink.c
+++ b/testsuite/systemtap.syscall/unlink.c
@@ -14,22 +14,22 @@ int main()
close (fd1);
unlink("foobar1");
- // unlink ("foobar1") = 0
+ //staptest// unlink ("foobar1") = 0
unlink("foobar1");
- // unlink ("foobar1") = -NNNN (ENOENT)
+ //staptest// unlink ("foobar1") = -NNNN (ENOENT)
unlink("foobar2");
- // unlink ("foobar2") = -NNNN (ENOENT)
+ //staptest// unlink ("foobar2") = -NNNN (ENOENT)
unlink(0);
- // unlink (NULL) = -NNNN (EFAULT)
+ //staptest// unlink (NULL) = -NNNN (EFAULT)
unlink("..");
- // unlink ("..") = -NNNN (EISDIR)
+ //staptest// unlink ("..") = -NNNN (EISDIR)
unlink("");
- // unlink ("") = -NNNN (ENOENT)
+ //staptest// unlink ("") = -NNNN (ENOENT)
return 0;
}
diff --git a/translate.cxx b/translate.cxx
index 17c37dc3..87811e9f 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -867,12 +867,10 @@ c_unparser::emit_common_header ()
o->newline() << "static atomic_t session_state = ATOMIC_INIT (STAP_SESSION_STARTING);";
o->newline() << "static atomic_t error_count = ATOMIC_INIT (0);";
o->newline() << "static atomic_t skipped_count = ATOMIC_INIT (0);";
- o->newline() << "#ifdef STP_TIMING";
o->newline() << "static atomic_t skipped_count_lowstack = ATOMIC_INIT (0);";
o->newline() << "static atomic_t skipped_count_reentrant = ATOMIC_INIT (0);";
o->newline() << "static atomic_t skipped_count_uprobe_reg = ATOMIC_INIT (0);";
o->newline() << "static atomic_t skipped_count_uprobe_unreg = ATOMIC_INIT (0);";
- o->newline() << "#endif";
o->newline();
o->newline() << "struct context {";
o->newline(1) << "atomic_t busy;";
@@ -920,6 +918,7 @@ c_unparser::emit_common_header ()
ostringstream oss;
oss << "c->statp = & time_" << dp->basest()->name << ";" << endl; // -t anti-dupe
oss << "# needs_global_locks: " << dp->needs_global_locks () << endl;
+ dp->print_dupe_stamp (oss);
dp->body->print(oss);
// NB: dependent probe conditions *could* be listed here, but don't need to be.
// That's because they're only dependent on the probe body, which is already
@@ -1360,9 +1359,10 @@ c_unparser::emit_module_exit ()
o->newline() << "#endif";
}
- // print final error/reentrancy counts if non-zero
+ // print final error/skipped counts if non-zero
o->newline() << "if (atomic_read (& skipped_count) || "
- << "atomic_read (& error_count)) {";
+ << "atomic_read (& error_count) || "
+ << "atomic_read (& skipped_count_reentrant)) {"; // PR9967
o->newline(1) << "_stp_warn (\"Number of errors: %d, "
<< "skipped probes: %d\\n\", "
<< "(int) atomic_read (& error_count), "
@@ -1508,6 +1508,7 @@ c_unparser::emit_probe (derived_probe* v)
// be very different with or without -t.
oss << "c->statp = & time_" << v->basest()->name << ";" << endl;
+ v->print_dupe_stamp (oss);
v->body->print(oss);
// Since the generated C changes based on whether or not the probe
@@ -3489,7 +3490,10 @@ c_unparser_assignment::visit_symbol (symbol *e)
void
c_unparser::visit_target_symbol (target_symbol* e)
{
- throw semantic_error("cannot translate general target-symbol expression", e->tok);
+ if (!e->probe_context_var.empty())
+ o->line() << "l->" << e->probe_context_var;
+ else
+ throw semantic_error("cannot translate general cast expression", e->tok);
}
@@ -4168,7 +4172,8 @@ c_unparser::visit_print_format (print_format* e)
int use_print = 0;
string format_string = print_format::components_to_string(components);
- if (tmp.size() == 0 || (tmp.size() == 1 && format_string == "%s"))
+ if ((tmp.size() == 0 && format_string.find("%%") == std::string::npos)
+ || (tmp.size() == 1 && format_string == "%s"))
use_print = 1;
else if (tmp.size() == 1
&& e->args[0]->tok->type == tok_string
@@ -4482,7 +4487,7 @@ dump_unwindsyms (Dwfl_Module *m,
// In the future, we'll also care about data symbols.
int syments = dwfl_module_getsymtab(m);
- assert(syments);
+ dwfl_assert ("Getting symbol table for " + modname, syments >= 0);
//extract build-id from debuginfo file
int build_id_len = 0;
@@ -4497,19 +4502,46 @@ dump_unwindsyms (Dwfl_Module *m,
// see https://bugzilla.redhat.com/show_bug.cgi?id=465872
// and http://sourceware.org/ml/systemtap/2008-q4/msg00579.html
#ifdef _ELFUTILS_PREREQ
-#if _ELFUTILS_PREREQ(0,138)
+ #if _ELFUTILS_PREREQ(0,138)
// Let's standardize to the buggy "end of build-id bits" behavior.
build_id_vaddr += build_id_len;
+ #endif
+ #if !_ELFUTILS_PREREQ(0,141)
+ #define NEED_ELFUTILS_BUILDID_WORKAROUND
+ #endif
+#else
+ #define NEED_ELFUTILS_BUILDID_WORKAROUND
#endif
+
+ // And check for another workaround needed.
+ // see https://bugzilla.redhat.com/show_bug.cgi?id=489439
+ // and http://sourceware.org/ml/systemtap/2009-q1/msg00513.html
+#ifdef NEED_ELFUTILS_BUILDID_WORKAROUND
+ if (build_id_vaddr < base && dwfl_module_relocations (m) == 1)
+ {
+ GElf_Addr main_bias;
+ dwfl_module_getelf (m, &main_bias);
+ build_id_vaddr += main_bias;
+ }
#endif
- if (c->session.verbose > 1) {
- clog << "Found build-id in " << name
- << ", length " << build_id_len;
- clog << ", end at 0x" << hex << build_id_vaddr
- << dec << endl;
- }
+ if (c->session.verbose > 1)
+ {
+ clog << "Found build-id in " << name
+ << ", length " << build_id_len;
+ clog << ", end at 0x" << hex << build_id_vaddr
+ << dec << endl;
+ }
}
+ // Get the canonical path of the main file for comparison at runtime.
+ // When given directly by the user through -d or in case of the kernel
+ // name and path might differ. path should be used for matching.
+ // Use end as sanity check when resolving symbol addresses and to
+ // calculate size for .dynamic and .absolute sections.
+ const char *mainfile;
+ Dwarf_Addr start, end;
+ dwfl_module_info (m, NULL, &start, &end, NULL, NULL, &mainfile, NULL);
+
// Look up the relocation basis for symbols
int n = dwfl_module_relocations (m);
@@ -4519,15 +4551,17 @@ dump_unwindsyms (Dwfl_Module *m,
// XXX: unfortunate duplication with tapsets.cxx:emit_address()
typedef map<Dwarf_Addr,const char*> addrmap_t; // NB: plain map, sorted by address
- vector<string> seclist; // encountered relocation bases (section names)
+ vector<pair<string,unsigned> > seclist; // encountered relocation bases
+ // (section names and sizes)
map<unsigned, addrmap_t> addrmap; // per-relocation-base sorted addrmap
Dwarf_Addr extra_offset = 0;
- for (int i = 1 /* XXX: why not 0? */ ; i < syments; ++i)
+ for (int i = 0; i < syments; ++i)
{
GElf_Sym sym;
- const char *name = dwfl_module_getsym(m, i, &sym, NULL);
+ GElf_Word shndxp;
+ const char *name = dwfl_module_getsym(m, i, &sym, &shndxp);
if (name)
{
// NB: Yey, we found the kernel's _stext value.
@@ -4547,23 +4581,25 @@ dump_unwindsyms (Dwfl_Module *m,
// base address outself. (see also below).
extra_offset = sym.st_value - base;
if (c->session.verbose > 2)
- clog << "Found kernel _stext 0x" << hex << extra_offset << dec << endl;
+ clog << "Found kernel _stext extra offset 0x" << hex << extra_offset << dec << endl;
}
- // We only need the function symbols to identify kernel-mode
- // PC's, so we omit undefined or "fake" absolute addresses.
- // These fake absolute addresses occur in some older i386
- // kernels to indicate they are vDSO symbols, not real
- // functions in the kernel.
- if (GELF_ST_TYPE (sym.st_info) == STT_FUNC &&
- ! (sym.st_shndx == SHN_UNDEF || sym.st_shndx == SHN_ABS))
+ // We are only interested in "real" symbols.
+ // We omit symbols that have suspicious addresses (before base,
+ // or after end).
+ if ((GELF_ST_TYPE (sym.st_info) == STT_FUNC ||
+ GELF_ST_TYPE (sym.st_info) == STT_OBJECT) // PR10000: also need .data
+ && !(sym.st_shndx == SHN_UNDEF // Value undefined,
+ || shndxp == (GElf_Word) -1 // in a non-allocated section,
+ || sym.st_value >= end // beyond current module,
+ || sym.st_value < base)) // before first section.
{
Dwarf_Addr sym_addr = sym.st_value;
+ Dwarf_Addr save_addr = sym_addr;
const char *secname = NULL;
if (n > 0) // only try to relocate if there exist relocation bases
{
- Dwarf_Addr save_addr = sym_addr;
int ki = dwfl_module_relocate_address (m, &sym_addr);
dwfl_assert ("dwfl_module_relocate_address", ki >= 0);
secname = dwfl_module_relocation_info (m, ki, NULL);
@@ -4581,6 +4617,16 @@ dump_unwindsyms (Dwfl_Module *m,
{
// This is a symbol within a (possibly relocatable)
// kernel image.
+
+ // We only need the function symbols to identify kernel-mode
+ // PC's, so we omit undefined or "fake" absolute addresses.
+ // These fake absolute addresses occur in some older i386
+ // kernels to indicate they are vDSO symbols, not real
+ // functions in the kernel. We also omit symbols that have
+ if (GELF_ST_TYPE (sym.st_info) == STT_FUNC
+ && sym.st_shndx == SHN_ABS)
+ continue;
+
secname = "_stext";
// NB: don't subtract session.sym_stext, which could be inconveniently NULL.
// Instead, sym_addr will get compensated later via extra_offset.
@@ -4606,10 +4652,27 @@ dump_unwindsyms (Dwfl_Module *m,
// Compute our section number
unsigned secidx;
for (secidx=0; secidx<seclist.size(); secidx++)
- if (seclist[secidx]==secname) break;
+ if (seclist[secidx].first==secname) break;
if (secidx == seclist.size()) // new section name
- seclist.push_back (secname);
+ {
+ // absolute, dynamic or kernel have just one relocation
+ // section, which covers the whole module address range.
+ unsigned size;
+ if (n <= 1)
+ size = end - start;
+ else
+ {
+ Dwarf_Addr b;
+ Elf_Scn *scn;
+ GElf_Shdr *shdr, shdr_mem;
+ scn = dwfl_module_address_section (m, &save_addr, &b);
+ assert (scn != NULL);
+ shdr = gelf_getshdr(scn, &shdr_mem);
+ size = shdr->sh_size;
+ }
+ seclist.push_back (make_pair(secname,size));
+ }
(addrmap[secidx])[sym_addr] = name;
}
@@ -4640,10 +4703,10 @@ dump_unwindsyms (Dwfl_Module *m,
// There would be only a small benefit to warning. A user
// likely can't do anything about this; backtraces for the
// affected module would just get all icky heuristicy.
-#if 0
- c->session.print_warning ("No unwind data for " + modname
- + ", " + dwfl_errmsg (-1));
-#endif
+ // So only report in verbose mode.
+ if (c->session.verbose > 2)
+ c->session.print_warning ("No unwind data for " + modname
+ + ", " + dwfl_errmsg (-1));
}
for (unsigned secidx = 0; secidx < seclist.size(); secidx++)
@@ -4670,18 +4733,27 @@ dump_unwindsyms (Dwfl_Module *m,
}
c->output << "static struct _stp_section _stp_module_" << stpmod_idx<< "_sections[] = {\n";
+ // For the kernel, executables (ET_EXEC) or shared libraries (ET_DYN)
+ // there is just one section that covers the whole address space of
+ // the module. For kernel modules (ET_REL) there can be multiple
+ // sections that get relocated separately.
for (unsigned secidx = 0; secidx < seclist.size(); secidx++)
{
c->output << "{\n"
- << ".name = " << lex_cast_qstring(seclist[secidx]) << ",\n"
+ << ".name = " << lex_cast_qstring(seclist[secidx].first) << ",\n"
+ << ".size = 0x" << hex << seclist[secidx].second << dec << ",\n"
<< ".symbols = _stp_module_" << stpmod_idx << "_symbols_" << secidx << ",\n"
- << ".num_symbols = sizeof(_stp_module_" << stpmod_idx << "_symbols_" << secidx << ")/sizeof(struct _stp_symbol)\n"
+ << ".num_symbols = " << addrmap[secidx].size() << "\n"
<< "},\n";
}
c->output << "};\n";
c->output << "static struct _stp_module _stp_module_" << stpmod_idx << " = {\n";
c->output << ".name = " << lex_cast_qstring (modname) << ", \n";
+
+ mainfile = canonicalize_file_name(mainfile);
+ c->output << ".path = " << lex_cast_qstring (mainfile) << ",\n";
+
c->output << ".dwarf_module_base = 0x" << hex << base << dec << ", \n";
if (unwind != NULL)
@@ -4743,6 +4815,7 @@ dump_unwindsyms (Dwfl_Module *m,
// Emit symbol table & unwind data, plus any calls needed to register
// them with the runtime.
+void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&);
void
emit_symbol_data (systemtap_session& s)
@@ -4755,6 +4828,14 @@ emit_symbol_data (systemtap_session& s)
unwindsym_dump_context ctx = { s, kallsyms_out, 0, s.unwindsym_modules };
+ // Micro optimization, mainly to speed up tiny regression tests
+ // using just begin probe.
+ if (s.unwindsym_modules.size () == 0)
+ {
+ emit_symbol_data_done(&ctx, s);
+ return;
+ }
+
// XXX: copied from tapsets.cxx dwflpp::, sadly
static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:build";
static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
@@ -4790,7 +4871,7 @@ emit_symbol_data (systemtap_session& s)
int rc = dwfl_linux_kernel_report_offline (dwfl,
elfutils_kernel_path.c_str(),
- NULL /* XXX: filtering callback */);
+ &dwfl_report_offline_predicate);
dwfl_report_end (dwfl, NULL, NULL);
if (rc == 0) // tolerate missing data; will warn user about it anyway
{
@@ -4798,6 +4879,7 @@ emit_symbol_data (systemtap_session& s)
do
{
if (pending_interrupts) return;
+ if (ctx.undone_unwindsym_modules.empty()) break;
off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0);
}
while (off > 0);
@@ -4812,7 +4894,8 @@ emit_symbol_data (systemtap_session& s)
{
NULL, /* dwfl_linux_kernel_find_elf, */
dwfl_standard_find_debuginfo,
- dwfl_offline_section_address,
+ NULL, /* ET_REL not supported for user space, only ET_EXEC and ET_DYN.
+ dwfl_offline_section_address, */
(char **) & debuginfo_path
};
@@ -4836,6 +4919,7 @@ emit_symbol_data (systemtap_session& s)
do
{
if (pending_interrupts) return;
+ if (ctx.undone_unwindsym_modules.empty()) break;
off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0);
}
while (off > 0);
@@ -4844,20 +4928,25 @@ emit_symbol_data (systemtap_session& s)
dwfl_end(dwfl);
}
+ emit_symbol_data_done (&ctx, s);
+}
+void
+emit_symbol_data_done (unwindsym_dump_context *ctx, systemtap_session& s)
+{
// Print out a definition of the runtime's _stp_modules[] globals.
- kallsyms_out << "\n";
- kallsyms_out << "static struct _stp_module *_stp_modules [] = {\n";
- for (unsigned i=0; i<ctx.stp_module_index; i++)
+ ctx->output << "\n";
+ ctx->output << "static struct _stp_module *_stp_modules [] = {\n";
+ for (unsigned i=0; i<ctx->stp_module_index; i++)
{
- kallsyms_out << "& _stp_module_" << i << ",\n";
+ ctx->output << "& _stp_module_" << i << ",\n";
}
- kallsyms_out << "};\n";
- kallsyms_out << "static unsigned _stp_num_modules = " << ctx.stp_module_index << ";\n";
+ ctx->output << "};\n";
+ ctx->output << "static unsigned _stp_num_modules = " << ctx->stp_module_index << ";\n";
// Some nonexistent modules may have been identified with "-d". Note them.
- for (set<string>::iterator it = ctx.undone_unwindsym_modules.begin();
- it != ctx.undone_unwindsym_modules.end();
+ for (set<string>::iterator it = ctx->undone_unwindsym_modules.begin();
+ it != ctx->undone_unwindsym_modules.end();
it ++)
{
s.print_warning ("missing unwind/symbol data for module '" + (*it) + "'");
@@ -4926,6 +5015,8 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#define STP_OVERLOAD";
s.op->newline() << "#endif";
+ s.op->newline() << "#define STP_SKIP_BADVARS " << (s.skip_badvars ? 1 : 0);
+
if (s.bulk_mode)
s.op->newline() << "#define STP_BULKMODE";
@@ -4936,9 +5027,7 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#define STP_PERFMON";
s.op->newline() << "#include \"runtime.h\"";
- s.op->newline() << "#include \"regs.c\"";
s.op->newline() << "#include \"stack.c\"";
- s.op->newline() << "#include \"regs-ia64.c\"";
s.op->newline() << "#include \"stat.c\"";
s.op->newline() << "#include <linux/string.h>";
s.op->newline() << "#include <linux/timer.h>";
diff --git a/util.cxx b/util.cxx
index 7d191cd2..5c05a1dd 100644
--- a/util.cxx
+++ b/util.cxx
@@ -1,5 +1,5 @@
// Copyright (C) Andrew Tridgell 2002 (original file)
-// Copyright (C) 2006 Red Hat Inc. (systemtap changes)
+// Copyright (C) 2006, 2009 Red Hat Inc. (systemtap changes)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
@@ -20,13 +20,15 @@
#include <cerrno>
extern "C" {
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <fcntl.h>
#include <pwd.h>
-#include <unistd.h>
+#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
}
using namespace std;
@@ -133,6 +135,25 @@ create_dir(const char *dir)
return 0;
}
+// Remove a file or directory
+int
+remove_file_or_dir (const char *name)
+{
+ int rc;
+ struct stat st;
+
+ if ((rc = stat(name, &st)) != 0)
+ {
+ if (errno == ENOENT)
+ return 0;
+ return 1;
+ }
+
+ if (remove (name) != 0)
+ return 1;
+ cerr << "remove returned 0" << endl;
+ return 0;
+}
void
tokenize(const string& str, vector<string>& tokens,
@@ -248,4 +269,62 @@ const string cmdstr_quoted(const string& cmd)
return quoted_cmd;
}
+
+string
+git_revision(const string& path)
+{
+ string revision = "(not-a-git-repository)";
+ string git_dir = path + "/.git/";
+
+ struct stat st;
+ if (stat(git_dir.c_str(), &st) == 0)
+ {
+ string command = "git --git-dir=\"" + git_dir
+ + "\" rev-parse HEAD 2>/dev/null";
+
+ char buf[50];
+ FILE *fp = popen(command.c_str(), "r");
+ if (fp != NULL)
+ {
+ char *bufp = fgets(buf, sizeof(buf), fp);
+ int rc = pclose(fp);
+ if (bufp != NULL && rc == 0)
+ revision = buf;
+ }
+ }
+
+ return revision;
+}
+
+
+static pid_t spawned_pid = 0;
+
+// Runs a command with a saved PID, so we can kill it from the signal handler
+int
+stap_system(const char *command)
+{
+ const char * argv[] = { "sh", "-c", command, NULL };
+ int ret, status;
+
+ spawned_pid = 0;
+ ret = posix_spawn(&spawned_pid, "/bin/sh", NULL, NULL,
+ const_cast<char **>(argv), environ);
+ if (ret == 0)
+ {
+ if (waitpid(spawned_pid, &status, 0) == spawned_pid)
+ ret = WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
+ else
+ ret = errno;
+ }
+ spawned_pid = 0;
+ return ret;
+}
+
+// Send a signal to our spawned command
+int
+kill_stap_spawn(int sig)
+{
+ return spawned_pid ? kill(spawned_pid, sig) : 0;
+}
+
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/util.h b/util.h
index 2884e021..175f1f40 100644
--- a/util.h
+++ b/util.h
@@ -8,10 +8,14 @@
const char *get_home_directory(void);
int copy_file(const char *src, const char *dest);
int create_dir(const char *dir);
+int remove_file_or_dir(const char *dir);
void tokenize(const std::string& str, std::vector<std::string>& tokens,
const std::string& delimiters);
std::string find_executable(const std::string& name);
const std::string cmdstr_quoted(const std::string& cmd);
+std::string git_revision(const std::string& path);
+int stap_system(const char *command);
+int kill_stap_spawn(int sig);
// stringification generics