]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // build/run probes |
04ffc218 | 2 | // Copyright (C) 2005-2014 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" |
a4b9c3b3 | 14 | #include "translate.h" |
f4b28491 | 15 | |
3b579393 | 16 | #include <cstdlib> |
f4b28491 | 17 | #include <fstream> |
d04cf5ff FCE |
18 | #include <sstream> |
19 | ||
20 | extern "C" { | |
49abf162 | 21 | #include <signal.h> |
0c6296b2 | 22 | #include <sys/wait.h> |
70404fc5 | 23 | #include <pwd.h> |
0da3e7a0 | 24 | #include <grp.h> |
b40af7ee DS |
25 | #include <sys/types.h> |
26 | #include <sys/stat.h> | |
27 | #include <unistd.h> | |
28 | #include <string.h> | |
29 | #include <errno.h> | |
3c4476ac | 30 | #include <sys/resource.h> |
d04cf5ff FCE |
31 | } |
32 | ||
2537a880 JS |
33 | // A bit of obfuscation for Gentoo's sake. |
34 | // We *need* -Werror for stapconf to work correctly. | |
b586ab77 | 35 | // https://bugs.gentoo.org/show_bug.cgi?id=522908 |
2537a880 | 36 | #define WERROR ("-W" "error") |
f4b28491 FCE |
37 | |
38 | using namespace std; | |
39 | ||
6274464e JK |
40 | /* Adjust and run make_cmd to build a kernel module. */ |
41 | static int | |
ff520ff4 JS |
42 | run_make_cmd(systemtap_session& s, vector<string>& make_cmd, |
43 | bool null_out=false, bool null_err=false) | |
6274464e | 44 | { |
e19ebcf7 | 45 | assert_no_interrupts(); |
576acc1a | 46 | |
e8474d2a FCE |
47 | // PR14168: we used to unsetenv values here; instead do it via |
48 | // env(1) in make_any_make_cmd(). | |
6274464e | 49 | |
b51455af JS |
50 | // Disable ccache to avoid saving files that will never be reused. |
51 | // (ccache is useless to us, because our compiler commands always | |
52 | // include the randomized tmpdir path.) | |
53 | // It's not critical if this fails, so the return is ignored. | |
54 | (void) setenv("CCACHE_DISABLE", "1", 0); | |
55 | ||
b54581ce | 56 | if (s.verbose > 2) |
ff520ff4 | 57 | make_cmd.push_back("V=1"); |
b54581ce | 58 | else if (s.verbose > 1) |
ff520ff4 | 59 | make_cmd.push_back("--no-print-directory"); |
6274464e | 60 | else |
ff520ff4 JS |
61 | { |
62 | make_cmd.push_back("-s"); | |
63 | make_cmd.push_back("--no-print-directory"); | |
64 | } | |
dff50e09 | 65 | |
70fb16aa | 66 | // Exploit SMP parallelism, if available. |
9fa0ffac | 67 | long smp = sysconf(_SC_NPROCESSORS_ONLN); |
3c4476ac FCE |
68 | if (smp <= 0) smp = 1; |
69 | // PR16276: but only if we're not running severely nproc-rlimited | |
70 | struct rlimit rlim; | |
71 | int rlimit_rc = getrlimit(RLIMIT_NPROC, &rlim); | |
5dd70393 | 72 | const unsigned int severely_limited = smp*30; // WAG at number of gcc+make etc. nested processes |
3c4476ac FCE |
73 | bool nproc_limited = (rlimit_rc == 0 && (rlim.rlim_max <= severely_limited || |
74 | rlim.rlim_cur <= severely_limited)); | |
75 | if (smp >= 1 && !nproc_limited) | |
70fb16aa | 76 | make_cmd.push_back("-j" + lex_cast(smp+1)); |
9fa0ffac | 77 | |
e0ccd368 FCE |
78 | if (strverscmp (s.kernel_base_release.c_str(), "2.6.29") < 0) |
79 | { | |
80 | // Older kernels, before linux commit #fd54f502841c1, include | |
81 | // gratuitous "echo"s in their Makefile. We need to suppress | |
82 | // that with this bluntness. | |
ff520ff4 | 83 | null_out = true; |
e0ccd368 FCE |
84 | } |
85 | ||
b13c6a37 | 86 | int rc = stap_system (s.verbose, "kbuild", make_cmd, null_out, null_err); |
3e1ec884 DB |
87 | if (rc != 0) |
88 | s.set_try_server (); | |
89 | return rc; | |
6274464e | 90 | } |
f4b28491 | 91 | |
7d26ee02 | 92 | static vector<string> |
8e0a2563 | 93 | make_any_make_cmd(systemtap_session& s, const string& dir, const string& target) |
7d26ee02 JS |
94 | { |
95 | vector<string> make_cmd; | |
e8474d2a FCE |
96 | |
97 | // PR14168: sanitize environment variables for kbuild invocation | |
98 | make_cmd.push_back("env"); | |
99 | make_cmd.push_back("-uARCH"); | |
100 | make_cmd.push_back("-uKBUILD_EXTMOD"); | |
101 | make_cmd.push_back("-uCROSS_COMPILE"); | |
102 | make_cmd.push_back("-uKBUILD_IMAGE"); | |
103 | make_cmd.push_back("-uKCONFIG_CONFIG"); | |
104 | make_cmd.push_back("-uINSTALL_PATH"); | |
105 | string newpath = string("PATH=/usr/bin:/bin:") + (getenv("PATH") ?: ""); | |
106 | make_cmd.push_back(newpath.c_str()); | |
107 | ||
7d26ee02 JS |
108 | make_cmd.push_back("make"); |
109 | make_cmd.push_back("-C"); | |
110 | make_cmd.push_back(s.kernel_build_tree); | |
111 | make_cmd.push_back("M=" + dir); // need make-quoting? | |
8e0a2563 | 112 | make_cmd.push_back(target); |
7d26ee02 JS |
113 | |
114 | // Add architecture, except for old powerpc (RHBZ669082) | |
115 | if (s.architecture != "powerpc" || | |
116 | (strverscmp (s.kernel_base_release.c_str(), "2.6.15") >= 0)) | |
117 | make_cmd.push_back("ARCH=" + s.architecture); // need make-quoting? | |
118 | ||
150f2075 FCE |
119 | // PR13847: suppress debuginfo creation by default |
120 | make_cmd.insert(make_cmd.end(), "CONFIG_DEBUG_INFO="); | |
121 | ||
7d26ee02 JS |
122 | // Add any custom kbuild flags |
123 | make_cmd.insert(make_cmd.end(), s.kbuildflags.begin(), s.kbuildflags.end()); | |
124 | ||
125 | return make_cmd; | |
126 | } | |
127 | ||
8e0a2563 JS |
128 | static vector<string> |
129 | make_make_cmd(systemtap_session& s, const string& dir) | |
130 | { | |
131 | return make_any_make_cmd(s, dir, "modules"); | |
132 | } | |
133 | ||
134 | static vector<string> | |
135 | make_make_objs_cmd(systemtap_session& s, const string& dir) | |
136 | { | |
137 | // Kbuild uses these rules to build external modules: | |
138 | // | |
139 | // module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD)) | |
140 | // modules: $(module-dirs) | |
141 | // @$(kecho) ' Building modules, stage 2.'; | |
142 | // $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost | |
143 | // | |
144 | // So if we're only interested in the stage 1 objects, we can | |
145 | // cheat and make only the $(module-dirs) part. | |
146 | return make_any_make_cmd(s, dir, "_module_" + dir); | |
147 | } | |
148 | ||
de0db58a JS |
149 | static void |
150 | output_autoconf(systemtap_session& s, ofstream& o, const char *autoconf_c, | |
151 | const char *deftrue, const char *deffalse) | |
152 | { | |
153 | o << "\t"; | |
154 | if (s.verbose < 4) | |
155 | o << "@"; | |
2ba1736a | 156 | o << "if $(CHECK_BUILD) $(SYSTEMTAP_RUNTIME)/linux/" << autoconf_c; |
de0db58a JS |
157 | if (s.verbose < 5) |
158 | o << " > /dev/null 2>&1"; | |
159 | o << "; then "; | |
160 | if (deftrue) | |
161 | o << "echo \"#define " << deftrue << " 1\""; | |
162 | if (deffalse) | |
163 | o << "; else echo \"#define " << deffalse << " 1\""; | |
164 | o << "; fi >> $@" << endl; | |
165 | } | |
166 | ||
9e62f7ba FCE |
167 | |
168 | void output_exportconf(systemtap_session& s, ofstream& o, const char *symbol, | |
169 | const char *deftrue) | |
e25ab03c | 170 | { |
9e62f7ba FCE |
171 | o << "\t"; |
172 | if (s.verbose < 4) | |
173 | o << "@"; | |
174 | if (s.kernel_exports.find(symbol) != s.kernel_exports.end()) | |
175 | o << "echo \"#define " << deftrue << " 1\""; | |
176 | o << ">> $@" << endl; | |
e25ab03c WH |
177 | } |
178 | ||
9e62f7ba | 179 | |
08c29612 DS |
180 | void output_dual_exportconf(systemtap_session& s, ofstream& o, |
181 | const char *symbol1, const char *symbol2, | |
182 | const char *deftrue) | |
183 | { | |
184 | o << "\t"; | |
185 | if (s.verbose < 4) | |
186 | o << "@"; | |
187 | if (s.kernel_exports.find(symbol1) != s.kernel_exports.end() | |
188 | && s.kernel_exports.find(symbol2) != s.kernel_exports.end()) | |
189 | o << "echo \"#define " << deftrue << " 1\""; | |
190 | o << ">> $@" << endl; | |
191 | } | |
192 | ||
193 | ||
13128684 JS |
194 | void output_either_exportconf(systemtap_session& s, ofstream& o, |
195 | const char *symbol1, const char *symbol2, | |
196 | const char *deftrue) | |
197 | { | |
198 | o << "\t"; | |
199 | if (s.verbose < 4) | |
200 | o << "@"; | |
201 | if (s.kernel_exports.find(symbol1) != s.kernel_exports.end() | |
202 | || s.kernel_exports.find(symbol2) != s.kernel_exports.end()) | |
203 | o << "echo \"#define " << deftrue << " 1\""; | |
204 | o << ">> $@" << endl; | |
205 | } | |
206 | ||
207 | ||
3a894f7e JS |
208 | static int |
209 | compile_dyninst (systemtap_session& s) | |
210 | { | |
4441e344 | 211 | const string module = s.tmpdir + "/" + s.module_filename(); |
3a894f7e JS |
212 | |
213 | vector<string> cmd; | |
214 | cmd.push_back("gcc"); | |
215 | cmd.push_back("--std=gnu99"); | |
216 | cmd.push_back("-Wall"); | |
2537a880 | 217 | cmd.push_back(WERROR); |
3a894f7e JS |
218 | cmd.push_back("-Wno-unused"); |
219 | cmd.push_back("-Wno-strict-aliasing"); | |
ba2daa43 FCE |
220 | |
221 | // BZ855981/948279. Since dyninst/runtime.h includes __sync_* calls, | |
222 | // the compiler may generate different code for it depending on -march. | |
223 | // For example, if the default is i386, we may get references to auxiliary | |
224 | // functions like __sync_add_and_fetch_4, which appear to be defined | |
225 | // nowhere. We hack around this problem thusly: | |
226 | if (s.architecture == "i386") | |
e1c3538b | 227 | cmd.push_back("-march=i586"); |
ba2daa43 | 228 | |
81bc77cc | 229 | cmd.push_back("-fvisibility=hidden"); |
3a894f7e | 230 | cmd.push_back("-O2"); |
2466bf70 JS |
231 | cmd.push_back("-I" + s.runtime_path); |
232 | cmd.push_back("-D__DYNINST__"); | |
8140a78d JS |
233 | for (size_t i = 0; i < s.c_macros.size(); ++i) |
234 | cmd.push_back("-D" + s.c_macros[i]); | |
3a894f7e JS |
235 | cmd.push_back(s.translated_source); |
236 | cmd.push_back("-pthread"); | |
2b5ecafd | 237 | cmd.push_back("-lrt"); |
3a894f7e JS |
238 | cmd.push_back("-fPIC"); |
239 | cmd.push_back("-shared"); | |
240 | cmd.push_back("-o"); | |
241 | cmd.push_back(module); | |
8140a78d JS |
242 | if (s.verbose > 3) |
243 | { | |
244 | cmd.push_back("-ftime-report"); | |
245 | cmd.push_back("-Q"); | |
246 | } | |
3a894f7e | 247 | |
6da8678d | 248 | int rc = stap_system (s.verbose, cmd); |
3a894f7e JS |
249 | if (rc) |
250 | s.set_try_server (); | |
251 | return rc; | |
252 | } | |
3a894f7e JS |
253 | |
254 | ||
f4b28491 FCE |
255 | int |
256 | compile_pass (systemtap_session& s) | |
257 | { | |
ac3af990 | 258 | if (s.runtime_usermode_p()) |
4441e344 | 259 | return compile_dyninst (s); |
3a894f7e | 260 | |
db3a383b JK |
261 | int rc = uprobes_pass (s); |
262 | if (rc) | |
3e1ec884 DB |
263 | { |
264 | s.set_try_server (); | |
265 | return rc; | |
266 | } | |
db3a383b | 267 | |
f4b28491 | 268 | // fill in a quick Makefile |
92ade41d FCE |
269 | string makefile_nm = s.tmpdir + "/Makefile"; |
270 | ofstream o (makefile_nm.c_str()); | |
92ade41d FCE |
271 | |
272 | // Create makefile | |
ed10c639 | 273 | |
255e4c68 | 274 | // Clever hacks copied from vmware modules |
ecf19454 FCE |
275 | string superverbose; |
276 | if (s.verbose > 3) | |
277 | superverbose = "set -x;"; | |
522518f1 | 278 | |
e9737939 MM |
279 | string redirecterrors = "> /dev/null 2>&1"; |
280 | if (s.verbose > 6) | |
281 | redirecterrors = ""; | |
282 | ||
e5976ba0 MH |
283 | // Support O= (or KBUILD_OUTPUT) option |
284 | o << "_KBUILD_CFLAGS := $(call flags,KBUILD_CFLAGS)" << endl; | |
285 | ||
2537a880 JS |
286 | o << "stap_check_gcc = $(shell " << superverbose |
287 | << " if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then " | |
288 | << "echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl; | |
289 | o << "CHECK_BUILD := $(CC) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) $(CPPFLAGS) " | |
290 | << "$(LINUXINCLUDE) $(_KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) " | |
291 | << "$(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\" " | |
292 | << WERROR << " -S -o /dev/null -xc " << endl; | |
293 | o << "stap_check_build = $(shell " << superverbose << " if $(CHECK_BUILD) $(1) " | |
294 | << redirecterrors << " ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl; | |
255e4c68 FCE |
295 | |
296 | o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl; | |
297 | ||
298 | // "autoconf" options go here | |
299 | ||
18222191 FCE |
300 | // RHBZ 543529: early rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules |
301 | o << "CONFIG_MODULE_SIG := n" << endl; | |
302 | ||
ecf19454 | 303 | string module_cflags = "EXTRA_CFLAGS"; |
522518f1 | 304 | o << module_cflags << " :=" << endl; |
84c4da88 FCE |
305 | |
306 | // XXX: This gruesome hack is needed on some kernels built with separate O=directory, | |
307 | // where files like 2.6.27 x86's asm/mach-*/mach_mpspec.h are not found on the cpp path. | |
308 | // This could be a bug in arch/x86/Makefile that names | |
309 | // mflags-y += -Iinclude/asm-x86/mach-default | |
310 | // but that path does not exist in an O= build tree. | |
311 | o << module_cflags << " += -Iinclude2/asm/mach-default" << endl; | |
18b13994 | 312 | o << module_cflags << " += -I" + s.kernel_build_tree << endl; |
d4393459 FCE |
313 | if (s.kernel_source_tree != "") |
314 | o << module_cflags << " += -I" + s.kernel_source_tree << endl; | |
ac4f2837 DS |
315 | for (unsigned i = 0; i < s.kernel_extra_cflags.size(); i++) |
316 | o << module_cflags << " += " + s.kernel_extra_cflags[i] << endl; | |
84c4da88 | 317 | |
6046b840 FCE |
318 | // NB: don't try |
319 | // o << module_cflags << " += -Iusr/include" << endl; | |
320 | // since such headers are cleansed of _KERNEL_ pieces that we need | |
321 | ||
de0db58a | 322 | o << "STAPCONF_HEADER := " << s.tmpdir << "/" << s.stapconf_name << endl; |
de0db58a | 323 | o << "$(STAPCONF_HEADER):" << endl; |
b03e7089 | 324 | o << "\t@> $@" << endl; |
de0db58a | 325 | output_autoconf(s, o, "autoconf-hrtimer-rel.c", "STAPCONF_HRTIMER_REL", NULL); |
86f726b7 | 326 | output_exportconf(s, o, "hrtimer_get_res", "STAPCONF_HRTIMER_GET_RES"); |
1d381a0d | 327 | output_autoconf(s, o, "autoconf-generated-compile.c", "STAPCONF_GENERATED_COMPILE", NULL); |
de0db58a JS |
328 | output_autoconf(s, o, "autoconf-hrtimer-getset-expires.c", "STAPCONF_HRTIMER_GETSET_EXPIRES", NULL); |
329 | output_autoconf(s, o, "autoconf-inode-private.c", "STAPCONF_INODE_PRIVATE", NULL); | |
330 | output_autoconf(s, o, "autoconf-constant-tsc.c", "STAPCONF_CONSTANT_TSC", NULL); | |
de0db58a JS |
331 | output_autoconf(s, o, "autoconf-ktime-get-real.c", "STAPCONF_KTIME_GET_REAL", NULL); |
332 | output_autoconf(s, o, "autoconf-x86-uniregs.c", "STAPCONF_X86_UNIREGS", NULL); | |
333 | output_autoconf(s, o, "autoconf-nameidata.c", "STAPCONF_NAMEIDATA_CLEANUP", NULL); | |
08c29612 | 334 | output_dual_exportconf(s, o, "unregister_kprobes", "unregister_kretprobes", "STAPCONF_UNREGISTER_KPROBES"); |
766cee5f | 335 | output_autoconf(s, o, "autoconf-kprobe-symbol-name.c", "STAPCONF_KPROBE_SYMBOL_NAME", NULL); |
de0db58a JS |
336 | output_autoconf(s, o, "autoconf-real-parent.c", "STAPCONF_REAL_PARENT", NULL); |
337 | output_autoconf(s, o, "autoconf-uaccess.c", "STAPCONF_LINUX_UACCESS_H", NULL); | |
338 | output_autoconf(s, o, "autoconf-oneachcpu-retry.c", "STAPCONF_ONEACHCPU_RETRY", NULL); | |
339 | output_autoconf(s, o, "autoconf-dpath-path.c", "STAPCONF_DPATH_PATH", NULL); | |
b9197b0f JS |
340 | output_exportconf(s, o, "synchronize_kernel", "STAPCONF_SYNCHRONIZE_KERNEL"); |
341 | output_exportconf(s, o, "synchronize_rcu", "STAPCONF_SYNCHRONIZE_RCU"); | |
08c29612 | 342 | output_exportconf(s, o, "synchronize_sched", "STAPCONF_SYNCHRONIZE_SCHED"); |
de0db58a | 343 | output_autoconf(s, o, "autoconf-task-uid.c", "STAPCONF_TASK_UID", NULL); |
ca89d289 | 344 | output_autoconf(s, o, "autoconf-from_kuid_munged.c", "STAPCONF_FROM_KUID_MUNGED", NULL); |
1c70d655 | 345 | output_exportconf(s, o, "get_mm_exe_file", "STAPCONF_GET_MM_EXE_FILE"); |
08c29612 | 346 | output_dual_exportconf(s, o, "alloc_vm_area", "free_vm_area", "STAPCONF_VM_AREA"); |
de0db58a | 347 | output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL); |
b1f85b93 | 348 | output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL); |
6ddf07ac JS |
349 | output_autoconf(s, o, "autoconf-x86-fs.c", "STAPCONF_X86_FS", NULL); |
350 | output_autoconf(s, o, "autoconf-x86-xfs.c", "STAPCONF_X86_XFS", NULL); | |
5cad2d3b | 351 | output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL); |
f098eb6d | 352 | output_autoconf(s, o, "autoconf-grsecurity.c", "STAPCONF_GRSECURITY", NULL); |
450718c9 | 353 | output_autoconf(s, o, "autoconf-trace-printk.c", "STAPCONF_TRACE_PRINTK", NULL); |
be004140 FCE |
354 | output_autoconf(s, o, "autoconf-regset.c", "STAPCONF_REGSET", NULL); |
355 | output_autoconf(s, o, "autoconf-utrace-regset.c", "STAPCONF_UTRACE_REGSET", NULL); | |
23258335 | 356 | output_autoconf(s, o, "autoconf-uprobe-get-pc.c", "STAPCONF_UPROBE_GET_PC", NULL); |
85804472 | 357 | output_autoconf(s, o, "autoconf-hlist-4args.c", "STAPCONF_HLIST_4ARGS", NULL); |
b09417ad | 358 | output_exportconf(s, o, "tsc_khz", "STAPCONF_TSC_KHZ"); |
9e62f7ba | 359 | output_exportconf(s, o, "cpu_khz", "STAPCONF_CPU_KHZ"); |
031fda59 | 360 | output_exportconf(s, o, "__module_text_address", "STAPCONF_MODULE_TEXT_ADDRESS"); |
af6c651f | 361 | output_exportconf(s, o, "add_timer_on", "STAPCONF_ADD_TIMER_ON"); |
8d59b39f | 362 | |
08c29612 | 363 | output_dual_exportconf(s, o, "probe_kernel_read", "probe_kernel_write", "STAPCONF_PROBE_KERNEL"); |
b273669e MW |
364 | output_autoconf(s, o, "autoconf-hw_breakpoint_context.c", |
365 | "STAPCONF_HW_BREAKPOINT_CONTEXT", NULL); | |
8c5905d0 TM |
366 | output_autoconf(s, o, "autoconf-save-stack-trace.c", |
367 | "STAPCONF_KERNEL_STACKTRACE", NULL); | |
9957bbd2 MW |
368 | output_autoconf(s, o, "autoconf-save-stack-trace-no-bp.c", |
369 | "STAPCONF_KERNEL_STACKTRACE_NO_BP", NULL); | |
d5cd287f DS |
370 | output_autoconf(s, o, "autoconf-asm-syscall.c", |
371 | "STAPCONF_ASM_SYSCALL_H", NULL); | |
c145b9cb | 372 | output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL); |
0d0f0d84 | 373 | output_autoconf(s, o, "autoconf-ring_buffer_lost_events.c", "STAPCONF_RING_BUFFER_LOST_EVENTS", NULL); |
c38602b5 | 374 | output_autoconf(s, o, "autoconf-ring_buffer_read_prepare.c", "STAPCONF_RING_BUFFER_READ_PREPARE", NULL); |
03a4ec63 | 375 | output_autoconf(s, o, "autoconf-kallsyms-on-each-symbol.c", "STAPCONF_KALLSYMS_ON_EACH_SYMBOL", NULL); |
c265cd25 | 376 | output_autoconf(s, o, "autoconf-walk-stack.c", "STAPCONF_WALK_STACK", NULL); |
0bbb8009 JS |
377 | output_autoconf(s, o, "autoconf-stacktrace_ops-warning.c", |
378 | "STAPCONF_STACKTRACE_OPS_WARNING", NULL); | |
18da5887 | 379 | output_autoconf(s, o, "autoconf-mm-context-vdso.c", "STAPCONF_MM_CONTEXT_VDSO", NULL); |
3b62d74b | 380 | output_autoconf(s, o, "autoconf-mm-context-vdso-base.c", "STAPCONF_MM_CONTEXT_VDSO_BASE", NULL); |
c1d2d085 | 381 | output_autoconf(s, o, "autoconf-blk-types.c", "STAPCONF_BLK_TYPES", NULL); |
aec17ca6 | 382 | output_autoconf(s, o, "autoconf-perf-structpid.c", "STAPCONF_PERF_STRUCTPID", NULL); |
2f3df331 MW |
383 | output_autoconf(s, o, "perf_event_counter_context.c", |
384 | "STAPCONF_PERF_COUNTER_CONTEXT", NULL); | |
385 | output_autoconf(s, o, "perf_probe_handler_nmi.c", | |
386 | "STAPCONF_PERF_HANDLER_NMI", NULL); | |
7f2d56c3 DS |
387 | output_exportconf(s, o, "path_lookup", "STAPCONF_PATH_LOOKUP"); |
388 | output_exportconf(s, o, "kern_path_parent", "STAPCONF_KERN_PATH_PARENT"); | |
389 | output_exportconf(s, o, "vfs_path_lookup", "STAPCONF_VFS_PATH_LOOKUP"); | |
33f02716 | 390 | output_exportconf(s, o, "kern_path", "STAPCONF_KERN_PATH"); |
b85e750d DS |
391 | output_exportconf(s, o, "proc_create_data", "STAPCONF_PROC_CREATE_DATA"); |
392 | output_exportconf(s, o, "PDE_DATA", "STAPCONF_PDE_DATA"); | |
2c9caccb | 393 | output_autoconf(s, o, "autoconf-module-sect-attrs.c", "STAPCONF_MODULE_SECT_ATTRS", NULL); |
04ffc218 | 394 | |
db7dcdff | 395 | output_autoconf(s, o, "autoconf-utrace-via-tracepoints.c", "STAPCONF_UTRACE_VIA_TRACEPOINTS", NULL); |
0e0e60b2 | 396 | output_autoconf(s, o, "autoconf-task_work-struct.c", "STAPCONF_TASK_WORK_STRUCT", NULL); |
abc69bab | 397 | output_autoconf(s, o, "autoconf-vm-area-pte.c", "STAPCONF_VM_AREA_PTE", NULL); |
56111fdc | 398 | output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL); |
52dea427 | 399 | output_autoconf(s, o, "autoconf-fs_supers-hlist.c", "STAPCONF_FS_SUPERS_HLIST", NULL); |
fce34f35 | 400 | output_autoconf(s, o, "autoconf-compat_sigaction.c", "STAPCONF_COMPAT_SIGACTION", NULL); |
4d914c37 | 401 | output_autoconf(s, o, "autoconf-netfilter.c", "STAPCONF_NETFILTER_V313", NULL); |
7cfb10ec | 402 | output_autoconf(s, o, "autoconf-netfilter-313b.c", "STAPCONF_NETFILTER_V313B", NULL); |
502f3816 | 403 | output_autoconf(s, o, "autoconf-netfilter-4_1.c", "STAPCONF_NETFILTER_V41", NULL); |
2736131d | 404 | output_autoconf(s, o, "autoconf-netfilter-4_4.c", "STAPCONF_NETFILTER_V44", NULL); |
590a9ae1 | 405 | output_autoconf(s, o, "autoconf-smpcall-5args.c", "STAPCONF_SMPCALL_5ARGS", NULL); |
ceeaa82b | 406 | output_autoconf(s, o, "autoconf-smpcall-4args.c", "STAPCONF_SMPCALL_4ARGS", NULL); |
db7dcdff | 407 | |
de5f477b JS |
408 | // used by tapset/timestamp_monotonic.stp |
409 | output_exportconf(s, o, "cpu_clock", "STAPCONF_CPU_CLOCK"); | |
410 | output_exportconf(s, o, "local_clock", "STAPCONF_LOCAL_CLOCK"); | |
411 | ||
64e807c2 | 412 | // used by runtime/uprobe-inode.c |
13128684 JS |
413 | output_either_exportconf(s, o, "uprobe_register", "register_uprobe", |
414 | "STAPCONF_UPROBE_REGISTER_EXPORTED"); | |
415 | output_either_exportconf(s, o, "uprobe_unregister", "unregister_uprobe", | |
416 | "STAPCONF_UPROBE_UNREGISTER_EXPORTED"); | |
417 | output_autoconf(s, o, "autoconf-old-inode-uprobes.c", "STAPCONF_OLD_INODE_UPROBES", NULL); | |
79af55c3 | 418 | output_autoconf(s, o, "autoconf-inode-uretprobes.c", "STAPCONF_INODE_URETPROBES", NULL); |
39e63bae DS |
419 | |
420 | // used by tapsets.cxx inode uprobe generated code | |
421 | output_exportconf(s, o, "uprobe_get_swbp_addr", "STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED"); | |
422 | ||
fe6feb40 | 423 | // used by runtime/loc2c-runtime.h |
64e807c2 FCE |
424 | output_exportconf(s, o, "task_user_regset_view", "STAPCONF_TASK_USER_REGSET_VIEW_EXPORTED"); |
425 | ||
36de3b61 DS |
426 | // used by runtime/stp_utrace.c |
427 | output_exportconf(s, o, "task_work_add", "STAPCONF_TASK_WORK_ADD_EXPORTED"); | |
d9d07e99 DS |
428 | output_exportconf(s, o, "wake_up_state", "STAPCONF_WAKE_UP_STATE_EXPORTED"); |
429 | output_exportconf(s, o, "try_to_wake_up", "STAPCONF_TRY_TO_WAKE_UP_EXPORTED"); | |
dfdbaa3d | 430 | output_exportconf(s, o, "signal_wake_up_state", "STAPCONF_SIGNAL_WAKE_UP_STATE_EXPORTED"); |
f346b8b3 DS |
431 | output_exportconf(s, o, "signal_wake_up", "STAPCONF_SIGNAL_WAKE_UP_EXPORTED"); |
432 | output_exportconf(s, o, "__lock_task_sighand", "STAPCONF___LOCK_TASK_SIGHAND_EXPORTED"); | |
36de3b61 | 433 | |
8fee9cc5 | 434 | output_autoconf(s, o, "autoconf-pagefault_disable.c", "STAPCONF_PAGEFAULT_DISABLE", NULL); |
15cf9503 | 435 | output_exportconf(s, o, "kallsyms_lookup_name", "STAPCONF_KALLSYMS"); |
85716315 | 436 | output_autoconf(s, o, "autoconf-uidgid.c", "STAPCONF_LINUX_UIDGID_H", NULL); |
4fe11374 | 437 | output_exportconf(s, o, "sigset_from_compat", "STAPCONF_SIGSET_FROM_COMPAT_EXPORTED"); |
42c2d1ed DS |
438 | output_exportconf(s, o, "vzalloc", "STAPCONF_VZALLOC"); |
439 | output_exportconf(s, o, "vzalloc_node", "STAPCONF_VZALLOC_NODE"); | |
c9c633a8 | 440 | output_exportconf(s, o, "vmalloc_node", "STAPCONF_VMALLOC_NODE"); |
8fee9cc5 | 441 | |
3ef9830a | 442 | output_autoconf(s, o, "autoconf-tracepoint-strings.c", "STAPCONF_TRACEPOINT_STRINGS", NULL); |
bac8aa5a | 443 | output_autoconf(s, o, "autoconf-timerfd.c", "STAPCONF_TIMERFD_H", NULL); |
3ef9830a | 444 | |
3f040971 DS |
445 | output_autoconf(s, o, "autoconf-module_layout.c", |
446 | "STAPCONF_MODULE_LAYOUT", NULL); | |
64ffc49b DS |
447 | output_autoconf(s, o, "autoconf-mod_kallsyms.c", |
448 | "STAPCONF_MOD_KALLSYMS", NULL); | |
3f040971 | 449 | |
de0db58a | 450 | o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl; |
5c54d49e | 451 | |
08fce398 SM |
452 | for (unsigned i=0; i<s.c_macros.size(); i++) |
453 | o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.c_macros[i]) << endl; // XXX right quoting? | |
ed10c639 | 454 | |
e4c58386 | 455 | if (s.verbose > 3) |
0986ac38 | 456 | o << "EXTRA_CFLAGS += -ftime-report -Q" << endl; |
db22e55f | 457 | |
ee6dda6f | 458 | // XXX: unfortunately, -save-temps can't work since linux kbuild cwd |
100a540e | 459 | // is not writable. |
ee6dda6f FCE |
460 | // |
461 | // if (s.keep_tmpdir) | |
462 | // o << "CFLAGS += -fverbose-asm -save-temps" << endl; | |
463 | ||
ec6fdef5 MW |
464 | // Kernels can be compiled with CONFIG_CC_OPTIMIZE_FOR_SIZE to select |
465 | // -Os, otherwise -O2 is the default. | |
466 | o << "EXTRA_CFLAGS += -freorder-blocks" << endl; // improve on -Os | |
977b259e JS |
467 | |
468 | // Generate eh_frame for self-backtracing | |
469 | o << "EXTRA_CFLAGS += -fasynchronous-unwind-tables" << endl; | |
ec6fdef5 | 470 | |
01116596 MW |
471 | // We used to allow the user to override default optimization when so |
472 | // requested by adding a -O[0123s] so they could determine the | |
473 | // time/space/speed tradeoffs themselves, but we cannot guantantee that | |
474 | // the (un)optimized code actually compiles and/or generates functional | |
475 | // code, so we had to remove it. | |
476 | // o << "EXTRA_CFLAGS += " << s.gcc_flags << endl; // Add -O[0123s] | |
35d4ab18 FCE |
477 | |
478 | // o << "CFLAGS += -fno-unit-at-a-time" << endl; | |
dff50e09 | 479 | |
de4123d6 | 480 | // 256^W512 bytes should be enough for anybody |
01a2eba8 | 481 | // XXX this doesn't validate varargs, per gcc bug #41633 |
de4123d6 | 482 | o << "EXTRA_CFLAGS += $(call cc-option,-Wframe-larger-than=512)" << endl; |
730c3efc | 483 | |
c1e83543 FCE |
484 | // gcc 5.0.0-0.13.fc23 ipa-icf seems to consume gigacpu on stap-generated code |
485 | o << "EXTRA_CFLAGS += $(call cc-option,-fno-ipa-icf)" << endl; | |
486 | ||
cbfbbf69 | 487 | // Assumes linux 2.6 kbuild |
2537a880 | 488 | o << "EXTRA_CFLAGS += -Wno-unused " << WERROR << endl; |
29bdbdb1 FCE |
489 | #if CHECK_POINTER_ARITH_PR5947 |
490 | o << "EXTRA_CFLAGS += -Wpointer-arith" << endl; | |
491 | #endif | |
0986ac38 | 492 | o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl; |
4b2c4ab5 FCE |
493 | // XXX: this may help ppc toc overflow |
494 | // o << "CFLAGS := $(subst -Os,-O2,$(CFLAGS)) -fminimal-toc" << endl; | |
cbfbbf69 | 495 | o << "obj-m := " << s.module_name << ".o" << endl; |
f4b28491 | 496 | |
a4b9c3b3 FCE |
497 | // print out all the auxiliary source (->object) file names |
498 | o << s.module_name << "-y := "; | |
499 | for (unsigned i=0; i<s.auxiliary_outputs.size(); i++) | |
500 | { | |
80d74c6b | 501 | if (s.auxiliary_outputs[i]->trailer_p) continue; |
a4b9c3b3 FCE |
502 | string srcname = s.auxiliary_outputs[i]->filename; |
503 | assert (srcname != "" && srcname.rfind('/') != string::npos); | |
504 | string objname = srcname.substr(srcname.rfind('/')+1); // basename | |
505 | assert (objname != "" && objname[objname.size()-1] == 'c'); | |
506 | objname[objname.size()-1] = 'o'; // now objname | |
507 | o << " " + objname; | |
508 | } | |
509 | // and once again, for the translated_source file. It can't simply | |
510 | // be named MODULENAME.c, since kbuild doesn't allow a foo.ko file | |
511 | // consisting of multiple .o's to have foo.o/foo.c as a source. | |
512 | // (It uses ld -r -o foo.o EACH.o EACH.o). | |
513 | { | |
514 | string srcname = s.translated_source; | |
515 | assert (srcname != "" && srcname.rfind('/') != string::npos); | |
516 | string objname = srcname.substr(srcname.rfind('/')+1); // basename | |
517 | assert (objname != "" && objname[objname.size()-1] == 'c'); | |
518 | objname[objname.size()-1] = 'o'; // now objname | |
519 | o << " " + objname; | |
520 | } | |
80d74c6b FCE |
521 | // and once again, for the trailer type auxiliary outputs. |
522 | for (unsigned i=0; i<s.auxiliary_outputs.size(); i++) | |
523 | { | |
524 | if (! s.auxiliary_outputs[i]->trailer_p) continue; | |
525 | string srcname = s.auxiliary_outputs[i]->filename; | |
526 | assert (srcname != "" && srcname.rfind('/') != string::npos); | |
527 | string objname = srcname.substr(srcname.rfind('/')+1); // basename | |
528 | assert (objname != "" && objname[objname.size()-1] == 'c'); | |
529 | objname[objname.size()-1] = 'o'; // now objname | |
530 | o << " " + objname; | |
531 | } | |
a4b9c3b3 FCE |
532 | o << endl; |
533 | ||
534 | // add all stapconf dependencies | |
535 | o << s.translated_source << ": $(STAPCONF_HEADER)" << endl; | |
536 | for (unsigned i=0; i<s.auxiliary_outputs.size(); i++) | |
537 | o << s.auxiliary_outputs[i]->filename << ": $(STAPCONF_HEADER)" << endl; | |
538 | ||
539 | ||
ed10c639 FCE |
540 | o.close (); |
541 | ||
b40af7ee | 542 | // Generate module directory pathname and make sure it exists. |
4d34dac1 FCE |
543 | string module_dir = s.kernel_build_tree; |
544 | string module_dir_makefile = module_dir + "/Makefile"; | |
b40af7ee | 545 | struct stat st; |
4d34dac1 | 546 | rc = stat(module_dir_makefile.c_str(), &st); |
b40af7ee DS |
547 | if (rc != 0) |
548 | { | |
ce0f6648 | 549 | clog << _F("Checking \" %s \" failed with error: %s\nEnsure kernel development headers & makefiles are installed.", |
46a1a151 | 550 | module_dir_makefile.c_str(), strerror(errno)) << endl; |
3e1ec884 | 551 | s.set_try_server (); |
b40af7ee | 552 | return rc; |
dff50e09 | 553 | } |
b40af7ee DS |
554 | |
555 | // Run make | |
7d26ee02 | 556 | vector<string> make_cmd = make_make_cmd(s, s.tmpdir); |
6274464e | 557 | rc = run_make_cmd(s, make_cmd); |
3e1ec884 DB |
558 | if (rc) |
559 | s.set_try_server (); | |
f4b28491 FCE |
560 | return rc; |
561 | } | |
562 | ||
db3a383b JK |
563 | /* |
564 | * If uprobes was built as part of the kernel build (either built-in | |
dbb9345d FCE |
565 | * or as a module), the uprobes exports should show up. This is to be |
566 | * as distinct from the stap-built uprobes.ko from the runtime. | |
db3a383b JK |
567 | */ |
568 | static bool | |
569 | kernel_built_uprobes (systemtap_session& s) | |
6274464e | 570 | { |
ac3af990 | 571 | if (s.runtime_usermode_p()) |
4441e344 JS |
572 | return true; // sort of, via dyninst |
573 | ||
95113339 FCE |
574 | // see also tapsets.cxx:kernel_supports_inode_uprobes() |
575 | return ((s.kernel_config["CONFIG_ARCH_SUPPORTS_UPROBES"] == "y" && s.kernel_config["CONFIG_UPROBES"] == "y") || | |
576 | (s.kernel_exports.find("unregister_uprobe") != s.kernel_exports.end())); | |
6274464e JK |
577 | } |
578 | ||
7d26ee02 JS |
579 | static int |
580 | make_uprobes (systemtap_session& s) | |
6274464e | 581 | { |
7ef486ad | 582 | if (s.verbose > 1) |
7d26ee02 | 583 | clog << _("Pass 4, preamble: (re)building SystemTap's version of uprobes.") |
db3a383b JK |
584 | << endl; |
585 | ||
7d26ee02 JS |
586 | // create a subdirectory for the uprobes module |
587 | string dir(s.tmpdir + "/uprobes"); | |
588 | if (create_dir(dir.c_str()) != 0) | |
589 | { | |
2713ea24 | 590 | s.print_warning("failed to create directory for build uprobes."); |
7d26ee02 JS |
591 | s.set_try_server (); |
592 | return 1; | |
0da3e7a0 | 593 | } |
6274464e | 594 | |
7d26ee02 JS |
595 | // create a simple Makefile |
596 | string makefile(dir + "/Makefile"); | |
597 | ofstream omf(makefile.c_str()); | |
598 | omf << "obj-m := uprobes.o" << endl; | |
599 | // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules | |
600 | omf << "CONFIG_MODULE_SIG := n" << endl; | |
601 | omf.close(); | |
6274464e | 602 | |
7d26ee02 | 603 | // create a simple #include-chained source file |
2ba1736a | 604 | string runtimesourcefile(s.runtime_path + "/linux/uprobes/uprobes.c"); |
7d26ee02 JS |
605 | string sourcefile(dir + "/uprobes.c"); |
606 | ofstream osrc(sourcefile.c_str()); | |
607 | osrc << "#include \"" << runtimesourcefile << "\"" << endl; | |
76d01f36 FCE |
608 | |
609 | // pass --modinfo k=v to uprobes build too | |
610 | for (unsigned i = 0; i < s.modinfos.size(); i++) | |
611 | { | |
612 | const string& mi = s.modinfos[i]; | |
613 | size_t loc = mi.find('='); | |
614 | string tag = mi.substr (0, loc); | |
615 | string value = mi.substr (loc+1); | |
616 | osrc << "MODULE_INFO(" << tag << "," << lex_cast_qstring(value) << ");" << endl; | |
617 | } | |
618 | ||
7d26ee02 JS |
619 | osrc.close(); |
620 | ||
621 | // make the module | |
622 | vector<string> make_cmd = make_make_cmd(s, dir); | |
ae5e0bbb | 623 | int rc = run_make_cmd(s, make_cmd); |
7d26ee02 JS |
624 | if (!rc && !copy_file(dir + "/Module.symvers", |
625 | s.tmpdir + "/Module.symvers")) | |
626 | rc = -1; | |
6274464e | 627 | |
f4d5049b | 628 | if (s.verbose > 1) |
ce0f6648 | 629 | clog << _("uprobes rebuild exit code: ") << rc << endl; |
3e1ec884 DB |
630 | if (rc) |
631 | s.set_try_server (); | |
91ea0ce6 | 632 | else |
7d26ee02 | 633 | s.uprobes_path = dir + "/uprobes.ko"; |
6274464e JK |
634 | return rc; |
635 | } | |
636 | ||
7d26ee02 JS |
637 | static bool |
638 | get_cached_uprobes(systemtap_session& s) | |
639 | { | |
640 | s.uprobes_hash = s.use_cache ? find_uprobes_hash(s) : ""; | |
641 | if (!s.uprobes_hash.empty()) | |
642 | { | |
643 | // NB: We always put uprobes.ko in its own directory, especially so | |
644 | // stap-serverd can more easily locate it. | |
645 | string dir(s.tmpdir + "/uprobes"); | |
646 | if (create_dir(dir.c_str()) != 0) | |
647 | return false; | |
648 | ||
649 | string cacheko = s.uprobes_hash + ".ko"; | |
650 | string tmpko = dir + "/uprobes.ko"; | |
651 | ||
652 | // The symvers file still needs to go in the script module's directory. | |
653 | string cachesyms = s.uprobes_hash + ".symvers"; | |
654 | string tmpsyms = s.tmpdir + "/Module.symvers"; | |
655 | ||
656 | if (get_file_size(cacheko) > 0 && copy_file(cacheko, tmpko) && | |
657 | get_file_size(cachesyms) > 0 && copy_file(cachesyms, tmpsyms)) | |
658 | { | |
659 | s.uprobes_path = tmpko; | |
660 | return true; | |
661 | } | |
662 | } | |
663 | return false; | |
664 | } | |
665 | ||
666 | static void | |
667 | set_cached_uprobes(systemtap_session& s) | |
db3a383b | 668 | { |
7d26ee02 JS |
669 | if (s.use_cache && !s.uprobes_hash.empty()) |
670 | { | |
671 | string cacheko = s.uprobes_hash + ".ko"; | |
672 | string tmpko = s.tmpdir + "/uprobes/uprobes.ko"; | |
673 | copy_file(tmpko, cacheko); | |
36ef6d6a | 674 | |
7d26ee02 JS |
675 | string cachesyms = s.uprobes_hash + ".symvers"; |
676 | string tmpsyms = s.tmpdir + "/uprobes/Module.symvers"; | |
677 | copy_file(tmpsyms, cachesyms); | |
678 | } | |
db3a383b JK |
679 | } |
680 | ||
7d26ee02 | 681 | int |
db3a383b JK |
682 | uprobes_pass (systemtap_session& s) |
683 | { | |
684 | if (!s.need_uprobes || kernel_built_uprobes(s)) | |
685 | return 0; | |
0944a81e | 686 | |
6c7e2241 | 687 | if (s.kernel_config["CONFIG_UTRACE"] != string("y")) |
01fa08f2 | 688 | { |
6c9f0b7b | 689 | clog << _("user-space process-tracking facilities not available [man error::process-tracking]") << endl; |
01fa08f2 DS |
690 | s.set_try_server (); |
691 | return 1; | |
692 | } | |
0944a81e | 693 | |
db3a383b | 694 | /* |
7d26ee02 JS |
695 | * We need to use the version of uprobes that comes with SystemTap. Try to |
696 | * get it from the cache first. If not found, build it and try to save it to | |
697 | * the cache for future reuse. | |
db3a383b | 698 | */ |
7d26ee02 JS |
699 | int rc = 0; |
700 | if (!get_cached_uprobes(s)) | |
701 | { | |
702 | rc = make_uprobes(s); | |
703 | if (!rc) | |
704 | set_cached_uprobes(s); | |
705 | } | |
3e1ec884 DB |
706 | if (rc) |
707 | s.set_try_server (); | |
db3a383b JK |
708 | return rc; |
709 | } | |
710 | ||
3a894f7e JS |
711 | static |
712 | vector<string> | |
713 | make_dyninst_run_command (systemtap_session& s, const string& remotedir, | |
dabd71bb | 714 | const string&) |
3a894f7e JS |
715 | { |
716 | vector<string> cmd; | |
56658530 | 717 | cmd.push_back(getenv("SYSTEMTAP_STAPDYN") ?: BINDIR "/stapdyn"); |
e75a4464 JS |
718 | |
719 | // use slightly less verbosity | |
720 | for (unsigned i=1; i<s.verbose; i++) | |
41300e6d JS |
721 | cmd.push_back("-v"); |
722 | if (s.suppress_warnings) | |
723 | cmd.push_back("-w"); | |
3a894f7e JS |
724 | |
725 | if (!s.cmd.empty()) | |
726 | { | |
727 | cmd.push_back("-c"); | |
728 | cmd.push_back(s.cmd); | |
729 | } | |
730 | ||
02bff028 JS |
731 | if (s.target_pid) |
732 | { | |
733 | cmd.push_back("-x"); | |
734 | cmd.push_back(lex_cast(s.target_pid)); | |
735 | } | |
736 | ||
6d842dc7 DS |
737 | if (!s.output_file.empty()) |
738 | { | |
739 | cmd.push_back("-o"); | |
740 | cmd.push_back(s.output_file); | |
741 | } | |
742 | ||
192130b3 JL |
743 | if (s.color_mode != s.color_auto) |
744 | { | |
745 | cmd.push_back("-C"); | |
746 | if (s.color_mode == s.color_always) | |
747 | cmd.push_back("always"); | |
748 | else | |
749 | cmd.push_back("never"); | |
750 | } | |
751 | ||
3a894f7e | 752 | cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir) |
4441e344 | 753 | + "/" + s.module_filename()); |
3a894f7e | 754 | |
bd268288 SM |
755 | // add module arguments |
756 | cmd.insert(cmd.end(), s.globalopts.begin(), s.globalopts.end()); | |
757 | ||
3a894f7e JS |
758 | return cmd; |
759 | } | |
3a894f7e | 760 | |
5eea6ed1 | 761 | vector<string> |
18630fb8 | 762 | make_run_command (systemtap_session& s, const string& remotedir, |
4112f219 | 763 | const string& version) |
f4b28491 | 764 | { |
ac3af990 | 765 | if (s.runtime_usermode_p()) |
4441e344 JS |
766 | return make_dyninst_run_command(s, remotedir, version); |
767 | ||
a63a95dc | 768 | // for now, just spawn staprun |
5eea6ed1 JS |
769 | vector<string> staprun_cmd; |
770 | staprun_cmd.push_back(getenv("SYSTEMTAP_STAPRUN") ?: BINDIR "/staprun"); | |
e75a4464 JS |
771 | |
772 | // use slightly less verbosity | |
773 | for (unsigned i=1; i<s.verbose; i++) | |
5eea6ed1 JS |
774 | staprun_cmd.push_back("-v"); |
775 | if (s.suppress_warnings) | |
776 | staprun_cmd.push_back("-w"); | |
777 | ||
778 | if (!s.output_file.empty()) | |
779 | { | |
780 | staprun_cmd.push_back("-o"); | |
781 | staprun_cmd.push_back(s.output_file); | |
782 | } | |
dff50e09 | 783 | |
5eea6ed1 JS |
784 | if (!s.cmd.empty()) |
785 | { | |
786 | staprun_cmd.push_back("-c"); | |
787 | staprun_cmd.push_back(s.cmd); | |
788 | } | |
dff50e09 | 789 | |
cbfbbf69 | 790 | if (s.target_pid) |
5eea6ed1 JS |
791 | { |
792 | staprun_cmd.push_back("-t"); | |
793 | staprun_cmd.push_back(lex_cast(s.target_pid)); | |
794 | } | |
dff50e09 | 795 | |
e9bb2221 AJ |
796 | if (s.target_namespaces_pid) |
797 | { | |
798 | staprun_cmd.push_back("-N"); | |
799 | staprun_cmd.push_back(lex_cast(s.target_namespaces_pid)); | |
800 | } | |
801 | ||
cbfbbf69 | 802 | if (s.buffer_size) |
5eea6ed1 JS |
803 | { |
804 | staprun_cmd.push_back("-b"); | |
805 | staprun_cmd.push_back(lex_cast(s.buffer_size)); | |
806 | } | |
dff50e09 | 807 | |
13128684 | 808 | if (s.need_uprobes && !kernel_built_uprobes(s)) |
5eea6ed1 | 809 | { |
18630fb8 JS |
810 | string opt_u = "-u"; |
811 | if (!s.uprobes_path.empty() && | |
812 | strverscmp("1.4", version.c_str()) <= 0) | |
813 | { | |
814 | if (remotedir.empty()) | |
815 | opt_u.append(s.uprobes_path); | |
816 | else | |
817 | opt_u.append(remotedir + "/" + basename(s.uprobes_path.c_str())); | |
818 | } | |
819 | staprun_cmd.push_back(opt_u); | |
5eea6ed1 | 820 | } |
6274464e | 821 | |
2fa2a091 | 822 | if (s.load_only) |
5eea6ed1 | 823 | staprun_cmd.push_back(s.output_file.empty() ? "-L" : "-D"); |
701c41be | 824 | |
b3367f63 DS |
825 | // Note that if this system requires signed modules, we can't rename |
826 | // it after it has been signed. | |
827 | if (!s.modname_given && (strverscmp("1.6", version.c_str()) <= 0) | |
cd1418c7 | 828 | && s.mok_fingerprints.empty()) |
5c854d7c CM |
829 | staprun_cmd.push_back("-R"); |
830 | ||
701c41be | 831 | if (!s.size_option.empty()) |
5eea6ed1 JS |
832 | { |
833 | staprun_cmd.push_back("-S"); | |
834 | staprun_cmd.push_back(s.size_option); | |
835 | } | |
2fa2a091 | 836 | |
192130b3 | 837 | if (s.color_mode != s.color_auto) |
579f0947 JL |
838 | { |
839 | staprun_cmd.push_back("-C"); | |
6d3599fc JL |
840 | if (s.color_mode == s.color_always) |
841 | staprun_cmd.push_back("always"); | |
842 | else | |
192130b3 | 843 | staprun_cmd.push_back("never"); |
579f0947 JL |
844 | } |
845 | ||
10bb5efc FL |
846 | if (s.monitor) |
847 | { | |
848 | staprun_cmd.push_back("-M"); | |
09ddc83c | 849 | staprun_cmd.push_back(lex_cast(s.monitor_interval)); |
10bb5efc FL |
850 | } |
851 | ||
18630fb8 | 852 | staprun_cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir) |
4441e344 | 853 | + "/" + s.module_filename()); |
dff50e09 | 854 | |
bb25d08f | 855 | // add module arguments |
5eea6ed1 JS |
856 | staprun_cmd.insert(staprun_cmd.end(), |
857 | s.globalopts.begin(), s.globalopts.end()); | |
bb25d08f | 858 | |
daa75206 | 859 | return staprun_cmd; |
f4b28491 | 860 | } |
73267b89 | 861 | |
0a6f5a3f | 862 | |
c9ccb642 FCE |
863 | // Build tiny kernel modules to query tracepoints. |
864 | // Given a (header-file -> test-contents) map, compile them ASAP, and return | |
2a0e62a8 | 865 | // a (header-file -> obj-filename) map. |
c9ccb642 FCE |
866 | |
867 | map<string,string> | |
868 | make_tracequeries(systemtap_session& s, const map<string,string>& contents) | |
0a6f5a3f | 869 | { |
f982c59b | 870 | static unsigned tick = 0; |
aca66a36 | 871 | string basename("tracequery_kmod_" + lex_cast(++tick)); |
2a0e62a8 | 872 | map<string,string> objs; |
f982c59b | 873 | |
0a6f5a3f | 874 | // create a subdirectory for the module |
f982c59b | 875 | string dir(s.tmpdir + "/" + basename); |
0a6f5a3f JS |
876 | if (create_dir(dir.c_str()) != 0) |
877 | { | |
2713ea24 | 878 | s.print_warning("failed to create directory for querying tracepoints."); |
3e1ec884 | 879 | s.set_try_server (); |
2a0e62a8 | 880 | return objs; |
0a6f5a3f JS |
881 | } |
882 | ||
0a6f5a3f JS |
883 | // create a simple Makefile |
884 | string makefile(dir + "/Makefile"); | |
885 | ofstream omf(makefile.c_str()); | |
9ccda279 | 886 | // force debuginfo generation, and relax implicit functions |
2537a880 | 887 | omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration " << WERROR << endl; |
a7ec2317 FCE |
888 | // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules |
889 | omf << "CONFIG_MODULE_SIG := n" << endl; | |
890 | ||
8bb62408 JS |
891 | // PR18389: disable GCC's Identical Code Folding, since the stubs may look identical |
892 | omf << "EXTRA_CFLAGS += $(call cc-option,-fno-ipa-icf)" << endl; | |
893 | ||
18b13994 | 894 | omf << "EXTRA_CFLAGS += -I" + s.kernel_build_tree << endl; |
c9ccb642 FCE |
895 | if (s.kernel_source_tree != "") |
896 | omf << "EXTRA_CFLAGS += -I" + s.kernel_source_tree << endl; | |
ac4f2837 DS |
897 | for (unsigned i = 0; i < s.kernel_extra_cflags.size(); i++) |
898 | omf << "EXTRA_CFLAGS += " + s.kernel_extra_cflags[i] << endl; | |
0a6f5a3f | 899 | |
c9ccb642 FCE |
900 | omf << "obj-m := " << endl; |
901 | // write out each header-specific source file into a separate file | |
902 | for (map<string,string>::const_iterator it = contents.begin(); it != contents.end(); it++) | |
903 | { | |
904 | string sbasename = basename + "_" + lex_cast(++tick); // suffixed | |
905 | ||
906 | // write out source code | |
907 | string srcname = dir + "/" + sbasename + ".c"; | |
908 | string src = it->second; | |
909 | ofstream osrc(srcname.c_str()); | |
910 | osrc << src; | |
911 | osrc.close(); | |
912 | ||
77b163ae FCE |
913 | if (s.verbose > 2) |
914 | clog << _F("Processing tracepoint header %s with query %s", | |
915 | it->first.c_str(), srcname.c_str()) | |
916 | << endl; | |
917 | ||
c9ccb642 FCE |
918 | // arrange to build it |
919 | omf << "obj-m += " + sbasename + ".o" << endl; // NB: without <dir> prefix | |
2a0e62a8 | 920 | objs[it->first] = dir + "/" + sbasename + ".o"; |
c9ccb642 FCE |
921 | } |
922 | omf.close(); | |
0a6f5a3f JS |
923 | |
924 | // make the module | |
8e0a2563 | 925 | vector<string> make_cmd = make_make_objs_cmd(s, dir); |
e86f32ee | 926 | make_cmd.push_back ("-i"); // ignore errors, give rc 0 even in case of tracepoint header nits |
ff520ff4 JS |
927 | bool quiet = (s.verbose < 4); |
928 | int rc = run_make_cmd(s, make_cmd, quiet, quiet); | |
3e1ec884 DB |
929 | if (rc) |
930 | s.set_try_server (); | |
c2cf1b87 | 931 | |
e86f32ee FCE |
932 | // Sometimes we fail a tracequery due to PR9993 / PR11649 type |
933 | // kernel trace header problems. In this case, due to PR12729, we | |
934 | // used to get a lovely "Warning: make exited with status: 2" but no | |
c2cf1b87 FCE |
935 | // other useful diagnostic. -vvvv would let a user see what's up, |
936 | // but the user can't fix the problem even with that. | |
937 | ||
2a0e62a8 | 938 | return objs; |
0a6f5a3f JS |
939 | } |
940 | ||
3e1c25aa JS |
941 | |
942 | // Build a tiny kernel module to query type information | |
d90053e7 | 943 | static int |
da9e11bd | 944 | make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string& name) |
3e1c25aa JS |
945 | { |
946 | static unsigned tick = 0; | |
aca66a36 | 947 | string basename("typequery_kmod_" + lex_cast(++tick)); |
3e1c25aa JS |
948 | |
949 | // create a subdirectory for the module | |
950 | string dir(s.tmpdir + "/" + basename); | |
951 | if (create_dir(dir.c_str()) != 0) | |
952 | { | |
2713ea24 | 953 | s.print_warning("failed to create directory for querying types."); |
3e1ec884 | 954 | s.set_try_server (); |
3e1c25aa JS |
955 | return 1; |
956 | } | |
957 | ||
958 | name = dir + "/" + basename + ".ko"; | |
959 | ||
960 | // create a simple Makefile | |
961 | string makefile(dir + "/Makefile"); | |
962 | ofstream omf(makefile.c_str()); | |
963 | omf << "EXTRA_CFLAGS := -g -fno-eliminate-unused-debug-types" << endl; | |
3ae4cdf9 | 964 | |
a7ec2317 FCE |
965 | // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules |
966 | omf << "CONFIG_MODULE_SIG := n" << endl; | |
967 | ||
3ae4cdf9 JS |
968 | // NB: We use -include instead of #include because that gives us more power. |
969 | // Using #include searches relative to the source's path, which in this case | |
970 | // is /tmp/..., so that's not helpful. Using -include will search relative | |
971 | // to the cwd, which will be the kernel build root. This means if you have a | |
972 | // full kernel build tree, it's possible to get at types that aren't in the | |
973 | // normal include path, e.g.: | |
974 | // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->... | |
da9e11bd JS |
975 | omf << "CFLAGS_" << basename << ".o :="; |
976 | for (size_t i = 0; i < headers.size(); ++i) | |
ff520ff4 | 977 | omf << " -include " << lex_cast_qstring(headers[i]); // XXX right quoting? |
da9e11bd | 978 | omf << endl; |
3ae4cdf9 | 979 | |
3e1c25aa JS |
980 | omf << "obj-m := " + basename + ".o" << endl; |
981 | omf.close(); | |
982 | ||
983 | // create our empty source file | |
984 | string source(dir + "/" + basename + ".c"); | |
985 | ofstream osrc(source.c_str()); | |
986 | osrc.close(); | |
987 | ||
988 | // make the module | |
7d26ee02 | 989 | vector<string> make_cmd = make_make_cmd(s, dir); |
ff520ff4 JS |
990 | bool quiet = (s.verbose < 4); |
991 | int rc = run_make_cmd(s, make_cmd, quiet, quiet); | |
3e1ec884 DB |
992 | if (rc) |
993 | s.set_try_server (); | |
994 | return rc; | |
3e1c25aa JS |
995 | } |
996 | ||
997 | ||
998 | // Build a tiny user module to query type information | |
d90053e7 | 999 | static int |
da9e11bd | 1000 | make_typequery_umod(systemtap_session& s, const vector<string>& headers, string& name) |
3e1c25aa JS |
1001 | { |
1002 | static unsigned tick = 0; | |
1003 | ||
aca66a36 | 1004 | name = s.tmpdir + "/typequery_umod_" + lex_cast(++tick) + ".so"; |
3e1c25aa JS |
1005 | |
1006 | // make the module | |
3ae4cdf9 JS |
1007 | // |
1008 | // NB: As with kmod, using -include makes relative paths more useful. The | |
1009 | // cwd in this case will be the cwd of stap itself though, which may be | |
1010 | // trickier to deal with. It might be better to "cd `dirname $script`" | |
1011 | // first... | |
ff520ff4 JS |
1012 | vector<string> cmd; |
1013 | cmd.push_back("gcc"); | |
1014 | cmd.push_back("-shared"); | |
1015 | cmd.push_back("-g"); | |
1016 | cmd.push_back("-fno-eliminate-unused-debug-types"); | |
1017 | cmd.push_back("-xc"); | |
1018 | cmd.push_back("/dev/null"); | |
1019 | cmd.push_back("-o"); | |
1020 | cmd.push_back(name); | |
da9e11bd | 1021 | for (size_t i = 0; i < headers.size(); ++i) |
ff520ff4 JS |
1022 | { |
1023 | cmd.push_back("-include"); | |
1024 | cmd.push_back(headers[i]); | |
1025 | } | |
1026 | bool quiet = (s.verbose < 4); | |
1027 | int rc = stap_system (s.verbose, cmd, quiet, quiet); | |
3e1ec884 DB |
1028 | if (rc) |
1029 | s.set_try_server (); | |
1030 | return rc; | |
3e1c25aa JS |
1031 | } |
1032 | ||
d90053e7 JS |
1033 | |
1034 | int | |
1035 | make_typequery(systemtap_session& s, string& module) | |
1036 | { | |
1037 | int rc; | |
1038 | string new_module; | |
da9e11bd | 1039 | vector<string> headers; |
60d98537 | 1040 | bool kernel = startswith(module, "kernel"); |
d90053e7 | 1041 | |
da9e11bd | 1042 | for (size_t end, i = kernel ? 6 : 0; i < module.size(); i = end + 1) |
d90053e7 | 1043 | { |
da9e11bd JS |
1044 | if (module[i] != '<') |
1045 | return -1; | |
1046 | end = module.find('>', ++i); | |
1047 | if (end == string::npos) | |
1048 | return -1; | |
1049 | string header = module.substr(i, end - i); | |
504d2b61 | 1050 | vector<string> matches; |
5ef28d5a | 1051 | if (regexp_match(header, "^[a-zA-Z0-9/_.+-]+$", matches)) |
2713ea24 | 1052 | s.print_warning("skipping malformed @cast header \""+ header + "\""); |
504d2b61 JS |
1053 | else |
1054 | headers.push_back(header); | |
d90053e7 | 1055 | } |
da9e11bd | 1056 | if (headers.empty()) |
d90053e7 JS |
1057 | return -1; |
1058 | ||
da9e11bd JS |
1059 | if (kernel) |
1060 | rc = make_typequery_kmod(s, headers, new_module); | |
1061 | else | |
1062 | rc = make_typequery_umod(s, headers, new_module); | |
1063 | ||
d90053e7 JS |
1064 | if (!rc) |
1065 | module = new_module; | |
1066 | ||
1067 | return rc; | |
1068 | } | |
1069 | ||
73267b89 | 1070 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |