summaryrefslogtreecommitdiffstats
diff options
authorFrank Ch. Eigler <fche@redhat.com>2025-09-15 13:02:23 -0400
committerFrank Ch. Eigler <fche@elastic.org>2025-09-15 13:07:36 -0400
commit1fe4178def008f562244e1820d0ffe10f774e78a (patch)
treee20a9c6259e5fdf30482e1ad03303242f0b04cf6
parentsystemtap.syscall/*.exp: [file tail FOO] in pass/fail messages (diff)
PR33428: imply kernel<vmlinux.h> in kernel-side @cast() for type info
Linux 5.7+ includes a vmlinux.h file generated during build that includes most or all kernel-side data structure declarations, mainly for use by BPF compilers. By processing that into DWARF via the typequery mechanism, we can generate kernel data structure debuginfo for use in many @cast operations, without having to painstakingly enumerate and track the exact kernel header files containing those declarations. This search is active and preferred by default for all kernel-space @cast operations. It can be disabled with "--compatible=5.3" .
-rw-r--r--NEWS8
-rw-r--r--buildrun.cxx29
-rw-r--r--man/stap.1.in4
-rw-r--r--tapsets.cxx40
-rw-r--r--testsuite/semok/pr33428.stp8
5 files changed, 76 insertions, 13 deletions
diff --git a/NEWS b/NEWS
index f1d78e8fa..76c9676a6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,13 @@
1* What's new in version 5.4 1* What's new in version 5.4
2 2
3- The kernel-context @cast operator now implicitly searches a kernel's
4 <vmlinux.h> generated header file first, if available (kernel 5.7+),
5 for type declarations. This can make some debuginfo access
6 unnecessary, and thus processing faster. It can work around kernel
7 API changes where type declarations move between headers.
8 Use --compatible=5.3 to disable this behaviour.
9 Use @cast(..., "kernel<vmlinux.h>") manually if desired.
10
3- Type checking and autocast processing have been made more thorough, 11- Type checking and autocast processing have been made more thorough,
4 so elided variables are checked more and @defined() tests may be 12 so elided variables are checked more and @defined() tests may be
5 more complicated. Preexisting scripts that rely on elision for 13 more complicated. Preexisting scripts that rely on elision for
diff --git a/buildrun.cxx b/buildrun.cxx
index ad299d0fc..1f56a976b 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -1201,9 +1201,19 @@ make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string&
1201 // full kernel build tree, it's possible to get at types that aren't in the 1201 // full kernel build tree, it's possible to get at types that aren't in the
1202 // normal include path, e.g.: 1202 // normal include path, e.g.:
1203 // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->... 1203 // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->...
1204 omf << "CFLAGS_" << basename << ".o :="; 1204 omf << "CFLAGS_" << basename << ".o := -w "; // suppress warnings
1205 bool no_vmlinux_h = true;
1205 for (size_t i = 0; i < headers.size(); ++i) 1206 for (size_t i = 0; i < headers.size(); ++i)
1206 omf << " -include " << lex_cast_qstring(headers[i]); // XXX right quoting? 1207 {
1208 const string& h = headers[i];
1209 if (h == string("vmlinux.h")) // PR33428: vmlinux.h special case
1210 {
1211 omf << " -include " << lex_cast_qstring(s.kernel_build_tree) << "/" << lex_cast_qstring("vmlinux.h");
1212 no_vmlinux_h = false;
1213 }
1214 else
1215 omf << " -include " << lex_cast_qstring(h); // XXX right quoting?
1216 }
1207 omf << endl; 1217 omf << endl;
1208 1218
1209 omf << "obj-m := " + basename + ".o" << endl; 1219 omf << "obj-m := " + basename + ".o" << endl;
@@ -1213,10 +1223,17 @@ make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string&
1213 string source(dir + "/" + basename + ".c"); 1223 string source(dir + "/" + basename + ".c");
1214 ofstream osrc(source.c_str()); 1224 ofstream osrc(source.c_str());
1215 1225
1216 // this is mandated by linux kbuild as of 5.11+ 1226 if (no_vmlinux_h) {
1217 osrc << "#include <linux/module.h>" << endl; 1227 // this is mandated by linux kbuild as of 5.11+
1218 osrc << "MODULE_LICENSE(\"GPL\");" << endl; 1228 osrc << "#include <linux/module.h>" << endl;
1219 osrc << "MODULE_DESCRIPTION(\"" << basename << "\");" << endl; 1229 osrc << "MODULE_LICENSE(\"GPL\");" << endl;
1230 osrc << "MODULE_DESCRIPTION(\"" << basename << "\");" << endl;
1231 } else {
1232 // PR33428: do the same as the above, but without using linux/module.h macro infrastructure, because
1233 // vmlinux.h conflicts with kernel headers.
1234 osrc << "static const char modinfo[] __attribute__((__used__)) __attribute__((__section__(\".modinfo\"))) = \"license=GPL\\0description=typequery\";" << endl;
1235 }
1236
1220 1237
1221 osrc.close(); 1238 osrc.close();
1222 1239
diff --git a/man/stap.1.in b/man/stap.1.in
index 80c9d50d0..0a069eba7 100644
--- a/man/stap.1.in
+++ b/man/stap.1.in
@@ -1899,6 +1899,10 @@ surrounded by angle brackets, in case normal debuginfo is not available. For
1899kernel headers, prefix it with "kernel" to use the appropriate build system. 1899kernel headers, prefix it with "kernel" to use the appropriate build system.
1900All other headers are built with default GCC parameters into a user module. 1900All other headers are built with default GCC parameters into a user module.
1901Multiple headers may be specified in sequence to resolve a codependency. 1901Multiple headers may be specified in sequence to resolve a codependency.
1902.PP
1903As of systemtap version 5.4, the kernel "<vmlinux.h>" header is tried before
1904any specified kernel headers or modules, which may make it unnecessary to list
1905any explicit module or header file names for kernel data structures.
1902.SAMPLE 1906.SAMPLE
1903@cast(tv, "timeval", "<sys/time.h>")\->tv_sec 1907@cast(tv, "timeval", "<sys/time.h>")\->tv_sec
1904@cast(task, "task_struct", "kernel<linux/sched.h>")\->tgid 1908@cast(task, "task_struct", "kernel<linux/sched.h>")\->tgid
diff --git a/tapsets.cxx b/tapsets.cxx
index 38c8a49b2..d267b6506 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -500,10 +500,10 @@ static const string TOK_LIBRARY("library");
500static const string TOK_PLT("plt"); 500static const string TOK_PLT("plt");
501static const string TOK_METHOD("method"); 501static const string TOK_METHOD("method");
502static const string TOK_CLASS("class");; 502static const string TOK_CLASS("class");;
503static const string TOK_CALLEE("callee");; 503static const string TOK_CALLEE("callee");
504static const string TOK_CALLEES("callees");; 504static const string TOK_CALLEES("callees");
505static const string TOK_NEAREST("nearest");; 505static const string TOK_NEAREST("nearest");
506 506static const string TOK_KERNEL_VMLINUX_H("kernel<vmlinux.h>");
507 507
508 508
509struct dwarf_query; // forward decl 509struct dwarf_query; // forward decl
@@ -4853,7 +4853,7 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
4853void 4853void
4854dwarf_var_expanding_visitor::visit_cast_op (cast_op *e) 4854dwarf_var_expanding_visitor::visit_cast_op (cast_op *e)
4855{ 4855{
4856 // Fill in our current module context if needed 4856 // Fill in our current module context if needed, i.e., absent third field in @cast()
4857 if (e->module.empty()) 4857 if (e->module.empty())
4858 { 4858 {
4859 // Backward compatibility for @cast() ops, sans module string, 4859 // Backward compatibility for @cast() ops, sans module string,
@@ -4862,7 +4862,16 @@ dwarf_var_expanding_visitor::visit_cast_op (cast_op *e)
4862 if (strverscmp(sess.compatible.c_str(), "4.3") < 0) 4862 if (strverscmp(sess.compatible.c_str(), "4.3") < 0)
4863 e->module = "kernel"; 4863 e->module = "kernel";
4864 else 4864 else
4865 e->module = q.dw.module_name; 4865 {
4866 // absolute /user/space/path/name xor kernel xor kernel-module name
4867 if (is_user_module (q.dw.module_name))
4868 e->module = q.dw.module_name;
4869 else if ((strverscmp(sess.compatible.c_str(), "5.4") >= 0) && // default on new enough systemtap
4870 (strverscmp(sess.kernel_base_release.c_str(), "6.7") >= 0)) // for new enough kernel to have a vmlinux.h
4871 e->module = string(TOK_KERNEL_VMLINUX_H) + string(":") + q.dw.module_name; // PR33428: prefix
4872 else
4873 e->module = q.dw.module_name;
4874 }
4866 } 4875 }
4867 4876
4868 var_expanding_visitor::visit_cast_op(e); 4877 var_expanding_visitor::visit_cast_op(e);
@@ -5153,10 +5162,27 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
5153 5162
5154 // split the module string by ':' for alternatives 5163 // split the module string by ':' for alternatives
5155 vector<string> modules; 5164 vector<string> modules;
5165
5166 // PR33428: prepend "kernel<vmlinux.h>" to the list if there is any
5167 // "kernel" or "kernel<FILE>" component.
5168 if ((strverscmp(sess.compatible.c_str(), "5.4") >= 0) && // default on new enough systemtap
5169 (strverscmp(sess.kernel_base_release.c_str(), "6.7") >= 0) && // for new enough kernel to have a vmlinux.h
5170 (e->module.find(TOK_KERNEL_VMLINUX_H) == string::npos)) // don't prepend again; might already be here from implicit "" expansion
5171 {
5172 if (e->module.starts_with("kernel")) // right at the front?
5173 e->module = string(TOK_KERNEL_VMLINUX_H) + string(":") + e->module;
5174 else {
5175 string::size_type p = e->module.find(":kernel"); // in the middle?
5176 if (p != string::npos)
5177 e->module.insert(p, TOK_KERNEL_VMLINUX_H + string (":"));
5178 }
5179 }
5180
5156 tokenize(e->module, modules, ":"); 5181 tokenize(e->module, modules, ":");
5157 bool userspace_p=false; // PR10601 5182
5158 for (unsigned i = 0; !result && i < modules.size(); ++i) 5183 for (unsigned i = 0; !result && i < modules.size(); ++i)
5159 { 5184 {
5185 bool userspace_p=false; // PR10601
5160 string& module = modules[i]; 5186 string& module = modules[i];
5161 filter_special_modules(module); 5187 filter_special_modules(module);
5162 5188
diff --git a/testsuite/semok/pr33428.stp b/testsuite/semok/pr33428.stp
new file mode 100644
index 000000000..2557b00a3
--- /dev/null
+++ b/testsuite/semok/pr33428.stp
@@ -0,0 +1,8 @@
1#! stap -p2
2
3probe module("nfsv3").function("nfs3_proc_access"), kernel.function("do_sys_open")
4{
5 print(@cast(0xf00d, "struct mount")$, "kernel<vmlinux.h") // explicit
6 print(@cast(0xbeef, "struct mount")$) // implicit "nfsv3"->"kernel<vmlinux.h>:nfsv3"
7 print(@cast(0xdead, "struct mount")$,"kernel<linux/sched.h>") // explicit ->"kernel<vmlinux.h>:kernel<linux/sched.h>"
8}