summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buildrun.cxx57
-rw-r--r--buildrun.h2
-rw-r--r--cache.cxx18
-rw-r--r--hash.cxx20
-rw-r--r--hash.h2
-rw-r--r--tapsets.cxx67
-rwxr-xr-xtestsuite/semok/cast.stp4
-rw-r--r--testsuite/systemtap.base/cast.exp6
-rw-r--r--testsuite/systemtap.base/cast.stp21
9 files changed, 192 insertions, 5 deletions
diff --git a/buildrun.cxx b/buildrun.cxx
index e0f22f29..71753e9f 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -443,4 +443,61 @@ make_tracequery(systemtap_session& s, string& name, const vector<string>& extra_
return run_make_cmd(s, make_cmd);
}
+
+// Build a tiny kernel module to query type information
+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;
+ 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
+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
+ 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";
+ return stap_system (cmd.c_str());
+}
+
/* 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 e87b7b85..fb33b4c8 100644
--- a/buildrun.h
+++ b/buildrun.h
@@ -15,6 +15,8 @@ int compile_pass (systemtap_session& s);
int run_pass (systemtap_session& s);
int make_tracequery(systemtap_session& s, std::string& name, const std::vector<std::string>& extra_headers);
+int make_typequery_kmod(systemtap_session& s, const std::string& header, std::string& name);
+int make_typequery_umod(systemtap_session& s, const std::string& header, std::string& name);
#endif // BUILDRUN_H
diff --git a/cache.cxx b/cache.cxx
index 86f7213a..61bc243f 100644
--- a/cache.cxx
+++ b/cache.cxx
@@ -253,14 +253,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/hash.cxx b/hash.cxx
index 01013c43..45ae05eb 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -273,4 +273,24 @@ find_tracequery_hash (systemtap_session& s)
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 bb3d5ae1..7e432216 100644
--- a/hash.h
+++ b/hash.h
@@ -37,5 +37,7 @@ public:
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/tapsets.cxx b/tapsets.cxx
index 01c838d9..5a62d47f 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -5104,9 +5104,64 @@ 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 "kmod<path/to/header>" or "umod<path/to/header>"
+ // for those cases, build a module including that header
+ if (module.rfind('>') == module.size() - 1 &&
+ (module.compare(0, 5, "kmod<") == 0 ||
+ module.compare(0, 5, "umod<") == 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
+ int rc;
+ string new_module, header = module.substr(5, module.size() - 6);
+ if (module[0] == 'k')
+ rc = make_typequery_kmod(s, header, new_module);
+ else
+ rc = make_typequery_umod(s, header, new_module);
+ if (rc == 0)
+ {
+ module = new_module;
+
+ if (s.use_cache)
+ {
+ // try to save typequery in the cache
+ if (s.verbose > 2)
+ clog << "Copying " << new_module
+ << " to " << cached_module << endl;
+ if (copy_file(new_module.c_str(),
+ cached_module.c_str()) != 0)
+ cerr << "Copy failed (\"" << new_module << "\" to \""
+ << cached_module << "\"): " << strerror(errno) << endl;
+ }
+ }
+ }
+}
+
+
void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
{
bool lvalue = is_active_lvalue(e);
@@ -5125,6 +5180,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
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);
+ 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.
@@ -5148,7 +5204,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
diff --git a/testsuite/semok/cast.stp b/testsuite/semok/cast.stp
index 93da18ef..d30823cd 100755
--- a/testsuite/semok/cast.stp
+++ b/testsuite/semok/cast.stp
@@ -10,4 +10,8 @@ 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", "kmod<linux/sched.h>")->tgid)
+ println(@cast(0, "timeval", "umod<sys/time.h>")->tv_sec)
}
diff --git a/testsuite/systemtap.base/cast.exp b/testsuite/systemtap.base/cast.exp
index df3246e8..74c4d72a 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
+tv_sec OK}
+stap_run2 $srcdir/$subdir/$test.stp -g
diff --git a/testsuite/systemtap.base/cast.stp b/testsuite/systemtap.base/cast.stp
index bec0cc9b..33a14a28 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", "kmod<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,19 @@ probe begin
else
printf("execname \"%s\" != \"%s\"\n", name, cast_name)
+ // Compare tv_sec using a generated user module
+ sec = 42
+ cast_sec = @cast(get_timeval(sec), "timeval", "umod<sys/time.h>")->tv_sec
+ if (sec == cast_sec)
+ println("tv_sec OK")
+ else
+ printf("tv_sec %d != %d\n", sec, cast_sec)
+
exit()
}
+
+function get_timeval:long(sec:long) %{
+ static struct timeval mytime = {0};
+ mytime.tv_sec = THIS->sec;
+ THIS->__retvalue = (long)&mytime;
+%}