]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // build/run probes |
3e1ec884 | 2 | // Copyright (C) 2005-2011 Red Hat Inc. |
f4b28491 FCE |
3 | // |
4 | // This file is part of systemtap, and is free software. You can | |
5 | // redistribute it and/or modify it under the terms of the GNU General | |
6 | // Public License (GPL); either version 2, or (at your option) any | |
7 | // later version. | |
8 | ||
9 | #include "config.h" | |
10 | #include "buildrun.h" | |
dc38c0ae | 11 | #include "session.h" |
72dbc915 | 12 | #include "util.h" |
7d26ee02 | 13 | #include "hash.h" |
f4b28491 | 14 | |
3b579393 | 15 | #include <cstdlib> |
f4b28491 | 16 | #include <fstream> |
d04cf5ff FCE |
17 | #include <sstream> |
18 | ||
19 | extern "C" { | |
49abf162 | 20 | #include <signal.h> |
0c6296b2 | 21 | #include <sys/wait.h> |
70404fc5 | 22 | #include <pwd.h> |
0da3e7a0 | 23 | #include <grp.h> |
b40af7ee DS |
24 | #include <sys/types.h> |
25 | #include <sys/stat.h> | |
26 | #include <unistd.h> | |
27 | #include <string.h> | |
28 | #include <errno.h> | |
d04cf5ff FCE |
29 | } |
30 | ||
f4b28491 FCE |
31 | |
32 | using namespace std; | |
33 | ||
6274464e JK |
34 | /* Adjust and run make_cmd to build a kernel module. */ |
35 | static int | |
ff520ff4 JS |
36 | run_make_cmd(systemtap_session& s, vector<string>& make_cmd, |
37 | bool null_out=false, bool null_err=false) | |
6274464e JK |
38 | { |
39 | // Before running make, fix up the environment a bit. PATH should | |
40 | // already be overridden. Clean out a few variables that | |
b5e66ada | 41 | // s.kernel_build_tree/Makefile uses. |
6274464e JK |
42 | int rc = unsetenv("ARCH") || unsetenv("KBUILD_EXTMOD") |
43 | || unsetenv("CROSS_COMPILE") || unsetenv("KBUILD_IMAGE") | |
44 | || unsetenv("KCONFIG_CONFIG") || unsetenv("INSTALL_PATH"); | |
45 | if (rc) | |
46 | { | |
47 | const char* e = strerror (errno); | |
48 | cerr << "unsetenv failed: " << e << endl; | |
3e1ec884 | 49 | s.set_try_server (); |
6274464e JK |
50 | } |
51 | ||
b51455af JS |
52 | // Disable ccache to avoid saving files that will never be reused. |
53 | // (ccache is useless to us, because our compiler commands always | |
54 | // include the randomized tmpdir path.) | |
55 | // It's not critical if this fails, so the return is ignored. | |
56 | (void) setenv("CCACHE_DISABLE", "1", 0); | |
57 | ||
b54581ce | 58 | if (s.verbose > 2) |
ff520ff4 | 59 | make_cmd.push_back("V=1"); |
b54581ce | 60 | else if (s.verbose > 1) |
ff520ff4 | 61 | make_cmd.push_back("--no-print-directory"); |
6274464e | 62 | else |
ff520ff4 JS |
63 | { |
64 | make_cmd.push_back("-s"); | |
65 | make_cmd.push_back("--no-print-directory"); | |
66 | } | |
dff50e09 | 67 | |
9fa0ffac FCE |
68 | // NB: there appears to be no parallelism opportunity in the |
69 | // module-building makefiles, so while the following works, it | |
70 | // doesn't seem to accomplish anything measurable as of F13. | |
71 | #if 0 | |
72 | long smp = sysconf(_SC_NPROCESSORS_ONLN); | |
73 | if (smp > 1) | |
ff520ff4 | 74 | make_cmd.push_back("-j" + lex_cast(smp)); |
9fa0ffac FCE |
75 | #endif |
76 | ||
e0ccd368 FCE |
77 | if (strverscmp (s.kernel_base_release.c_str(), "2.6.29") < 0) |
78 | { | |
79 | // Older kernels, before linux commit #fd54f502841c1, include | |
80 | // gratuitous "echo"s in their Makefile. We need to suppress | |
81 | // that with this bluntness. | |
ff520ff4 | 82 | null_out = true; |
e0ccd368 FCE |
83 | } |
84 | ||
ff520ff4 | 85 | rc = stap_system (s.verbose, make_cmd, null_out, null_err); |
3e1ec884 DB |
86 | if (rc != 0) |
87 | s.set_try_server (); | |
88 | return rc; | |
6274464e | 89 | } |
f4b28491 | 90 | |
7d26ee02 JS |
91 | static vector<string> |
92 | make_make_cmd(systemtap_session& s, const string& dir) | |
93 | { | |
94 | vector<string> make_cmd; | |
95 | make_cmd.push_back("make"); | |
96 | make_cmd.push_back("-C"); | |
97 | make_cmd.push_back(s.kernel_build_tree); | |
98 | make_cmd.push_back("M=" + dir); // need make-quoting? | |
99 | make_cmd.push_back("modules"); | |
100 | ||
101 | // Add architecture, except for old powerpc (RHBZ669082) | |
102 | if (s.architecture != "powerpc" || | |
103 | (strverscmp (s.kernel_base_release.c_str(), "2.6.15") >= 0)) | |
104 | make_cmd.push_back("ARCH=" + s.architecture); // need make-quoting? | |
105 | ||
106 | // Add any custom kbuild flags | |
107 | make_cmd.insert(make_cmd.end(), s.kbuildflags.begin(), s.kbuildflags.end()); | |
108 | ||
109 | return make_cmd; | |
110 | } | |
111 | ||
de0db58a JS |
112 | static void |
113 | output_autoconf(systemtap_session& s, ofstream& o, const char *autoconf_c, | |
114 | const char *deftrue, const char *deffalse) | |
115 | { | |
116 | o << "\t"; | |
117 | if (s.verbose < 4) | |
118 | o << "@"; | |
119 | o << "if $(CHECK_BUILD) $(SYSTEMTAP_RUNTIME)/" << autoconf_c; | |
120 | if (s.verbose < 5) | |
121 | o << " > /dev/null 2>&1"; | |
122 | o << "; then "; | |
123 | if (deftrue) | |
124 | o << "echo \"#define " << deftrue << " 1\""; | |
125 | if (deffalse) | |
126 | o << "; else echo \"#define " << deffalse << " 1\""; | |
127 | o << "; fi >> $@" << endl; | |
128 | } | |
129 | ||
9e62f7ba FCE |
130 | |
131 | void output_exportconf(systemtap_session& s, ofstream& o, const char *symbol, | |
132 | const char *deftrue) | |
e25ab03c | 133 | { |
9e62f7ba FCE |
134 | o << "\t"; |
135 | if (s.verbose < 4) | |
136 | o << "@"; | |
137 | if (s.kernel_exports.find(symbol) != s.kernel_exports.end()) | |
138 | o << "echo \"#define " << deftrue << " 1\""; | |
139 | o << ">> $@" << endl; | |
e25ab03c WH |
140 | } |
141 | ||
9e62f7ba | 142 | |
f4b28491 FCE |
143 | int |
144 | compile_pass (systemtap_session& s) | |
145 | { | |
db3a383b JK |
146 | int rc = uprobes_pass (s); |
147 | if (rc) | |
3e1ec884 DB |
148 | { |
149 | s.set_try_server (); | |
150 | return rc; | |
151 | } | |
db3a383b | 152 | |
f4b28491 | 153 | // fill in a quick Makefile |
92ade41d FCE |
154 | string makefile_nm = s.tmpdir + "/Makefile"; |
155 | ofstream o (makefile_nm.c_str()); | |
92ade41d FCE |
156 | |
157 | // Create makefile | |
ed10c639 | 158 | |
255e4c68 | 159 | // Clever hacks copied from vmware modules |
ecf19454 FCE |
160 | string superverbose; |
161 | if (s.verbose > 3) | |
162 | superverbose = "set -x;"; | |
522518f1 | 163 | |
e9737939 MM |
164 | string redirecterrors = "> /dev/null 2>&1"; |
165 | if (s.verbose > 6) | |
166 | redirecterrors = ""; | |
167 | ||
e5976ba0 MH |
168 | // Support O= (or KBUILD_OUTPUT) option |
169 | o << "_KBUILD_CFLAGS := $(call flags,KBUILD_CFLAGS)" << endl; | |
170 | ||
ecf19454 | 171 | o << "stap_check_gcc = $(shell " << superverbose << " if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl; |
c72dd3c7 | 172 | o << "CHECK_BUILD := $(CC) $(KBUILD_CPPFLAGS) $(CPPFLAGS) $(LINUXINCLUDE) $(_KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) $(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\"" << (s.omit_werror ? "" : " -Werror") << " -S -o /dev/null -xc " << endl; |
de0db58a | 173 | o << "stap_check_build = $(shell " << superverbose << " if $(CHECK_BUILD) $(1) " << redirecterrors << " ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl; |
255e4c68 FCE |
174 | |
175 | o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl; | |
176 | ||
177 | // "autoconf" options go here | |
178 | ||
18222191 FCE |
179 | // RHBZ 543529: early rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules |
180 | o << "CONFIG_MODULE_SIG := n" << endl; | |
181 | ||
ecf19454 | 182 | string module_cflags = "EXTRA_CFLAGS"; |
522518f1 | 183 | o << module_cflags << " :=" << endl; |
84c4da88 FCE |
184 | |
185 | // XXX: This gruesome hack is needed on some kernels built with separate O=directory, | |
186 | // where files like 2.6.27 x86's asm/mach-*/mach_mpspec.h are not found on the cpp path. | |
187 | // This could be a bug in arch/x86/Makefile that names | |
188 | // mflags-y += -Iinclude/asm-x86/mach-default | |
189 | // but that path does not exist in an O= build tree. | |
190 | o << module_cflags << " += -Iinclude2/asm/mach-default" << endl; | |
d4393459 FCE |
191 | if (s.kernel_source_tree != "") |
192 | o << module_cflags << " += -I" + s.kernel_source_tree << endl; | |
84c4da88 | 193 | |
6046b840 FCE |
194 | // NB: don't try |
195 | // o << module_cflags << " += -Iusr/include" << endl; | |
196 | // since such headers are cleansed of _KERNEL_ pieces that we need | |
197 | ||
de0db58a JS |
198 | o << "STAPCONF_HEADER := " << s.tmpdir << "/" << s.stapconf_name << endl; |
199 | o << s.translated_source << ": $(STAPCONF_HEADER)" << endl; | |
200 | o << "$(STAPCONF_HEADER):" << endl; | |
201 | o << "\t@echo -n > $@" << endl; | |
202 | output_autoconf(s, o, "autoconf-hrtimer-rel.c", "STAPCONF_HRTIMER_REL", NULL); | |
203 | output_autoconf(s, o, "autoconf-hrtimer-getset-expires.c", "STAPCONF_HRTIMER_GETSET_EXPIRES", NULL); | |
204 | output_autoconf(s, o, "autoconf-inode-private.c", "STAPCONF_INODE_PRIVATE", NULL); | |
205 | output_autoconf(s, o, "autoconf-constant-tsc.c", "STAPCONF_CONSTANT_TSC", NULL); | |
de0db58a JS |
206 | output_autoconf(s, o, "autoconf-ktime-get-real.c", "STAPCONF_KTIME_GET_REAL", NULL); |
207 | output_autoconf(s, o, "autoconf-x86-uniregs.c", "STAPCONF_X86_UNIREGS", NULL); | |
208 | output_autoconf(s, o, "autoconf-nameidata.c", "STAPCONF_NAMEIDATA_CLEANUP", NULL); | |
209 | output_autoconf(s, o, "autoconf-unregister-kprobes.c", "STAPCONF_UNREGISTER_KPROBES", NULL); | |
210 | output_autoconf(s, o, "autoconf-real-parent.c", "STAPCONF_REAL_PARENT", NULL); | |
211 | output_autoconf(s, o, "autoconf-uaccess.c", "STAPCONF_LINUX_UACCESS_H", NULL); | |
212 | output_autoconf(s, o, "autoconf-oneachcpu-retry.c", "STAPCONF_ONEACHCPU_RETRY", NULL); | |
213 | output_autoconf(s, o, "autoconf-dpath-path.c", "STAPCONF_DPATH_PATH", NULL); | |
214 | output_autoconf(s, o, "autoconf-synchronize-sched.c", "STAPCONF_SYNCHRONIZE_SCHED", NULL); | |
215 | output_autoconf(s, o, "autoconf-task-uid.c", "STAPCONF_TASK_UID", NULL); | |
216 | output_autoconf(s, o, "autoconf-vm-area.c", "STAPCONF_VM_AREA", NULL); | |
217 | output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL); | |
b1f85b93 | 218 | output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL); |
5cad2d3b | 219 | output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL); |
f098eb6d | 220 | output_autoconf(s, o, "autoconf-grsecurity.c", "STAPCONF_GRSECURITY", NULL); |
450718c9 | 221 | output_autoconf(s, o, "autoconf-trace-printk.c", "STAPCONF_TRACE_PRINTK", NULL); |
be004140 FCE |
222 | output_autoconf(s, o, "autoconf-regset.c", "STAPCONF_REGSET", NULL); |
223 | output_autoconf(s, o, "autoconf-utrace-regset.c", "STAPCONF_UTRACE_REGSET", NULL); | |
23258335 | 224 | output_autoconf(s, o, "autoconf-uprobe-get-pc.c", "STAPCONF_UPROBE_GET_PC", NULL); |
b09417ad | 225 | output_exportconf(s, o, "tsc_khz", "STAPCONF_TSC_KHZ"); |
9e62f7ba | 226 | output_exportconf(s, o, "cpu_khz", "STAPCONF_CPU_KHZ"); |
031fda59 | 227 | output_exportconf(s, o, "__module_text_address", "STAPCONF_MODULE_TEXT_ADDRESS"); |
af6c651f | 228 | output_exportconf(s, o, "add_timer_on", "STAPCONF_ADD_TIMER_ON"); |
8d59b39f | 229 | |
de0db58a | 230 | output_autoconf(s, o, "autoconf-probe-kernel.c", "STAPCONF_PROBE_KERNEL", NULL); |
8c5905d0 TM |
231 | output_autoconf(s, o, "autoconf-save-stack-trace.c", |
232 | "STAPCONF_KERNEL_STACKTRACE", NULL); | |
d5cd287f DS |
233 | output_autoconf(s, o, "autoconf-asm-syscall.c", |
234 | "STAPCONF_ASM_SYSCALL_H", NULL); | |
c145b9cb | 235 | output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL); |
03a4ec63 | 236 | output_autoconf(s, o, "autoconf-kallsyms-on-each-symbol.c", "STAPCONF_KALLSYMS_ON_EACH_SYMBOL", NULL); |
c265cd25 | 237 | output_autoconf(s, o, "autoconf-walk-stack.c", "STAPCONF_WALK_STACK", NULL); |
0bbb8009 JS |
238 | output_autoconf(s, o, "autoconf-stacktrace_ops-warning.c", |
239 | "STAPCONF_STACKTRACE_OPS_WARNING", NULL); | |
18da5887 | 240 | output_autoconf(s, o, "autoconf-mm-context-vdso.c", "STAPCONF_MM_CONTEXT_VDSO", NULL); |
c1d2d085 | 241 | output_autoconf(s, o, "autoconf-blk-types.c", "STAPCONF_BLK_TYPES", NULL); |
aec17ca6 | 242 | output_autoconf(s, o, "autoconf-perf-structpid.c", "STAPCONF_PERF_STRUCTPID", NULL); |
c6d523a7 DS |
243 | output_autoconf(s, o, "autoconf-kern-path-parent.c", |
244 | "STAPCONF_KERN_PATH_PARENT", NULL); | |
255e4c68 | 245 | |
de0db58a | 246 | o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl; |
5c54d49e | 247 | |
ed10c639 | 248 | for (unsigned i=0; i<s.macros.size(); i++) |
ff520ff4 | 249 | o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl; // XXX right quoting? |
ed10c639 | 250 | |
e4c58386 | 251 | if (s.verbose > 3) |
0986ac38 | 252 | o << "EXTRA_CFLAGS += -ftime-report -Q" << endl; |
db22e55f | 253 | |
ee6dda6f FCE |
254 | // XXX: unfortunately, -save-temps can't work since linux kbuild cwd |
255 | // is not writeable. | |
256 | // | |
257 | // if (s.keep_tmpdir) | |
258 | // o << "CFLAGS += -fverbose-asm -save-temps" << endl; | |
259 | ||
ec6fdef5 MW |
260 | // Kernels can be compiled with CONFIG_CC_OPTIMIZE_FOR_SIZE to select |
261 | // -Os, otherwise -O2 is the default. | |
262 | o << "EXTRA_CFLAGS += -freorder-blocks" << endl; // improve on -Os | |
263 | ||
01116596 MW |
264 | // We used to allow the user to override default optimization when so |
265 | // requested by adding a -O[0123s] so they could determine the | |
266 | // time/space/speed tradeoffs themselves, but we cannot guantantee that | |
267 | // the (un)optimized code actually compiles and/or generates functional | |
268 | // code, so we had to remove it. | |
269 | // o << "EXTRA_CFLAGS += " << s.gcc_flags << endl; // Add -O[0123s] | |
35d4ab18 FCE |
270 | |
271 | // o << "CFLAGS += -fno-unit-at-a-time" << endl; | |
dff50e09 | 272 | |
01a2eba8 JS |
273 | // 256 bytes should be enough for anybody |
274 | // XXX this doesn't validate varargs, per gcc bug #41633 | |
275 | o << "EXTRA_CFLAGS += $(call cc-option,-Wframe-larger-than=256)" << endl; | |
730c3efc | 276 | |
cbfbbf69 | 277 | // Assumes linux 2.6 kbuild |
c72dd3c7 | 278 | o << "EXTRA_CFLAGS += -Wno-unused" << (s.omit_werror ? "" : " -Werror") << endl; |
29bdbdb1 FCE |
279 | #if CHECK_POINTER_ARITH_PR5947 |
280 | o << "EXTRA_CFLAGS += -Wpointer-arith" << endl; | |
281 | #endif | |
0986ac38 | 282 | o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl; |
4b2c4ab5 FCE |
283 | // XXX: this may help ppc toc overflow |
284 | // o << "CFLAGS := $(subst -Os,-O2,$(CFLAGS)) -fminimal-toc" << endl; | |
cbfbbf69 | 285 | o << "obj-m := " << s.module_name << ".o" << endl; |
f4b28491 | 286 | |
ed10c639 FCE |
287 | o.close (); |
288 | ||
b40af7ee | 289 | // Generate module directory pathname and make sure it exists. |
4d34dac1 FCE |
290 | string module_dir = s.kernel_build_tree; |
291 | string module_dir_makefile = module_dir + "/Makefile"; | |
b40af7ee | 292 | struct stat st; |
4d34dac1 | 293 | rc = stat(module_dir_makefile.c_str(), &st); |
b40af7ee DS |
294 | if (rc != 0) |
295 | { | |
ce0f6648 | 296 | clog << _F("Checking \" %s \" failed with error: %s\nEnsure kernel development headers & makefiles are installed.", |
46a1a151 | 297 | module_dir_makefile.c_str(), strerror(errno)) << endl; |
3e1ec884 | 298 | s.set_try_server (); |
b40af7ee | 299 | return rc; |
dff50e09 | 300 | } |
b40af7ee DS |
301 | |
302 | // Run make | |
7d26ee02 | 303 | vector<string> make_cmd = make_make_cmd(s, s.tmpdir); |
6274464e | 304 | rc = run_make_cmd(s, make_cmd); |
3e1ec884 DB |
305 | if (rc) |
306 | s.set_try_server (); | |
f4b28491 FCE |
307 | return rc; |
308 | } | |
309 | ||
db3a383b JK |
310 | /* |
311 | * If uprobes was built as part of the kernel build (either built-in | |
dbb9345d FCE |
312 | * or as a module), the uprobes exports should show up. This is to be |
313 | * as distinct from the stap-built uprobes.ko from the runtime. | |
db3a383b JK |
314 | */ |
315 | static bool | |
316 | kernel_built_uprobes (systemtap_session& s) | |
6274464e | 317 | { |
dbb9345d | 318 | return (s.kernel_exports.find("unregister_uprobe") != s.kernel_exports.end()); |
6274464e JK |
319 | } |
320 | ||
7d26ee02 JS |
321 | static int |
322 | make_uprobes (systemtap_session& s) | |
6274464e | 323 | { |
7ef486ad | 324 | if (s.verbose > 1) |
7d26ee02 | 325 | clog << _("Pass 4, preamble: (re)building SystemTap's version of uprobes.") |
db3a383b JK |
326 | << endl; |
327 | ||
7d26ee02 JS |
328 | // create a subdirectory for the uprobes module |
329 | string dir(s.tmpdir + "/uprobes"); | |
330 | if (create_dir(dir.c_str()) != 0) | |
331 | { | |
332 | if (! s.suppress_warnings) | |
333 | cerr << _("Warning: failed to create directory for build uprobes.") << endl; | |
334 | s.set_try_server (); | |
335 | return 1; | |
0da3e7a0 | 336 | } |
6274464e | 337 | |
7d26ee02 JS |
338 | // create a simple Makefile |
339 | string makefile(dir + "/Makefile"); | |
340 | ofstream omf(makefile.c_str()); | |
341 | omf << "obj-m := uprobes.o" << endl; | |
342 | // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules | |
343 | omf << "CONFIG_MODULE_SIG := n" << endl; | |
344 | omf.close(); | |
6274464e | 345 | |
7d26ee02 JS |
346 | // create a simple #include-chained source file |
347 | string runtimesourcefile(s.runtime_path + "/uprobes/uprobes.c"); | |
348 | string sourcefile(dir + "/uprobes.c"); | |
349 | ofstream osrc(sourcefile.c_str()); | |
350 | osrc << "#include \"" << runtimesourcefile << "\"" << endl; | |
351 | osrc.close(); | |
352 | ||
353 | // make the module | |
354 | vector<string> make_cmd = make_make_cmd(s, dir); | |
355 | bool quiet = (s.verbose < 4); | |
356 | int rc = run_make_cmd(s, make_cmd, quiet, quiet); | |
357 | if (!rc && !copy_file(dir + "/Module.symvers", | |
358 | s.tmpdir + "/Module.symvers")) | |
359 | rc = -1; | |
6274464e | 360 | |
f4d5049b | 361 | if (s.verbose > 1) |
ce0f6648 | 362 | clog << _("uprobes rebuild exit code: ") << rc << endl; |
3e1ec884 DB |
363 | if (rc) |
364 | s.set_try_server (); | |
7d26ee02 JS |
365 | else |
366 | s.uprobes_path = dir + "/uprobes.ko"; | |
6274464e JK |
367 | return rc; |
368 | } | |
369 | ||
7d26ee02 JS |
370 | static bool |
371 | get_cached_uprobes(systemtap_session& s) | |
372 | { | |
373 | s.uprobes_hash = s.use_cache ? find_uprobes_hash(s) : ""; | |
374 | if (!s.uprobes_hash.empty()) | |
375 | { | |
376 | // NB: We always put uprobes.ko in its own directory, especially so | |
377 | // stap-serverd can more easily locate it. | |
378 | string dir(s.tmpdir + "/uprobes"); | |
379 | if (create_dir(dir.c_str()) != 0) | |
380 | return false; | |
381 | ||
382 | string cacheko = s.uprobes_hash + ".ko"; | |
383 | string tmpko = dir + "/uprobes.ko"; | |
384 | ||
385 | // The symvers file still needs to go in the script module's directory. | |
386 | string cachesyms = s.uprobes_hash + ".symvers"; | |
387 | string tmpsyms = s.tmpdir + "/Module.symvers"; | |
388 | ||
389 | if (get_file_size(cacheko) > 0 && copy_file(cacheko, tmpko) && | |
390 | get_file_size(cachesyms) > 0 && copy_file(cachesyms, tmpsyms)) | |
391 | { | |
392 | s.uprobes_path = tmpko; | |
393 | return true; | |
394 | } | |
395 | } | |
396 | return false; | |
397 | } | |
398 | ||
399 | static void | |
400 | set_cached_uprobes(systemtap_session& s) | |
db3a383b | 401 | { |
7d26ee02 JS |
402 | if (s.use_cache && !s.uprobes_hash.empty()) |
403 | { | |
404 | string cacheko = s.uprobes_hash + ".ko"; | |
405 | string tmpko = s.tmpdir + "/uprobes/uprobes.ko"; | |
406 | copy_file(tmpko, cacheko); | |
36ef6d6a | 407 | |
7d26ee02 JS |
408 | string cachesyms = s.uprobes_hash + ".symvers"; |
409 | string tmpsyms = s.tmpdir + "/uprobes/Module.symvers"; | |
410 | copy_file(tmpsyms, cachesyms); | |
411 | } | |
db3a383b JK |
412 | } |
413 | ||
7d26ee02 | 414 | int |
db3a383b JK |
415 | uprobes_pass (systemtap_session& s) |
416 | { | |
417 | if (!s.need_uprobes || kernel_built_uprobes(s)) | |
418 | return 0; | |
0944a81e FCE |
419 | |
420 | if (s.kernel_config["CONFIG_UTRACE"] != string("y")) { | |
94d05135 | 421 | clog << _("user-space facilities not available without kernel CONFIG_UTRACE") << endl; |
3e1ec884 | 422 | s.set_try_server (); |
0944a81e FCE |
423 | return 1; |
424 | } | |
425 | ||
db3a383b | 426 | /* |
7d26ee02 JS |
427 | * We need to use the version of uprobes that comes with SystemTap. Try to |
428 | * get it from the cache first. If not found, build it and try to save it to | |
429 | * the cache for future reuse. | |
db3a383b | 430 | */ |
7d26ee02 JS |
431 | int rc = 0; |
432 | if (!get_cached_uprobes(s)) | |
433 | { | |
434 | rc = make_uprobes(s); | |
435 | if (!rc) | |
436 | set_cached_uprobes(s); | |
437 | } | |
3e1ec884 DB |
438 | if (rc) |
439 | s.set_try_server (); | |
db3a383b JK |
440 | return rc; |
441 | } | |
442 | ||
5eea6ed1 | 443 | vector<string> |
4112f219 JS |
444 | make_run_command (systemtap_session& s, const string& module, |
445 | const string& version) | |
f4b28491 | 446 | { |
a63a95dc | 447 | // for now, just spawn staprun |
5eea6ed1 JS |
448 | vector<string> staprun_cmd; |
449 | staprun_cmd.push_back(getenv("SYSTEMTAP_STAPRUN") ?: BINDIR "/staprun"); | |
450 | if (s.verbose>1) | |
451 | staprun_cmd.push_back("-v"); | |
452 | if (s.verbose>2) | |
453 | staprun_cmd.push_back("-v"); | |
454 | if (s.suppress_warnings) | |
455 | staprun_cmd.push_back("-w"); | |
456 | ||
457 | if (!s.output_file.empty()) | |
458 | { | |
459 | staprun_cmd.push_back("-o"); | |
460 | staprun_cmd.push_back(s.output_file); | |
461 | } | |
dff50e09 | 462 | |
5eea6ed1 JS |
463 | if (!s.cmd.empty()) |
464 | { | |
465 | staprun_cmd.push_back("-c"); | |
466 | staprun_cmd.push_back(s.cmd); | |
467 | } | |
dff50e09 | 468 | |
cbfbbf69 | 469 | if (s.target_pid) |
5eea6ed1 JS |
470 | { |
471 | staprun_cmd.push_back("-t"); | |
472 | staprun_cmd.push_back(lex_cast(s.target_pid)); | |
473 | } | |
dff50e09 | 474 | |
cbfbbf69 | 475 | if (s.buffer_size) |
5eea6ed1 JS |
476 | { |
477 | staprun_cmd.push_back("-b"); | |
478 | staprun_cmd.push_back(lex_cast(s.buffer_size)); | |
479 | } | |
dff50e09 | 480 | |
6274464e | 481 | if (s.need_uprobes) |
5eea6ed1 JS |
482 | { |
483 | staprun_cmd.push_back("-u"); | |
484 | if (!s.uprobes_path.empty()) | |
e3d0ec49 | 485 | staprun_cmd.back().append(s.uprobes_path); |
5eea6ed1 | 486 | } |
6274464e | 487 | |
2fa2a091 | 488 | if (s.load_only) |
5eea6ed1 | 489 | staprun_cmd.push_back(s.output_file.empty() ? "-L" : "-D"); |
701c41be | 490 | |
4112f219 | 491 | if(!s.modname_given && (strverscmp("1.6", version.c_str()) <= 0)) |
5c854d7c CM |
492 | staprun_cmd.push_back("-R"); |
493 | ||
701c41be | 494 | if (!s.size_option.empty()) |
5eea6ed1 JS |
495 | { |
496 | staprun_cmd.push_back("-S"); | |
497 | staprun_cmd.push_back(s.size_option); | |
498 | } | |
2fa2a091 | 499 | |
daa75206 | 500 | if (module.empty()) |
5eea6ed1 | 501 | staprun_cmd.push_back(s.tmpdir + "/" + s.module_name + ".ko"); |
daa75206 | 502 | else |
5eea6ed1 | 503 | staprun_cmd.push_back(module); |
dff50e09 | 504 | |
bb25d08f | 505 | // add module arguments |
5eea6ed1 JS |
506 | staprun_cmd.insert(staprun_cmd.end(), |
507 | s.globalopts.begin(), s.globalopts.end()); | |
bb25d08f | 508 | |
daa75206 | 509 | return staprun_cmd; |
f4b28491 | 510 | } |
73267b89 | 511 | |
0a6f5a3f JS |
512 | |
513 | // Build a tiny kernel module to query tracepoints | |
514 | int | |
f982c59b | 515 | make_tracequery(systemtap_session& s, string& name, |
d4393459 | 516 | const vector<string>& decls) |
0a6f5a3f | 517 | { |
f982c59b | 518 | static unsigned tick = 0; |
aca66a36 | 519 | string basename("tracequery_kmod_" + lex_cast(++tick)); |
f982c59b | 520 | |
0a6f5a3f | 521 | // create a subdirectory for the module |
f982c59b | 522 | string dir(s.tmpdir + "/" + basename); |
0a6f5a3f JS |
523 | if (create_dir(dir.c_str()) != 0) |
524 | { | |
525 | if (! s.suppress_warnings) | |
94d05135 | 526 | cerr << _("Warning: failed to create directory for querying tracepoints.") << endl; |
3e1ec884 | 527 | s.set_try_server (); |
0a6f5a3f JS |
528 | return 1; |
529 | } | |
530 | ||
f982c59b | 531 | name = dir + "/" + basename + ".ko"; |
0a6f5a3f JS |
532 | |
533 | // create a simple Makefile | |
534 | string makefile(dir + "/Makefile"); | |
535 | ofstream omf(makefile.c_str()); | |
9ccda279 | 536 | // force debuginfo generation, and relax implicit functions |
c72dd3c7 | 537 | omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration" << (s.omit_werror ? "" : " -Werror") << endl; |
d4393459 FCE |
538 | if (s.kernel_source_tree != "") |
539 | omf << "EXTRA_CFLAGS += -I" + s.kernel_source_tree << endl; | |
f982c59b | 540 | omf << "obj-m := " + basename + ".o" << endl; |
a7ec2317 FCE |
541 | |
542 | // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules | |
543 | omf << "CONFIG_MODULE_SIG := n" << endl; | |
544 | ||
0a6f5a3f JS |
545 | omf.close(); |
546 | ||
547 | // create our source file | |
f982c59b | 548 | string source(dir + "/" + basename + ".c"); |
0a6f5a3f | 549 | ofstream osrc(source.c_str()); |
0a6f5a3f JS |
550 | osrc << "#ifdef CONFIG_TRACEPOINTS" << endl; |
551 | osrc << "#include <linux/tracepoint.h>" << endl; | |
552 | ||
553 | // override DECLARE_TRACE to synthesize probe functions for us | |
554 | osrc << "#undef DECLARE_TRACE" << endl; | |
555 | osrc << "#define DECLARE_TRACE(name, proto, args) \\" << endl; | |
556 | osrc << " void stapprobe_##name(proto) {}" << endl; | |
557 | ||
5f73a260 JS |
558 | // 2.6.35 added the NOARGS variant, but it's the same for us |
559 | osrc << "#undef DECLARE_TRACE_NOARGS" << endl; | |
560 | osrc << "#define DECLARE_TRACE_NOARGS(name) \\" << endl; | |
561 | osrc << " DECLARE_TRACE(name, void, )" << endl; | |
562 | ||
d99d8819 JS |
563 | // older tracepoints used DEFINE_TRACE, so redirect that too |
564 | osrc << "#undef DEFINE_TRACE" << endl; | |
565 | osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl; | |
566 | osrc << " DECLARE_TRACE(name, TPPROTO(proto), TPARGS(args))" << endl; | |
567 | ||
d4393459 FCE |
568 | // add the specified decls/#includes |
569 | for (unsigned z=0; z<decls.size(); z++) | |
915ad99a | 570 | osrc << "#undef TRACE_INCLUDE_FILE\n" |
d4393459 FCE |
571 | << "#undef TRACE_INCLUDE_PATH\n" |
572 | << decls[z] << "\n"; | |
0a6f5a3f JS |
573 | |
574 | // finish up the module source | |
575 | osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl; | |
0a6f5a3f JS |
576 | osrc.close(); |
577 | ||
578 | // make the module | |
7d26ee02 | 579 | vector<string> make_cmd = make_make_cmd(s, dir); |
ff520ff4 JS |
580 | bool quiet = (s.verbose < 4); |
581 | int rc = run_make_cmd(s, make_cmd, quiet, quiet); | |
3e1ec884 DB |
582 | if (rc) |
583 | s.set_try_server (); | |
584 | return rc; | |
0a6f5a3f JS |
585 | } |
586 | ||
3e1c25aa JS |
587 | |
588 | // Build a tiny kernel module to query type information | |
d90053e7 | 589 | static int |
da9e11bd | 590 | make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string& name) |
3e1c25aa JS |
591 | { |
592 | static unsigned tick = 0; | |
aca66a36 | 593 | string basename("typequery_kmod_" + lex_cast(++tick)); |
3e1c25aa JS |
594 | |
595 | // create a subdirectory for the module | |
596 | string dir(s.tmpdir + "/" + basename); | |
597 | if (create_dir(dir.c_str()) != 0) | |
598 | { | |
599 | if (! s.suppress_warnings) | |
94d05135 | 600 | cerr << _("Warning: failed to create directory for querying types.") << endl; |
3e1ec884 | 601 | s.set_try_server (); |
3e1c25aa JS |
602 | return 1; |
603 | } | |
604 | ||
605 | name = dir + "/" + basename + ".ko"; | |
606 | ||
607 | // create a simple Makefile | |
608 | string makefile(dir + "/Makefile"); | |
609 | ofstream omf(makefile.c_str()); | |
610 | omf << "EXTRA_CFLAGS := -g -fno-eliminate-unused-debug-types" << endl; | |
3ae4cdf9 | 611 | |
a7ec2317 FCE |
612 | // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules |
613 | omf << "CONFIG_MODULE_SIG := n" << endl; | |
614 | ||
3ae4cdf9 JS |
615 | // NB: We use -include instead of #include because that gives us more power. |
616 | // Using #include searches relative to the source's path, which in this case | |
617 | // is /tmp/..., so that's not helpful. Using -include will search relative | |
618 | // to the cwd, which will be the kernel build root. This means if you have a | |
619 | // full kernel build tree, it's possible to get at types that aren't in the | |
620 | // normal include path, e.g.: | |
621 | // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->... | |
da9e11bd JS |
622 | omf << "CFLAGS_" << basename << ".o :="; |
623 | for (size_t i = 0; i < headers.size(); ++i) | |
ff520ff4 | 624 | omf << " -include " << lex_cast_qstring(headers[i]); // XXX right quoting? |
da9e11bd | 625 | omf << endl; |
3ae4cdf9 | 626 | |
3e1c25aa JS |
627 | omf << "obj-m := " + basename + ".o" << endl; |
628 | omf.close(); | |
629 | ||
630 | // create our empty source file | |
631 | string source(dir + "/" + basename + ".c"); | |
632 | ofstream osrc(source.c_str()); | |
633 | osrc.close(); | |
634 | ||
635 | // make the module | |
7d26ee02 | 636 | vector<string> make_cmd = make_make_cmd(s, dir); |
ff520ff4 JS |
637 | bool quiet = (s.verbose < 4); |
638 | int rc = run_make_cmd(s, make_cmd, quiet, quiet); | |
3e1ec884 DB |
639 | if (rc) |
640 | s.set_try_server (); | |
641 | return rc; | |
3e1c25aa JS |
642 | } |
643 | ||
644 | ||
645 | // Build a tiny user module to query type information | |
d90053e7 | 646 | static int |
da9e11bd | 647 | make_typequery_umod(systemtap_session& s, const vector<string>& headers, string& name) |
3e1c25aa JS |
648 | { |
649 | static unsigned tick = 0; | |
650 | ||
aca66a36 | 651 | name = s.tmpdir + "/typequery_umod_" + lex_cast(++tick) + ".so"; |
3e1c25aa JS |
652 | |
653 | // make the module | |
3ae4cdf9 JS |
654 | // |
655 | // NB: As with kmod, using -include makes relative paths more useful. The | |
656 | // cwd in this case will be the cwd of stap itself though, which may be | |
657 | // trickier to deal with. It might be better to "cd `dirname $script`" | |
658 | // first... | |
ff520ff4 JS |
659 | vector<string> cmd; |
660 | cmd.push_back("gcc"); | |
661 | cmd.push_back("-shared"); | |
662 | cmd.push_back("-g"); | |
663 | cmd.push_back("-fno-eliminate-unused-debug-types"); | |
664 | cmd.push_back("-xc"); | |
665 | cmd.push_back("/dev/null"); | |
666 | cmd.push_back("-o"); | |
667 | cmd.push_back(name); | |
da9e11bd | 668 | for (size_t i = 0; i < headers.size(); ++i) |
ff520ff4 JS |
669 | { |
670 | cmd.push_back("-include"); | |
671 | cmd.push_back(headers[i]); | |
672 | } | |
673 | bool quiet = (s.verbose < 4); | |
674 | int rc = stap_system (s.verbose, cmd, quiet, quiet); | |
3e1ec884 DB |
675 | if (rc) |
676 | s.set_try_server (); | |
677 | return rc; | |
3e1c25aa JS |
678 | } |
679 | ||
d90053e7 JS |
680 | |
681 | int | |
682 | make_typequery(systemtap_session& s, string& module) | |
683 | { | |
684 | int rc; | |
685 | string new_module; | |
da9e11bd | 686 | vector<string> headers; |
60d98537 | 687 | bool kernel = startswith(module, "kernel"); |
d90053e7 | 688 | |
da9e11bd | 689 | for (size_t end, i = kernel ? 6 : 0; i < module.size(); i = end + 1) |
d90053e7 | 690 | { |
da9e11bd JS |
691 | if (module[i] != '<') |
692 | return -1; | |
693 | end = module.find('>', ++i); | |
694 | if (end == string::npos) | |
695 | return -1; | |
696 | string header = module.substr(i, end - i); | |
504d2b61 | 697 | vector<string> matches; |
5ef28d5a | 698 | if (regexp_match(header, "^[a-zA-Z0-9/_.+-]+$", matches)) |
504d2b61 JS |
699 | { |
700 | if (! s.suppress_warnings) | |
e5f690c7 | 701 | cerr << _F("Warning: skipping malformed @cast header \"%s\"", |
ce0f6648 | 702 | header.c_str()) << endl; |
504d2b61 JS |
703 | } |
704 | else | |
705 | headers.push_back(header); | |
d90053e7 | 706 | } |
da9e11bd | 707 | if (headers.empty()) |
d90053e7 JS |
708 | return -1; |
709 | ||
da9e11bd JS |
710 | if (kernel) |
711 | rc = make_typequery_kmod(s, headers, new_module); | |
712 | else | |
713 | rc = make_typequery_umod(s, headers, new_module); | |
714 | ||
d90053e7 JS |
715 | if (!rc) |
716 | module = new_module; | |
717 | ||
718 | return rc; | |
719 | } | |
720 | ||
73267b89 | 721 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |