summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@elastic.org>2009-10-08 09:57:43 -0400
committerFrank Ch. Eigler <fche@elastic.org>2009-10-08 09:57:43 -0400
commit561079c8601d7ded6fe958b4cec3d0f7aec1ee63 (patch)
treeb6481615519c60f87314319c1828eb6645833b19
parente4cf148d68fe01b680856ad39739faf99bfc29b4 (diff)
downloadsystemtap-steved-561079c8601d7ded6fe958b4cec3d0f7aec1ee63.tar.gz
systemtap-steved-561079c8601d7ded6fe958b4cec3d0f7aec1ee63.tar.xz
systemtap-steved-561079c8601d7ded6fe958b4cec3d0f7aec1ee63.zip
PR10702: preprocessor conditional for kernel CONFIG_foo
* session.h (kernel_config[]): New session field. * main.cxx (parse_kernel_config): Populate it. * parse.cxx (eval_comparison): Use it. * testsuite/buildok/utrace.stp, testsuite/parseok/kconfig.stp: New tests. * NEWS, stap.1.in, doc/langref.tex: Mention it.
-rw-r--r--NEWS3
-rw-r--r--doc/langref.tex11
-rw-r--r--main.cxx32
-rw-r--r--parse.cxx23
-rw-r--r--session.h1
-rw-r--r--stap.1.in11
-rwxr-xr-xtestsuite/buildok/utrace.stp3
-rwxr-xr-xtestsuite/parseok/kconfig.stp3
8 files changed, 80 insertions, 7 deletions
diff --git a/NEWS b/NEWS
index b8a42305..9fe26ba6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
* What's new
+- Preprocessor conditional for kernel configuration testing:
+ %( CONFIG_foo == "y" %? ... %)
+
- ftrace(msg:string) tapset function to send strings to the system-wide
ftrace ring-buffer (if any).
diff --git a/doc/langref.tex b/doc/langref.tex
index 523deb1b..3afe6128 100644
--- a/doc/langref.tex
+++ b/doc/langref.tex
@@ -1816,6 +1816,17 @@ probe kernel.function (
%( arch == "ia64" %?
probe syscall.vliw = kernel.function("vliw_widget") {}
%)
+
+\end{verbatim}
+\end{vindent}
+
+The following code adapts to the presence of a kernel CONFIG option.
+
+\begin{vindent}
+\begin{verbatim}
+%( CONFIG_UTRACE == "y" %?
+ probe process.syscall {}
+%)
\end{verbatim}
\end{vindent}
diff --git a/main.cxx b/main.cxx
index 86990675..c0ff3ba5 100644
--- a/main.cxx
+++ b/main.cxx
@@ -335,8 +335,8 @@ setup_signals (sighandler_t handler)
sigaction (SIGTERM, &sa, NULL);
}
-void
-setup_kernel_release (systemtap_session &s, const char* kstr) {
+void setup_kernel_release (systemtap_session &s, const char* kstr)
+{
if (kstr[0] == '/') // fully specified path
{
s.kernel_build_tree = kstr;
@@ -364,6 +364,29 @@ setup_kernel_release (systemtap_session &s, const char* kstr) {
}
}
+
+void parse_kernel_config (systemtap_session &s)
+{
+ // PR10702: pull config options
+ string kernel_config_file = s.kernel_build_tree + "/.config";
+ ifstream kcf (kernel_config_file.c_str());
+ string line;
+ while (getline (kcf, line))
+ {
+ if (line.substr(0, 7) != "CONFIG_") continue;
+ size_t off = line.find('=');
+ if (off == string::npos) continue;
+ string key = line.substr(0, off);
+ string value = line.substr(off+1, string::npos);
+ s.kernel_config[key] = value;
+ }
+ if (s.verbose > 2)
+ clog << "Parsed kernel \"" << kernel_config_file << "\", number of tuples: " << s.kernel_config.size() << endl;
+
+ kcf.close();
+}
+
+
static void
checkOptions (systemtap_session &s)
{
@@ -945,6 +968,9 @@ main (int argc, char * const argv [])
clog << "Created temporary directory \"" << s.tmpdir << "\"" << endl;
}
+ // Now that no further changes to s.kernel_build_tree can occur, let's use it.
+ parse_kernel_config (s);
+
// Create the name of the C source file within the temporary
// directory.
s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
@@ -1028,7 +1054,7 @@ main (int argc, char * const argv [])
// GLOB_NOMATCH is acceptable
if (s.verbose>1 && globbuf.gl_pathc > 0)
- clog << "Searched '" << dir << "', "
+ clog << "Searched \"" << dir << "\", "
<< "found " << globbuf.gl_pathc << endl;
for (unsigned j=0; j<globbuf.gl_pathc; j++)
diff --git a/parse.cxx b/parse.cxx
index bfd7600f..b88ef7ff 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -183,12 +183,14 @@ bool eval_comparison (const OPERAND& lhs, const token* op, const OPERAND& rhs)
// The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %)
// where CONDITION is: kernel_v[r] COMPARISON-OP "version-string"
// or: arch COMPARISON-OP "arch-string"
+// or: CONFIG_foo COMPARISON-OP "config-string"
// or: "string1" COMPARISON-OP "string2"
// or: number1 COMPARISON-OP number2
// The %: ELSE-TOKENS part is optional.
//
// e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %)
// e.g. %( arch != "i?86" %? "foo" %: "baz" %)
+// e.g. %( CONFIG_foo %? "foo" %: "baz" %)
//
// Up to an entire %( ... %) expression is processed by a single call
// to this function. Tokens included by any nested conditions are
@@ -270,6 +272,23 @@ bool eval_pp_conditional (systemtap_session& s,
return result;
}
+ else if (l->type == tok_identifier && l->content.substr(0,7) == "CONFIG_" && r->type == tok_string)
+ {
+ string lhs = s.kernel_config[l->content]; // may be empty
+ string rhs = r->content;
+
+ int nomatch = fnmatch (lhs.c_str(), rhs.c_str(), FNM_NOESCAPE); // still spooky
+
+ bool result;
+ if (op->type == tok_operator && op->content == "==")
+ result = !nomatch;
+ else if (op->type == tok_operator && op->content == "!=")
+ result = nomatch;
+ else
+ throw parse_error ("expected '==' or '!='", op);
+
+ return result;
+ }
else if (l->type == tok_string && r->type == tok_string)
{
string lhs = l->content;
@@ -291,10 +310,8 @@ bool eval_pp_conditional (systemtap_session& s,
&& op->type == tok_operator)
throw parse_error ("expected number literal as right value", r);
- // XXX: support other forms? "CONFIG_SMP" ?
-
else
- throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'\n"
+ throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr' or 'CONFIG_...'\n"
" or comparison between strings or integers", l);
}
diff --git a/session.h b/session.h
index a2176793..cc13c321 100644
--- a/session.h
+++ b/session.h
@@ -87,6 +87,7 @@ struct systemtap_session
std::string kernel_release;
std::string kernel_base_release;
std::string kernel_build_tree;
+ std::map<std::string,std::string> kernel_config;
std::string architecture;
std::string runtime_path;
std::string data_path;
diff --git a/stap.1.in b/stap.1.in
index e6370dfc..b6f79fe9 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -340,12 +340,21 @@ by
If, on the other hand, the first part is the identifier
.BR arch
to refer to the processor architecture (as named by the kernel
-build system ARCH/SUBARCH), then the second part then the second
+build system ARCH/SUBARCH), then the second
part is one of the two string comparison operators
.BR == " or " != ,
and the third part is a string literal for matching it. This
comparison is a wildcard (mis)match.
.PP
+Similarly, if the first part is an identifier like
+.BR CONFIG_something
+to refer to a kernel configuration option, then the second part is
+.BR == " or " != ,
+and the third part is a string literal for matching the value
+(commonly "y" or "m"). Nonexistent or unset kernel configuration
+options are represented by the empty string. This comparison is also
+a wildcard (mis)match.
+.PP
Otherwise, the CONDITION is expected to be a comparison between two string
literals or two numeric literals. In this case, the arguments are the only
variables usable.
diff --git a/testsuite/buildok/utrace.stp b/testsuite/buildok/utrace.stp
new file mode 100755
index 00000000..436bf9c4
--- /dev/null
+++ b/testsuite/buildok/utrace.stp
@@ -0,0 +1,3 @@
+#! stap -p4
+
+probe %( CONFIG_UTRACE == "y" %? process.begin %: never %) { }
diff --git a/testsuite/parseok/kconfig.stp b/testsuite/parseok/kconfig.stp
new file mode 100755
index 00000000..02920853
--- /dev/null
+++ b/testsuite/parseok/kconfig.stp
@@ -0,0 +1,3 @@
+#! stap -p2
+
+%( CONFIG_NO_SUCH_CONFIG == "" %? probe never {} %: %)