From da9e11bd5cd3cbedbf794a0e8a83956bd178ba60 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 10 Mar 2010 19:17:40 -0800 Subject: 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". * 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. --- NEWS | 4 ++++ buildrun.cxx | 48 +++++++++++++++++++++++++++++------------------- stap.1.in | 3 +++ testsuite/semok/cast.stp | 3 +++ 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")->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& 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")->... - 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& 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 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", "")->tv_sec @cast(task, "task_struct", "kernel")->tgid +@cast(task, "task_struct", + "kernel")->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")->tgid) println(@cast(0, "timeval", "")->tv_sec) + // sometimes multiple headers are needed in tandem + println(@cast(0, "task_struct", "kernel")->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 -- cgit