summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2010-03-10 19:17:40 -0800
committerJosh Stone <jistone@redhat.com>2010-03-10 19:24:14 -0800
commitda9e11bd5cd3cbedbf794a0e8a83956bd178ba60 (patch)
treed727a14411eeda77c767fa30fe09ab4895b43798
parente54c1d239a7dba1954dfc8359e62c94329b44a6a (diff)
downloadsystemtap-steved-da9e11bd5cd3cbedbf794a0e8a83956bd178ba60.tar.gz
systemtap-steved-da9e11bd5cd3cbedbf794a0e8a83956bd178ba60.tar.xz
systemtap-steved-da9e11bd5cd3cbedbf794a0e8a83956bd178ba60.zip
PR11370: Add multi-header @casts
Sometimes you need multiple headers to fully describe a type, so we now permit them to be listed together, e.g. "kernel<foo.h><bar.h>". * buildrun.cxx (make_typequery): Split the input string into a vector. (make_typequery_kmod, make_typequery_umod): Use the vector of headers. * testsuite/semok/cast.stp: Add a multi-header case. * stap.1.in, NEWS: Document it.
-rw-r--r--NEWS4
-rw-r--r--buildrun.cxx48
-rw-r--r--stap.1.in3
-rwxr-xr-xtestsuite/semok/cast.stp3
4 files changed, 39 insertions, 19 deletions
diff --git a/NEWS b/NEWS
index df0824d3..4c3cf751 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,9 @@
* What's new
+- Type-casting can now use multiple headers to resolve codependencies.
+ @cast(task, "task_struct",
+ "kernel<linux/sched.h><linux/fs_struct.h>")->fs->umask
+
- Tapset-related man pages have been renamed. 'man -k 3stap' should show
the installed list, which due to prefixing should no longer collide over
ordinary system functions.
diff --git a/buildrun.cxx b/buildrun.cxx
index d6fc52ee..084022bf 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -541,7 +541,7 @@ make_tracequery(systemtap_session& s, string& name,
// Build a tiny kernel module to query type information
static int
-make_typequery_kmod(systemtap_session& s, const string& header, string& name)
+make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string& name)
{
static unsigned tick = 0;
string basename("typequery_kmod_" + lex_cast(++tick));
@@ -569,7 +569,10 @@ make_typequery_kmod(systemtap_session& s, const string& header, string& name)
// 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 << "CFLAGS_" << basename << ".o :=";
+ for (size_t i = 0; i < headers.size(); ++i)
+ omf << " -include " << lex_cast_qstring(headers[i]);
+ omf << endl;
omf << "obj-m := " + basename + ".o" << endl;
omf.close();
@@ -598,7 +601,7 @@ make_typequery_kmod(systemtap_session& s, const string& header, string& name)
// Build a tiny user module to query type information
static int
-make_typequery_umod(systemtap_session& s, const string& header, string& name)
+make_typequery_umod(systemtap_session& s, const vector<string>& headers, string& name)
{
static unsigned tick = 0;
@@ -610,11 +613,13 @@ make_typequery_umod(systemtap_session& s, const string& header, string& name)
// 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;
+ ostringstream cmd;
+ cmd << "gcc -shared -g -fno-eliminate-unused-debug-types -xc /dev/null -o " << name;
+ for (size_t i = 0; i < headers.size(); ++i)
+ cmd << " -include " << lex_cast_qstring(headers[i]);
if (s.verbose < 4)
- cmd += " >/dev/null 2>&1";
- return stap_system (s.verbose, cmd);
+ cmd << " >/dev/null 2>&1";
+ return stap_system (s.verbose, cmd.str());
}
@@ -623,23 +628,28 @@ make_typequery(systemtap_session& s, string& module)
{
int rc;
string new_module;
+ vector<string> headers;
+ bool kernel = (module.compare(0, 6, "kernel") == 0);
- 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)
+ for (size_t end, i = kernel ? 6 : 0; i < module.size(); i = end + 1)
{
- string header = module.substr(7, module.size() - 8);
- rc = make_typequery_kmod(s, header, new_module);
+ if (module[i] != '<')
+ return -1;
+ end = module.find('>', ++i);
+ if (end == string::npos)
+ return -1;
+ string header = module.substr(i, end - i);
+ assert_regexp_match("@cast header", header, "^[a-z0-9/_.+-]+$");
+ headers.push_back(header);
}
- else
+ if (headers.empty())
return -1;
+ if (kernel)
+ rc = make_typequery_kmod(s, headers, new_module);
+ else
+ rc = make_typequery_umod(s, headers, new_module);
+
if (!rc)
module = new_module;
diff --git a/stap.1.in b/stap.1.in
index e1b38878..01fb9aba 100644
--- a/stap.1.in
+++ b/stap.1.in
@@ -844,9 +844,12 @@ 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.
+Multiple headers may be specified in sequence to resolve a codependency.
.SAMPLE
@cast(tv, "timeval", "<sys/time.h>")->tv_sec
@cast(task, "task_struct", "kernel<linux/sched.h>")->tgid
+@cast(task, "task_struct",
+ "kernel<linux/sched.h><linux/fs_struct.h>")->fs->umask
.ESAMPLE
.PP
When in guru mode, the translator will also allow scripts to assign new
diff --git a/testsuite/semok/cast.stp b/testsuite/semok/cast.stp
index 14401886..d3606a50 100755
--- a/testsuite/semok/cast.stp
+++ b/testsuite/semok/cast.stp
@@ -15,6 +15,9 @@ probe begin {
println(@cast(0, "task_struct", "kernel<linux/sched.h>")->tgid)
println(@cast(0, "timeval", "<sys/time.h>")->tv_sec)
+ // sometimes multiple headers are needed in tandem
+ println(@cast(0, "task_struct", "kernel<linux/sched.h><linux/fs_struct.h>")->fs->umask)
+
// make sure that bogus @casts can get optimized away
@cast(0, "task_struct")->no_such_field
@cast(0, "task_struct")->parent->no_such_field