summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--NEWS35
-rw-r--r--buildrun.cxx35
-rw-r--r--doc/SystemTap_Tapset_Reference/tapsets.tmpl39
-rw-r--r--hash.cxx18
-rw-r--r--hash.h1
-rw-r--r--includes/sys/sdt.h171
-rw-r--r--initscript/README.initscript2
-rw-r--r--initscript/systemtap.in22
-rw-r--r--main.cxx14
-rw-r--r--runtime/itrace.c6
-rw-r--r--runtime/staprun/common.c218
-rw-r--r--runtime/staprun/mainloop.c52
-rw-r--r--runtime/staprun/relay.c134
-rw-r--r--runtime/staprun/relay_old.c124
-rw-r--r--runtime/staprun/staprun.h29
-rw-r--r--runtime/task_finder.c6
-rw-r--r--runtime/uprobes2/uprobes.c6
-rw-r--r--runtime/uprobes2/uprobes.h5
-rw-r--r--runtime/utrace_compatibility.h5
-rwxr-xr-xscripts/kernel-doc2
-rw-r--r--session.h2
-rw-r--r--stap.1.in31
-rw-r--r--staprun.8.in17
-rw-r--r--tapset/ip.stp32
-rw-r--r--tapset/tcp.stp34
-rw-r--r--tapsets.cxx38
-rw-r--r--testsuite/lib/stap_run2.exp2
-rw-r--r--testsuite/systemtap.base/sdt.exp20
-rw-r--r--testsuite/systemtap.base/sdt.stp20
-rw-r--r--testsuite/systemtap.base/static_uprobes.exp12
-rw-r--r--testsuite/systemtap.examples/network/tcp.stp11
-rw-r--r--translate.cxx7
33 files changed, 915 insertions, 238 deletions
diff --git a/AUTHORS b/AUTHORS
index 6a20ef72..0ed3ed04 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,6 +1,7 @@
Ananth N Mavinakayanahalli
Anil Keshavamurthy
Anithra Janakiraman
+Breno Leitao
Charles Spirakis
Dan Horak
Dave Brolley
@@ -21,6 +22,8 @@ K.Prasad
Kent Sebastian
Kevin Stafford
Li Guanglei
+Lubomir Rintel
+Mahesh J Salgaonkar
Mark McLoughlin
Mark Wielaard
Martin Hunt
diff --git a/NEWS b/NEWS
index fff8afc9..7ae93675 100644
--- a/NEWS
+++ b/NEWS
@@ -1,14 +1,43 @@
* What's new
+- 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.
* What's new in version 0.9
diff --git a/buildrun.cxx b/buildrun.cxx
index d797607b..48d4ea50 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -340,7 +340,10 @@ 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";
@@ -392,21 +395,25 @@ make_tracequery(systemtap_session& s, string& name)
// 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[2] = { "/include/trace/*.h", "/source/include/trace/*.h" };
+ for (unsigned z=0; z<2; 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(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;
+ }
+ globfree(&trace_glob);
}
- globfree(&trace_glob);
// finish up the module source
osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
diff --git a/doc/SystemTap_Tapset_Reference/tapsets.tmpl b/doc/SystemTap_Tapset_Reference/tapsets.tmpl
index 892d30a9..21706ea2 100644
--- a/doc/SystemTap_Tapset_Reference/tapsets.tmpl
+++ b/doc/SystemTap_Tapset_Reference/tapsets.tmpl
@@ -5,23 +5,10 @@
<book id="TapsetRef">
<bookinfo>
<title>SystemTap Tapset Reference Manual</title>
-
- <authorgroup>
- <author>
- <firstname>William</firstname>
- <surname>Cohen</surname>
- <contrib></contrib>
- <affiliation>
- <address>
- <email>wcohen@redhat.com</email>
- </address>
- </affiliation>
- </author>
- </authorgroup>
<copyright>
- <year>2008, 2009</year>
- <holder>Red Hat, Inc.</holder>
+ <year>2008-2009</year>
+ <holder>Red Hat, Inc. and others</holder>
</copyright>
<legalnotice>
@@ -170,11 +157,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">
@@ -185,25 +173,6 @@
</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>
<para>
diff --git a/hash.cxx b/hash.cxx
index 61caa356..b8d5a0e4 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -237,4 +237,22 @@ 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";
+}
+
/* 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..0fe95e27 100644
--- a/hash.h
+++ b/hash.h
@@ -35,5 +35,6 @@ public:
};
void find_hash (systemtap_session& s, const std::string& script);
+void find_tracequery_hash (systemtap_session& s);
/* 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..3da4ff66 100644
--- a/includes/sys/sdt.h
+++ b/includes/sys/sdt.h
@@ -13,124 +13,98 @@
#include <string.h>
#include <sys/types.h>
-#if _LP64
-#define STAP_PROBE_STRUCT_ARG(arg) \
- __uint64_t arg
-#else
-#define STAP_PROBE_STRUCT_ARG(arg) \
- long arg __attribute__ ((aligned(8)))
-#endif
+#define STAP_PROBE_DATA_(probe,dataop) \
+ __asm__ volatile (".section .probes\n" \
+ "\t.align 8\n" \
+ "1:\n\t.asciz " #probe "\n" \
+ "\t.align 4\n" \
+ "\t.int 0x31425250\n" \
+ "\t.align 8\n" \
+ "\t" #dataop " 1b\n" \
+ "\t.align 8\n" \
+ "\t" #dataop " 2f\n" \
+ "\t.previous\n")
-#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 */
-#define STAP_CONCAT(a,b) a ## b
-#define STAP_LABEL_PREFIX(p) _stapprobe1_ ## p
-/* __COUNTER__ is not present in gcc 4.1 */
-#if __GNUC__ == 4 && __GNUC_MINOR__ >= 3
-#define STAP_COUNTER STAP_CONCAT(__,COUNTER__)
+#if _LP64
+#define STAP_PROBE_DATA(probe) \
+ STAP_PROBE_DATA_(#probe,.quad)
#else
-#define STAP_COUNTER STAP_CONCAT(__,LINE__)
+#define STAP_PROBE_DATA(probe) \
+ STAP_PROBE_DATA_(#probe,.long)
#endif
-#define STAP_LABEL(a,b) STAP_CONCAT(a,b)
-#define STAP_PROBE_(probe,label) \
+#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" \
+ "\tnop"); \
} while (0)
-#define STAP_PROBE1_(probe,label,parm1) \
+#define STAP_PROBE1_(probe,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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 */" :: "X"(arg1)); \
} while (0)
-#define STAP_PROBE2_(probe,label,parm1,parm2) \
+#define STAP_PROBE2_(probe,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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 */" :: "X"(arg1), "X"(arg2)); \
} while (0)
-#define STAP_PROBE3_(probe,label,parm1,parm2,parm3) \
+#define STAP_PROBE3_(probe,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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 */" :: "X"(arg1), "X"(arg2), "X"(arg3)); \
} while (0)
-#define STAP_PROBE4_(probe,label,parm1,parm2,parm3,parm4) \
+#define STAP_PROBE4_(probe,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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4)); \
} while (0)
-#define STAP_PROBE5_(probe,label,parm1,parm2,parm3,parm4,parm5) \
+#define STAP_PROBE5_(probe,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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 %4 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5)); \
} while (0)
-#define STAP_PROBE6_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6) \
+#define STAP_PROBE6_(probe,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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 %4 %5 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6)); \
} while (0)
-#define STAP_PROBE7_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \
+#define STAP_PROBE7_(probe,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; \
@@ -138,14 +112,13 @@ do { \
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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 %4 %5 %6 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7)); \
} while (0)
-#define STAP_PROBE8_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \
+#define STAP_PROBE8_(probe,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; \
@@ -154,14 +127,13 @@ do { \
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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 %4 %5 %6 %7 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7), "X"(arg8)); \
} while (0)
-#define STAP_PROBE9_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \
+#define STAP_PROBE9_(probe,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; \
@@ -171,14 +143,13 @@ do { \
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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 %4 %5 %6 %7 %8 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7), "X"(arg8), "X"(arg9)); \
} while (0)
-#define STAP_PROBE10_(probe,label,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \
+#define STAP_PROBE10_(probe,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; \
@@ -189,33 +160,33 @@ do { \
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_PROBE_DATA(probe); \
+ __asm__ volatile ("2:\n" \
+ "\tnop /* %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 */" :: "X"(arg1), "X"(arg2), "X"(arg3), "X"(arg4), "X"(arg5), "X"(arg6), "X"(arg7), "X"(arg8), "X"(arg9), "X"(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))
+ STAP_PROBE1_(probe,(parm1))
#define STAP_PROBE2(provider,probe,parm1,parm2) \
- STAP_PROBE2_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2))
+ STAP_PROBE2_(probe,(parm1),(parm2))
#define STAP_PROBE3(provider,probe,parm1,parm2,parm3) \
- STAP_PROBE3_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3))
+ STAP_PROBE3_(probe,(parm1),(parm2),(parm3))
#define STAP_PROBE4(provider,probe,parm1,parm2,parm3,parm4) \
- STAP_PROBE4_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4))
+ STAP_PROBE4_(probe,(parm1),(parm2),(parm3),(parm4))
#define STAP_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) \
- STAP_PROBE5_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4),(parm5))
+ STAP_PROBE5_(probe,(parm1),(parm2),(parm3),(parm4),(parm5))
#define STAP_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) \
- STAP_PROBE6_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4),(parm5),(parm6))
+ STAP_PROBE6_(probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6))
#define STAP_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \
- STAP_PROBE7_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7))
+ STAP_PROBE7_(probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7))
#define STAP_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \
- STAP_PROBE8_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8))
+ STAP_PROBE8_(probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8))
#define STAP_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \
- STAP_PROBE9_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8),(parm9))
+ STAP_PROBE9_(probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8),(parm9))
#define STAP_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \
- STAP_PROBE10_(probe,STAP_LABEL(STAP_LABEL_PREFIX(probe),STAP_COUNTER),(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8),(parm9),(parm10))
+ STAP_PROBE10_(probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8),(parm9),(parm10))
#define DTRACE_PROBE(provider,probe) \
STAP_PROBE(provider,probe)
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 ab57fde5..d6c03c2f 100644
--- a/main.cxx
+++ b/main.cxx
@@ -108,10 +108,14 @@ 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
+ << " a subset of strftime(3) (%%,%C,%Y,%y,%m,%d,%e,%F,%H,%I,%j,%k," << endl
+ << " %l,%M,%S,%R,%T,%u,%w) 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;
@@ -447,7 +451,7 @@ main (int argc, char * const argv [])
{ "sign-module", 2, &long_opt, LONG_OPT_SIGN_MODULE },
{ 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;
@@ -631,6 +635,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;
diff --git a/runtime/itrace.c b/runtime/itrace.c
index 3d9ded2f..618cbff0 100644
--- a/runtime/itrace.c
+++ b/runtime/itrace.c
@@ -18,6 +18,12 @@
#include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/utrace.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"
diff --git a/runtime/staprun/common.c b/runtime/staprun/common.c
index fd16b4b8..8200ec9d 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,132 @@ 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)
+{
+ char *c = buf;
+ const char *c2 = fmt, *end = buf + max;
+ int ret, num;
+ struct tm tm;
+ if (buf == NULL || fmt == NULL || max <= 1)
+ return -EINVAL;
+ localtime_r(&t, &tm);
+
+ while (*c2 != '\0'){
+ if (c + 1 >= end)
+ return -EINVAL;
+ if (*c2 != '%') {
+ *c++ = *c2++;
+ continue;
+ }
+ c2++;
+ switch (*c2++) {
+ case '%':
+ *c++ = '%';
+ break;
+ case 'Y':
+ num = tm.tm_year + 1900;
+ goto numbering;
+ case 'y':
+ num = tm.tm_year % 100;
+ goto numbering02;
+ case 'C':
+ num = ((tm.tm_year + 1900 - 1) / 100) + 1;
+ goto numbering;
+ case 'm':
+ num = tm.tm_mon + 1;
+ goto numbering02;
+ case 'd':
+ num = tm.tm_mday;
+ goto numbering02;
+ case 'e':
+ num = tm.tm_mday;
+ goto numbering;
+ case 'F':
+ ret = snprintf(c, end - c, "%d-%02d-%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'H':
+ num = tm.tm_hour;
+ goto numbering02;
+ case 'I':
+ num = tm.tm_hour % 12;
+ if (num == 0) num = 12;
+ goto numbering02;
+ case 'j':
+ ret = snprintf(c, end - c, "%03d", tm.tm_yday);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'k':
+ num = tm.tm_hour;
+ goto numbering;
+ case 'l':
+ num = tm.tm_hour % 12;
+ if (num == 0) num = 12;
+ goto numbering;
+ case 'M':
+ num = tm.tm_min;
+ goto numbering02;
+ case 'S':
+ num = tm.tm_sec;
+ goto numbering02;
+ case 'R':
+ ret = snprintf(c, end - c, "%02d:%02d",
+ tm.tm_hour, tm.tm_min);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'T':
+ ret = snprintf(c, end - c, "%02d:%02d:%02d",
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ if (ret < 0) return ret;
+ c += ret;
+ break;
+ case 'u':
+ num = tm.tm_wday == 0 ? 7 : tm.tm_wday;
+ goto numbering;
+ case 'w':
+ num = tm.tm_wday;
+ goto numbering;
+ default:
+ return -EINVAL;
+ }
+ continue;
+numbering:
+ ret = snprintf(c, end - c, "%d", num);
+ if (ret < 0) return ret;
+ c += ret;
+ continue;
+numbering02:
+ ret = snprintf(c, end - c, "%02d", num);
+ if (ret < 0) return ret;
+ c += ret;
+ }
+ *c = '\0';
+ return c - buf;
+}
+
void parse_args(int argc, char **argv)
{
int c;
+ char *s;
/* Initialize option variables. */
verbose = 0;
@@ -49,8 +175,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 +214,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 +274,41 @@ 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 a subset of\n");
+ err(" strftime(3) (%%%%,%%C,%%Y,%%y,%%m,%%d,%%e,%%F,%%H,%%I\n");
+ err(" %%j,%%k,%%l,%%M,%%S,%%R,%%T,%%u,%%w) 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 +319,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 +531,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 b5ba7fbf..205fdf37 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -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;
}
@@ -454,21 +489,14 @@ int stp_main_loop(void)
switch (type) {
#ifdef STP_OLD_TRANSPORT
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:
{
diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c
index 19621933..50f295b5 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);
@@ -99,6 +189,19 @@ static void *reader_thread(void *data)
}
}
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);
+ return(NULL);
+ }
+ wsize = 0;
+ }
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);
@@ -116,7 +219,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 +266,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 +307,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..ef8fd0da 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,6 +231,18 @@ 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);
+ exit(1);
+ }
+ scb->wsize = 0;
+ }
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);
@@ -196,6 +266,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);
@@ -217,7 +288,7 @@ static void *reader_thread(void *data)
}
rc = read(proc_fd[cpu], &status[cpu].info, sizeof(struct _stp_buf_info));
- subbufs_consumed = process_subbufs(&status[cpu].info);
+ subbufs_consumed = process_subbufs(&status[cpu].info, &scb);
if (subbufs_consumed) {
if (subbufs_consumed > status[cpu].max_backlog)
status[cpu].max_backlog = subbufs_consumed;
@@ -233,6 +304,33 @@ static void *reader_thread(void *data)
}
/**
+ * 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 = 0;
+ }
+ 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;
+}
+
+/**
* init_relayfs - create files and threads for relayfs processing
*
* Returns 0 if successful, negative otherwise
@@ -249,10 +347,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 84cf63fc..acc533b2 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")
@@ -113,7 +117,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);
@@ -125,6 +134,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 *);
@@ -153,6 +163,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/task_finder.c b/runtime/task_finder.c
index 2b408763..3f4908cb 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -6,6 +6,12 @@
#endif
#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>
diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c
index af187fc9..a0e9f2fe 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>
diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h
index 11d01f5c..112e29e2 100644
--- a/runtime/uprobes2/uprobes.h
+++ b/runtime/uprobes2/uprobes.h
@@ -23,6 +23,11 @@
#include <linux/types.h>
#include <linux/list.h>
+/* Adapt to struct renaming. */
+#ifdef UTRACE_API_VERSION
+#define utrace_attached_engine utrace_engine
+#endif
+
struct pt_regs;
enum uprobe_type {
diff --git a/runtime/utrace_compatibility.h b/runtime/utrace_compatibility.h
index 4a70da42..5521a5c2 100644
--- a/runtime/utrace_compatibility.h
+++ b/runtime/utrace_compatibility.h
@@ -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
/*
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 9947882d..92178910 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -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);
diff --git a/session.h b/session.h
index 679bda2f..106918b6 100644
--- a/session.h
+++ b/session.h
@@ -91,6 +91,7 @@ struct systemtap_session
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;
@@ -117,6 +118,7 @@ struct systemtap_session
std::string cache_path;
std::string hash_path;
std::string stapconf_path;
+ std::string tracequery_path;
// dwarfless operation
bool consult_symtab;
diff --git a/stap.1.in b/stap.1.in
index 5a2e35f9..c562c8b7 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -175,7 +175,9 @@ 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 a subset of strftime(3) (%%, %C, %Y, %y, %m, %d, %e, %F,
+%H, %I, %j, %l, %M, %S, %R, %T, %u, %w) for FILE.
.TP
.BI \-c " CMD"
Start the probes, run CMD, and exit when CMD finishes.
@@ -193,8 +195,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 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.
.TP
.B \-\-kelf
For names and addresses of functions to probe,
@@ -776,10 +788,12 @@ 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
When in guru mode, the translator will also allow scripts to assign new
values to members of typecasted pointers.
@@ -1044,7 +1058,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
diff --git a/staprun.8.in b/staprun.8.in
index c7e77dc4..01ef2320 100644
--- a/staprun.8.in
+++ b/staprun.8.in
@@ -52,7 +52,10 @@ 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 backgroud and bulk mode)
+where 'x' is the cpu number. This supports a subset of strftime(3)
+(%%, %C, %Y, %y, %m, %d, %e, %F, %H, %I, %j, %l, %M, %S, %R, %T, %u, %w)
+for FILE.
.TP
.B \-b BUFFER_SIZE
The systemtap module will specify a buffer size.
@@ -73,6 +76,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
diff --git a/tapset/ip.stp b/tapset/ip.stp
new file mode 100644
index 00000000..1e2e263c
--- /dev/null
+++ b/tapset/ip.stp
@@ -0,0 +1,32 @@
+// 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>
+
+/**
+ * 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
+}
diff --git a/tapset/tcp.stp b/tapset/tcp.stp
index 1375f115..bb96b0cb 100644
--- a/tapset/tcp.stp
+++ b/tapset/tcp.stp
@@ -73,6 +73,16 @@ 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
+}
+
+/* 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) {
@@ -182,6 +192,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
*/
@@ -189,12 +203,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
@@ -202,6 +224,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)
}
/**
@@ -209,6 +235,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
@@ -217,6 +247,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)
}
/**
diff --git a/tapsets.cxx b/tapsets.cxx
index a8653d8a..e9ade595 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -18,6 +18,7 @@
#include "buildrun.h"
#include "dwarf_wrappers.h"
#include "auto_free.h"
+#include "hash.h"
#include <cstdlib>
#include <algorithm>
@@ -206,7 +207,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";
@@ -9991,12 +9994,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);
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);
diff --git a/testsuite/lib/stap_run2.exp b/testsuite/lib/stap_run2.exp
index b734a1e7..d1f02c83 100644
--- a/testsuite/lib/stap_run2.exp
+++ b/testsuite/lib/stap_run2.exp
@@ -29,7 +29,7 @@ proc stap_run2 { TEST_NAME args } {
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]
+ set cmd [concat stap $TEST_FILE $args]
send_log "executing: $cmd\n"
catch {eval exec $cmd} res
diff --git a/testsuite/systemtap.base/sdt.exp b/testsuite/systemtap.base/sdt.exp
index 21b94810..46fa5a28 100644
--- a/testsuite/systemtap.base/sdt.exp
+++ b/testsuite/systemtap.base/sdt.exp
@@ -15,6 +15,7 @@ set extra_flags {{""} {additional_flags=-std=gnu89} {additional_flags=-ansi} {ad
# 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,42 +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]} {
- stap_run3 "$test $extra_flag" $srcdir/$subdir/$test.stp -c ./$test.prog
+ 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]} {
- stap_run3 "$test c++ $extra_flag" $srcdir/$subdir/$test.stp -c ./$test.prog
+ 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/static_uprobes.exp b/testsuite/systemtap.base/static_uprobes.exp
index b4214436..e407440e 100644
--- a/testsuite/systemtap.base/static_uprobes.exp
+++ b/testsuite/systemtap.base/static_uprobes.exp
@@ -103,7 +103,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
@@ -177,6 +181,10 @@ expect {
wait
-if {$ok == 5} { pass "$test C++" } { fail "$test C++ ($ok)" }
+# we now generate the probes via asm so there is no label debug info
+if {$ok == 5} { pass "$test C++" } { xfail "$test C++ ($ok)" }
+if { $verbose == 0 } {
catch {exec rm -f $sup_srcpath $sup_exepath $supcplus_exepath $sup_dpath $sup_hpath $sup_stppath}
+}
+
diff --git a/testsuite/systemtap.examples/network/tcp.stp b/testsuite/systemtap.examples/network/tcp.stp
new file mode 100644
index 00000000..ebe72a1c
--- /dev/null
+++ b/testsuite/systemtap.examples/network/tcp.stp
@@ -0,0 +1,11 @@
+//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/translate.cxx b/translate.cxx
index 377a11fb..40bb82c2 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;";
@@ -1360,9 +1358,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), "