Branch data Line data Source code
1 : : // build/run probes
2 : : // Copyright (C) 2005-2013 Red Hat Inc.
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"
11 : : #include "session.h"
12 : : #include "util.h"
13 : : #include "hash.h"
14 : : #include "translate.h"
15 : :
16 : : #include <cstdlib>
17 : : #include <fstream>
18 : : #include <sstream>
19 : :
20 : : extern "C" {
21 : : #include <signal.h>
22 : : #include <sys/wait.h>
23 : : #include <pwd.h>
24 : : #include <grp.h>
25 : : #include <sys/types.h>
26 : : #include <sys/stat.h>
27 : : #include <unistd.h>
28 : : #include <string.h>
29 : : #include <errno.h>
30 : : }
31 : :
32 : :
33 : : using namespace std;
34 : :
35 : : /* Adjust and run make_cmd to build a kernel module. */
36 : : static int
37 : 622 : run_make_cmd(systemtap_session& s, vector<string>& make_cmd,
38 : : bool null_out=false, bool null_err=false)
39 : : {
40 : 622 : assert_no_interrupts();
41 : :
42 : : // PR14168: we used to unsetenv values here; instead do it via
43 : : // env(1) in make_any_make_cmd().
44 : :
45 : : // Disable ccache to avoid saving files that will never be reused.
46 : : // (ccache is useless to us, because our compiler commands always
47 : : // include the randomized tmpdir path.)
48 : : // It's not critical if this fails, so the return is ignored.
49 : 622 : (void) setenv("CCACHE_DISABLE", "1", 0);
50 : :
51 [ + + ]: 622 : if (s.verbose > 2)
52 [ + - ][ + - ]: 1 : make_cmd.push_back("V=1");
[ + - ]
53 [ + + ]: 621 : else if (s.verbose > 1)
54 [ + - ][ + - ]: 15 : make_cmd.push_back("--no-print-directory");
[ + - ]
55 : : else
56 : : {
57 [ + - ][ + - ]: 606 : make_cmd.push_back("-s");
[ + - ]
58 [ + - ][ + - ]: 606 : make_cmd.push_back("--no-print-directory");
[ + - ]
59 : : }
60 : :
61 : : // Exploit SMP parallelism, if available.
62 : 622 : long smp = sysconf(_SC_NPROCESSORS_ONLN);
63 [ + - ]: 622 : if (smp >= 1)
64 [ + - ][ + - ]: 622 : make_cmd.push_back("-j" + lex_cast(smp+1));
[ + - ][ + - ]
[ + - ]
65 : :
66 [ - + ]: 622 : if (strverscmp (s.kernel_base_release.c_str(), "2.6.29") < 0)
67 : : {
68 : : // Older kernels, before linux commit #fd54f502841c1, include
69 : : // gratuitous "echo"s in their Makefile. We need to suppress
70 : : // that with this bluntness.
71 : 0 : null_out = true;
72 : : }
73 : :
74 [ + - ][ + - ]: 622 : int rc = stap_system (s.verbose, "kbuild", make_cmd, null_out, null_err);
[ + - ]
75 [ + + ]: 622 : if (rc != 0)
76 : 5 : s.set_try_server ();
77 : 622 : return rc;
78 : : }
79 : :
80 : : static vector<string>
81 : 622 : make_any_make_cmd(systemtap_session& s, const string& dir, const string& target)
82 : : {
83 [ + - ]: 622 : vector<string> make_cmd;
84 : :
85 : : // PR14168: sanitize environment variables for kbuild invocation
86 [ + - ][ + - ]: 622 : make_cmd.push_back("env");
[ + - ]
87 [ + - ][ + - ]: 622 : make_cmd.push_back("-uARCH");
[ + - ]
88 [ + - ][ + - ]: 622 : make_cmd.push_back("-uKBUILD_EXTMOD");
[ + - ]
89 [ + - ][ + - ]: 622 : make_cmd.push_back("-uCROSS_COMPILE");
[ + - ]
90 [ + - ][ + - ]: 622 : make_cmd.push_back("-uKBUILD_IMAGE");
[ + - ]
91 [ + - ][ + - ]: 622 : make_cmd.push_back("-uKCONFIG_CONFIG");
[ + - ]
92 [ + - ][ + - ]: 622 : make_cmd.push_back("-uINSTALL_PATH");
[ + - ]
93 [ + - ][ + - ]: 622 : string newpath = string("PATH=/usr/bin:/bin:") + (getenv("PATH") ?: "");
[ + - ][ + - ]
94 [ + - ][ + - ]: 622 : make_cmd.push_back(newpath.c_str());
[ + - ][ + - ]
95 : :
96 [ + - ][ + - ]: 622 : make_cmd.push_back("make");
[ + - ]
97 [ + - ][ + - ]: 622 : make_cmd.push_back("-C");
[ + - ]
98 [ + - ]: 622 : make_cmd.push_back(s.kernel_build_tree);
99 [ + - ][ + - ]: 622 : make_cmd.push_back("M=" + dir); // need make-quoting?
[ + - ]
100 [ + - ]: 622 : make_cmd.push_back(target);
101 : :
102 : : // Add architecture, except for old powerpc (RHBZ669082)
103 [ + - ]: 622 : if (s.architecture != "powerpc" ||
[ - + # # ]
[ + - ]
104 [ # # ]: 0 : (strverscmp (s.kernel_base_release.c_str(), "2.6.15") >= 0))
105 [ + - ][ + - ]: 622 : make_cmd.push_back("ARCH=" + s.architecture); // need make-quoting?
[ + - ]
106 : :
107 : : // PR13847: suppress debuginfo creation by default
108 [ + - ][ + - ]: 622 : make_cmd.insert(make_cmd.end(), "CONFIG_DEBUG_INFO=");
[ + - ][ + - ]
109 : :
110 : : // Add any custom kbuild flags
111 [ + - ][ + - ]: 622 : make_cmd.insert(make_cmd.end(), s.kbuildflags.begin(), s.kbuildflags.end());
[ + - ][ + - ]
112 : :
113 [ + - ]: 622 : return make_cmd;
114 : : }
115 : :
116 : : static vector<string>
117 : 621 : make_make_cmd(systemtap_session& s, const string& dir)
118 : : {
119 [ + - ][ + - ]: 621 : return make_any_make_cmd(s, dir, "modules");
[ + - ]
120 : : }
121 : :
122 : : static vector<string>
123 : 1 : make_make_objs_cmd(systemtap_session& s, const string& dir)
124 : : {
125 : : // Kbuild uses these rules to build external modules:
126 : : //
127 : : // module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD))
128 : : // modules: $(module-dirs)
129 : : // @$(kecho) ' Building modules, stage 2.';
130 : : // $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
131 : : //
132 : : // So if we're only interested in the stage 1 objects, we can
133 : : // cheat and make only the $(module-dirs) part.
134 [ + - ]: 1 : return make_any_make_cmd(s, dir, "_module_" + dir);
135 : : }
136 : :
137 : : static void
138 : 30086 : output_autoconf(systemtap_session& s, ofstream& o, const char *autoconf_c,
139 : : const char *deftrue, const char *deffalse)
140 : : {
141 : 30086 : o << "\t";
142 [ + - ]: 30086 : if (s.verbose < 4)
143 : 30086 : o << "@";
144 : 30086 : o << "if $(CHECK_BUILD) $(SYSTEMTAP_RUNTIME)/linux/" << autoconf_c;
145 [ + - ]: 30086 : if (s.verbose < 5)
146 : 30086 : o << " > /dev/null 2>&1";
147 : 30086 : o << "; then ";
148 [ + - ]: 30086 : if (deftrue)
149 : 30086 : o << "echo \"#define " << deftrue << " 1\"";
150 [ - + ]: 30086 : if (deffalse)
151 : 0 : o << "; else echo \"#define " << deffalse << " 1\"";
152 : 30086 : o << "; fi >> $@" << endl;
153 : 30086 : }
154 : :
155 : :
156 : 11666 : void output_exportconf(systemtap_session& s, ofstream& o, const char *symbol,
157 : : const char *deftrue)
158 : : {
159 : 11666 : o << "\t";
160 [ + - ]: 11666 : if (s.verbose < 4)
161 : 11666 : o << "@";
162 [ + - ][ + - ]: 11666 : if (s.kernel_exports.find(symbol) != s.kernel_exports.end())
[ + - ][ + - ]
[ + + ]
163 : 4298 : o << "echo \"#define " << deftrue << " 1\"";
164 : 11666 : o << ">> $@" << endl;
165 : 11666 : }
166 : :
167 : :
168 : 1842 : void output_dual_exportconf(systemtap_session& s, ofstream& o,
169 : : const char *symbol1, const char *symbol2,
170 : : const char *deftrue)
171 : : {
172 : 1842 : o << "\t";
173 [ + - ]: 1842 : if (s.verbose < 4)
174 : 1842 : o << "@";
175 [ + - ][ + - ]: 5526 : if (s.kernel_exports.find(symbol1) != s.kernel_exports.end()
[ + - ]
[ + - + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + -
# # # # #
# # # ]
176 [ + - ][ + - ]: 3684 : && s.kernel_exports.find(symbol2) != s.kernel_exports.end())
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ # # # #
# # # # ]
177 : 1842 : o << "echo \"#define " << deftrue << " 1\"";
178 : 1842 : o << ">> $@" << endl;
179 : 1842 : }
180 : :
181 : :
182 : 1228 : void output_either_exportconf(systemtap_session& s, ofstream& o,
183 : : const char *symbol1, const char *symbol2,
184 : : const char *deftrue)
185 : : {
186 : 1228 : o << "\t";
187 [ + - ]: 1228 : if (s.verbose < 4)
188 : 1228 : o << "@";
189 [ + - ][ + - ]: 3684 : if (s.kernel_exports.find(symbol1) != s.kernel_exports.end()
[ + - ]
[ + - - + ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ - +
# # # # #
# # # ]
190 [ + - ][ + - ]: 2456 : || s.kernel_exports.find(symbol2) != s.kernel_exports.end())
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ # # # #
# # # # ]
191 : 0 : o << "echo \"#define " << deftrue << " 1\"";
192 : 1228 : o << ">> $@" << endl;
193 : 1228 : }
194 : :
195 : :
196 : : static int
197 : 0 : compile_dyninst (systemtap_session& s)
198 : : {
199 [ # # ][ # # ]: 0 : const string module = s.tmpdir + "/" + s.module_filename();
[ # # ][ # # ]
[ # # ]
200 : :
201 [ # # ]: 0 : vector<string> cmd;
202 [ # # ][ # # ]: 0 : cmd.push_back("gcc");
[ # # ]
203 [ # # ][ # # ]: 0 : cmd.push_back("--std=gnu99");
[ # # ]
204 [ # # ][ # # ]: 0 : cmd.push_back("-Wall");
[ # # ]
205 [ # # ][ # # ]: 0 : cmd.push_back("-Werror");
[ # # ]
206 [ # # ][ # # ]: 0 : cmd.push_back("-Wno-unused");
[ # # ]
207 [ # # ][ # # ]: 0 : cmd.push_back("-Wno-strict-aliasing");
[ # # ]
208 [ # # ][ # # ]: 0 : cmd.push_back("-O2");
[ # # ]
209 [ # # ][ # # ]: 0 : cmd.push_back("-I" + s.runtime_path);
[ # # ]
210 [ # # ][ # # ]: 0 : cmd.push_back("-D__DYNINST__");
[ # # ]
211 [ # # ]: 0 : for (size_t i = 0; i < s.c_macros.size(); ++i)
212 [ # # ][ # # ]: 0 : cmd.push_back("-D" + s.c_macros[i]);
[ # # ]
213 [ # # ]: 0 : cmd.push_back(s.translated_source);
214 [ # # ][ # # ]: 0 : cmd.push_back("-pthread");
[ # # ]
215 [ # # ][ # # ]: 0 : cmd.push_back("-lrt");
[ # # ]
216 [ # # ][ # # ]: 0 : cmd.push_back("-fPIC");
[ # # ]
217 [ # # ][ # # ]: 0 : cmd.push_back("-shared");
[ # # ]
218 [ # # ][ # # ]: 0 : cmd.push_back("-o");
[ # # ]
219 [ # # ]: 0 : cmd.push_back(module);
220 [ # # ]: 0 : if (s.verbose > 3)
221 : : {
222 [ # # ][ # # ]: 0 : cmd.push_back("-ftime-report");
[ # # ]
223 [ # # ][ # # ]: 0 : cmd.push_back("-Q");
[ # # ]
224 : : }
225 : :
226 [ # # ]: 0 : int rc = stap_system (s.verbose, cmd);
227 [ # # ]: 0 : if (rc)
228 [ # # ]: 0 : s.set_try_server ();
229 [ # # ][ # # ]: 0 : return rc;
230 : : }
231 : :
232 : :
233 : : int
234 : 624 : compile_pass (systemtap_session& s)
235 : : {
236 [ - + ]: 624 : if (s.runtime_usermode_p())
237 [ # # ]: 0 : return compile_dyninst (s);
238 : :
239 [ + - ]: 624 : int rc = uprobes_pass (s);
240 [ + + ]: 624 : if (rc)
241 : : {
242 [ + - ]: 10 : s.set_try_server ();
243 : 10 : return rc;
244 : : }
245 : :
246 : : // fill in a quick Makefile
247 [ + - ]: 614 : string makefile_nm = s.tmpdir + "/Makefile";
248 [ + - ][ + - ]: 614 : ofstream o (makefile_nm.c_str());
249 : :
250 : : // Create makefile
251 : :
252 : : // Clever hacks copied from vmware modules
253 [ + - ]: 614 : string superverbose;
254 [ - + ]: 614 : if (s.verbose > 3)
255 [ # # ]: 0 : superverbose = "set -x;";
256 : :
257 [ + - ]: 614 : string redirecterrors = "> /dev/null 2>&1";
258 [ - + ]: 614 : if (s.verbose > 6)
259 [ # # ]: 0 : redirecterrors = "";
260 : :
261 : : // Support O= (or KBUILD_OUTPUT) option
262 [ + - ][ + - ]: 614 : o << "_KBUILD_CFLAGS := $(call flags,KBUILD_CFLAGS)" << endl;
263 : :
264 [ + - ][ + - ]: 614 : 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;
[ + - ][ + - ]
265 [ + - ][ + - ]: 614 : o << "CHECK_BUILD := $(CC) $(NOSTDINC_FLAGS) $(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;
[ + - ][ - + ]
[ + - ][ + - ]
[ + - ]
266 [ + - ][ + - ]: 614 : o << "stap_check_build = $(shell " << superverbose << " if $(CHECK_BUILD) $(1) " << redirecterrors << " ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl;
[ + - ][ + - ]
[ + - ][ + - ]
267 : :
268 [ + - ][ + - ]: 614 : o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl;
[ + - ][ + - ]
269 : :
270 : : // "autoconf" options go here
271 : :
272 : : // RHBZ 543529: early rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules
273 [ + - ][ + - ]: 614 : o << "CONFIG_MODULE_SIG := n" << endl;
274 : :
275 [ + - ]: 614 : string module_cflags = "EXTRA_CFLAGS";
276 [ + - ][ + - ]: 614 : o << module_cflags << " :=" << endl;
[ + - ]
277 : :
278 : : // XXX: This gruesome hack is needed on some kernels built with separate O=directory,
279 : : // where files like 2.6.27 x86's asm/mach-*/mach_mpspec.h are not found on the cpp path.
280 : : // This could be a bug in arch/x86/Makefile that names
281 : : // mflags-y += -Iinclude/asm-x86/mach-default
282 : : // but that path does not exist in an O= build tree.
283 [ + - ][ + - ]: 614 : o << module_cflags << " += -Iinclude2/asm/mach-default" << endl;
[ + - ]
284 [ + - ][ + + ]: 614 : if (s.kernel_source_tree != "")
285 [ + - ][ + - ]: 41 : o << module_cflags << " += -I" + s.kernel_source_tree << endl;
[ + - ][ + - ]
[ + - ]
286 : :
287 : : // NB: don't try
288 : : // o << module_cflags << " += -Iusr/include" << endl;
289 : : // since such headers are cleansed of _KERNEL_ pieces that we need
290 : :
291 [ + - ][ + - ]: 614 : o << "STAPCONF_HEADER := " << s.tmpdir << "/" << s.stapconf_name << endl;
[ + - ][ + - ]
[ + - ]
292 [ + - ][ + - ]: 614 : o << "$(STAPCONF_HEADER):" << endl;
293 [ + - ][ + - ]: 614 : o << "\t@echo -n > $@" << endl;
294 [ + - ]: 614 : output_autoconf(s, o, "autoconf-hrtimer-rel.c", "STAPCONF_HRTIMER_REL", NULL);
295 [ + - ]: 614 : output_autoconf(s, o, "autoconf-generated-compile.c", "STAPCONF_GENERATED_COMPILE", NULL);
296 [ + - ]: 614 : output_autoconf(s, o, "autoconf-hrtimer-getset-expires.c", "STAPCONF_HRTIMER_GETSET_EXPIRES", NULL);
297 [ + - ]: 614 : output_autoconf(s, o, "autoconf-inode-private.c", "STAPCONF_INODE_PRIVATE", NULL);
298 [ + - ]: 614 : output_autoconf(s, o, "autoconf-constant-tsc.c", "STAPCONF_CONSTANT_TSC", NULL);
299 [ + - ]: 614 : output_autoconf(s, o, "autoconf-ktime-get-real.c", "STAPCONF_KTIME_GET_REAL", NULL);
300 [ + - ]: 614 : output_autoconf(s, o, "autoconf-x86-uniregs.c", "STAPCONF_X86_UNIREGS", NULL);
301 [ + - ]: 614 : output_autoconf(s, o, "autoconf-nameidata.c", "STAPCONF_NAMEIDATA_CLEANUP", NULL);
302 [ + - ]: 614 : output_dual_exportconf(s, o, "unregister_kprobes", "unregister_kretprobes", "STAPCONF_UNREGISTER_KPROBES");
303 [ + - ]: 614 : output_autoconf(s, o, "autoconf-kprobe-symbol-name.c", "STAPCONF_KPROBE_SYMBOL_NAME", NULL);
304 [ + - ]: 614 : output_autoconf(s, o, "autoconf-real-parent.c", "STAPCONF_REAL_PARENT", NULL);
305 [ + - ]: 614 : output_autoconf(s, o, "autoconf-uaccess.c", "STAPCONF_LINUX_UACCESS_H", NULL);
306 [ + - ]: 614 : output_autoconf(s, o, "autoconf-oneachcpu-retry.c", "STAPCONF_ONEACHCPU_RETRY", NULL);
307 [ + - ]: 614 : output_autoconf(s, o, "autoconf-dpath-path.c", "STAPCONF_DPATH_PATH", NULL);
308 [ + - ]: 614 : output_exportconf(s, o, "synchronize_sched", "STAPCONF_SYNCHRONIZE_SCHED");
309 [ + - ]: 614 : output_autoconf(s, o, "autoconf-task-uid.c", "STAPCONF_TASK_UID", NULL);
310 [ + - ]: 614 : output_dual_exportconf(s, o, "alloc_vm_area", "free_vm_area", "STAPCONF_VM_AREA");
311 [ + - ]: 614 : output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL);
312 [ + - ]: 614 : output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL);
313 [ + - ]: 614 : output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL);
314 [ + - ]: 614 : output_autoconf(s, o, "autoconf-grsecurity.c", "STAPCONF_GRSECURITY", NULL);
315 [ + - ]: 614 : output_autoconf(s, o, "autoconf-trace-printk.c", "STAPCONF_TRACE_PRINTK", NULL);
316 [ + - ]: 614 : output_autoconf(s, o, "autoconf-regset.c", "STAPCONF_REGSET", NULL);
317 [ + - ]: 614 : output_autoconf(s, o, "autoconf-utrace-regset.c", "STAPCONF_UTRACE_REGSET", NULL);
318 [ + - ]: 614 : output_autoconf(s, o, "autoconf-uprobe-get-pc.c", "STAPCONF_UPROBE_GET_PC", NULL);
319 [ + - ]: 614 : output_autoconf(s, o, "autoconf-hlist-4args.c", "STAPCONF_HLIST_4ARGS", NULL);
320 [ + - ]: 614 : output_exportconf(s, o, "tsc_khz", "STAPCONF_TSC_KHZ");
321 [ + - ]: 614 : output_exportconf(s, o, "cpu_khz", "STAPCONF_CPU_KHZ");
322 [ + - ]: 614 : output_exportconf(s, o, "__module_text_address", "STAPCONF_MODULE_TEXT_ADDRESS");
323 [ + - ]: 614 : output_exportconf(s, o, "add_timer_on", "STAPCONF_ADD_TIMER_ON");
324 : :
325 [ + - ]: 614 : output_dual_exportconf(s, o, "probe_kernel_read", "probe_kernel_write", "STAPCONF_PROBE_KERNEL");
326 : : output_autoconf(s, o, "autoconf-hw_breakpoint_context.c",
327 [ + - ]: 614 : "STAPCONF_HW_BREAKPOINT_CONTEXT", NULL);
328 : : output_autoconf(s, o, "autoconf-save-stack-trace.c",
329 [ + - ]: 614 : "STAPCONF_KERNEL_STACKTRACE", NULL);
330 : : output_autoconf(s, o, "autoconf-save-stack-trace-no-bp.c",
331 [ + - ]: 614 : "STAPCONF_KERNEL_STACKTRACE_NO_BP", NULL);
332 : : output_autoconf(s, o, "autoconf-asm-syscall.c",
333 [ + - ]: 614 : "STAPCONF_ASM_SYSCALL_H", NULL);
334 [ + - ]: 614 : output_autoconf(s, o, "autoconf-ring_buffer-flags.c", "STAPCONF_RING_BUFFER_FLAGS", NULL);
335 [ + - ]: 614 : output_autoconf(s, o, "autoconf-ring_buffer_lost_events.c", "STAPCONF_RING_BUFFER_LOST_EVENTS", NULL);
336 [ + - ]: 614 : output_autoconf(s, o, "autoconf-ring_buffer_read_prepare.c", "STAPCONF_RING_BUFFER_READ_PREPARE", NULL);
337 [ + - ]: 614 : output_autoconf(s, o, "autoconf-kallsyms-on-each-symbol.c", "STAPCONF_KALLSYMS_ON_EACH_SYMBOL", NULL);
338 [ + - ]: 614 : output_autoconf(s, o, "autoconf-walk-stack.c", "STAPCONF_WALK_STACK", NULL);
339 : : output_autoconf(s, o, "autoconf-stacktrace_ops-warning.c",
340 [ + - ]: 614 : "STAPCONF_STACKTRACE_OPS_WARNING", NULL);
341 [ + - ]: 614 : output_autoconf(s, o, "autoconf-mm-context-vdso.c", "STAPCONF_MM_CONTEXT_VDSO", NULL);
342 [ + - ]: 614 : output_autoconf(s, o, "autoconf-mm-context-vdso-base.c", "STAPCONF_MM_CONTEXT_VDSO_BASE", NULL);
343 [ + - ]: 614 : output_autoconf(s, o, "autoconf-blk-types.c", "STAPCONF_BLK_TYPES", NULL);
344 [ + - ]: 614 : output_autoconf(s, o, "autoconf-perf-structpid.c", "STAPCONF_PERF_STRUCTPID", NULL);
345 : : output_autoconf(s, o, "perf_event_counter_context.c",
346 [ + - ]: 614 : "STAPCONF_PERF_COUNTER_CONTEXT", NULL);
347 : : output_autoconf(s, o, "perf_probe_handler_nmi.c",
348 [ + - ]: 614 : "STAPCONF_PERF_HANDLER_NMI", NULL);
349 [ + - ]: 614 : output_exportconf(s, o, "path_lookup", "STAPCONF_PATH_LOOKUP");
350 [ + - ]: 614 : output_exportconf(s, o, "kern_path_parent", "STAPCONF_KERN_PATH_PARENT");
351 [ + - ]: 614 : output_exportconf(s, o, "vfs_path_lookup", "STAPCONF_VFS_PATH_LOOKUP");
352 [ + - ]: 614 : output_autoconf(s, o, "autoconf-module-sect-attrs.c", "STAPCONF_MODULE_SECT_ATTRS", NULL);
353 : :
354 [ + - ]: 614 : output_autoconf(s, o, "autoconf-utrace-via-tracepoints.c", "STAPCONF_UTRACE_VIA_TRACEPOINTS", NULL);
355 [ + - ]: 614 : output_autoconf(s, o, "autoconf-task_work-struct.c", "STAPCONF_TASK_WORK_STRUCT", NULL);
356 [ + - ]: 614 : output_autoconf(s, o, "autoconf-vm-area-pte.c", "STAPCONF_VM_AREA_PTE", NULL);
357 [ + - ]: 614 : output_autoconf(s, o, "autoconf-relay-umode_t.c", "STAPCONF_RELAY_UMODE_T", NULL);
358 [ + - ]: 614 : output_autoconf(s, o, "autoconf-fs_supers-hlist.c", "STAPCONF_FS_SUPERS_HLIST", NULL);
359 : :
360 : : // used by tapset/timestamp_monotonic.stp
361 [ + - ]: 614 : output_exportconf(s, o, "cpu_clock", "STAPCONF_CPU_CLOCK");
362 [ + - ]: 614 : output_exportconf(s, o, "local_clock", "STAPCONF_LOCAL_CLOCK");
363 : :
364 : : // used by runtime/uprobe-inode.c
365 : : output_either_exportconf(s, o, "uprobe_register", "register_uprobe",
366 [ + - ]: 614 : "STAPCONF_UPROBE_REGISTER_EXPORTED");
367 : : output_either_exportconf(s, o, "uprobe_unregister", "unregister_uprobe",
368 [ + - ]: 614 : "STAPCONF_UPROBE_UNREGISTER_EXPORTED");
369 [ + - ]: 614 : output_exportconf(s, o, "uretprobe_register", "STAPCONF_URETPROBE_REGISTER_EXPORTED");
370 [ + - ]: 614 : output_exportconf(s, o, "uretprobe_unregister", "STAPCONF_URETPROBE_UNREGISTER_EXPORTED");
371 [ + - ]: 614 : output_autoconf(s, o, "autoconf-old-inode-uprobes.c", "STAPCONF_OLD_INODE_UPROBES", NULL);
372 [ + - ]: 614 : output_autoconf(s, o, "autoconf-inode-uprobes-noaddr.c", "STAPCONF_INODE_UPROBES_NOADDR", NULL);
373 [ + - ]: 614 : output_autoconf(s, o, "autoconf-inode-uretprobes.c", "STAPCONF_INODE_URETPROBES", NULL);
374 : :
375 : : // used by tapsets.cxx inode uprobe generated code
376 [ + - ]: 614 : output_exportconf(s, o, "uprobe_get_swbp_addr", "STAPCONF_UPROBE_GET_SWBP_ADDR_EXPORTED");
377 : :
378 : : // used by runtime/loc2c-runtime.h
379 [ + - ]: 614 : output_exportconf(s, o, "task_user_regset_view", "STAPCONF_TASK_USER_REGSET_VIEW_EXPORTED");
380 : :
381 : : // used by runtime/stp_utrace.c
382 [ + - ]: 614 : output_exportconf(s, o, "task_work_add", "STAPCONF_TASK_WORK_ADD_EXPORTED");
383 [ + - ]: 614 : output_exportconf(s, o, "signal_wake_up_state", "STAPCONF_SIGNAL_WAKE_UP_STATE_EXPORTED");
384 [ + - ]: 614 : output_exportconf(s, o, "signal_wake_up", "STAPCONF_SIGNAL_WAKE_UP_EXPORTED");
385 [ + - ]: 614 : output_exportconf(s, o, "__lock_task_sighand", "STAPCONF___LOCK_TASK_SIGHAND_EXPORTED");
386 : :
387 [ + - ]: 614 : output_autoconf(s, o, "autoconf-pagefault_disable.c", "STAPCONF_PAGEFAULT_DISABLE", NULL);
388 [ + - ]: 614 : output_exportconf(s, o, "kallsyms_lookup_name", "STAPCONF_KALLSYMS");
389 : :
390 [ + - ][ + - ]: 614 : o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl;
[ + - ]
391 : :
392 [ + + ]: 711 : for (unsigned i=0; i<s.c_macros.size(); i++)
393 [ + - ][ + - ]: 97 : o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.c_macros[i]) << endl; // XXX right quoting?
[ + - ][ + - ]
[ + - ]
394 : :
395 [ - + ]: 614 : if (s.verbose > 3)
396 [ # # ][ # # ]: 0 : o << "EXTRA_CFLAGS += -ftime-report -Q" << endl;
397 : :
398 : : // XXX: unfortunately, -save-temps can't work since linux kbuild cwd
399 : : // is not writable.
400 : : //
401 : : // if (s.keep_tmpdir)
402 : : // o << "CFLAGS += -fverbose-asm -save-temps" << endl;
403 : :
404 : : // Kernels can be compiled with CONFIG_CC_OPTIMIZE_FOR_SIZE to select
405 : : // -Os, otherwise -O2 is the default.
406 [ + - ][ + - ]: 614 : o << "EXTRA_CFLAGS += -freorder-blocks" << endl; // improve on -Os
407 : :
408 : : // We used to allow the user to override default optimization when so
409 : : // requested by adding a -O[0123s] so they could determine the
410 : : // time/space/speed tradeoffs themselves, but we cannot guantantee that
411 : : // the (un)optimized code actually compiles and/or generates functional
412 : : // code, so we had to remove it.
413 : : // o << "EXTRA_CFLAGS += " << s.gcc_flags << endl; // Add -O[0123s]
414 : :
415 : : // o << "CFLAGS += -fno-unit-at-a-time" << endl;
416 : :
417 : : // 256 bytes should be enough for anybody
418 : : // XXX this doesn't validate varargs, per gcc bug #41633
419 [ + - ][ + - ]: 614 : o << "EXTRA_CFLAGS += $(call cc-option,-Wframe-larger-than=256)" << endl;
420 : :
421 : : // Assumes linux 2.6 kbuild
422 [ + - ][ - + ]: 614 : o << "EXTRA_CFLAGS += -Wno-unused" << (s.omit_werror ? "" : " -Werror") << endl;
[ + - ][ + - ]
423 : : #if CHECK_POINTER_ARITH_PR5947
424 : : o << "EXTRA_CFLAGS += -Wpointer-arith" << endl;
425 : : #endif
426 [ + - ][ + - ]: 614 : o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl;
[ + - ][ + - ]
427 : : // XXX: this may help ppc toc overflow
428 : : // o << "CFLAGS := $(subst -Os,-O2,$(CFLAGS)) -fminimal-toc" << endl;
429 [ + - ][ + - ]: 614 : o << "obj-m := " << s.module_name << ".o" << endl;
[ + - ][ + - ]
430 : :
431 : : // print out all the auxiliary source (->object) file names
432 [ + - ][ + - ]: 614 : o << s.module_name << "-y := ";
433 [ + + ]: 724 : for (unsigned i=0; i<s.auxiliary_outputs.size(); i++)
434 : : {
435 [ + - ]: 110 : string srcname = s.auxiliary_outputs[i]->filename;
436 [ + - ][ + - ]: 110 : assert (srcname != "" && srcname.rfind('/') != string::npos);
[ + - ][ - + ]
437 [ + - ][ + - ]: 110 : string objname = srcname.substr(srcname.rfind('/')+1); // basename
438 [ + - ][ + - ]: 110 : assert (objname != "" && objname[objname.size()-1] == 'c');
[ + - ][ + - ]
[ - + ]
439 [ + - ][ + - ]: 110 : objname[objname.size()-1] = 'o'; // now objname
440 [ + - ][ + - ]: 110 : o << " " + objname;
[ + - ]
441 [ + - ][ + - ]: 110 : }
442 : : // and once again, for the translated_source file. It can't simply
443 : : // be named MODULENAME.c, since kbuild doesn't allow a foo.ko file
444 : : // consisting of multiple .o's to have foo.o/foo.c as a source.
445 : : // (It uses ld -r -o foo.o EACH.o EACH.o).
446 : : {
447 [ + - ]: 614 : string srcname = s.translated_source;
448 [ + - ][ + - ]: 614 : assert (srcname != "" && srcname.rfind('/') != string::npos);
[ + - ][ - + ]
449 [ + - ][ + - ]: 614 : string objname = srcname.substr(srcname.rfind('/')+1); // basename
450 [ + - ][ + - ]: 614 : assert (objname != "" && objname[objname.size()-1] == 'c');
[ + - ][ + - ]
[ - + ]
451 [ + - ][ + - ]: 614 : objname[objname.size()-1] = 'o'; // now objname
452 [ + - ][ + - ]: 614 : o << " " + objname;
[ + - ][ + - ]
[ + - ]
453 : : }
454 [ + - ]: 614 : o << endl;
455 : :
456 : : // add all stapconf dependencies
457 [ + - ][ + - ]: 614 : o << s.translated_source << ": $(STAPCONF_HEADER)" << endl;
[ + - ]
458 [ + + ]: 724 : for (unsigned i=0; i<s.auxiliary_outputs.size(); i++)
459 [ + - ][ + - ]: 110 : o << s.auxiliary_outputs[i]->filename << ": $(STAPCONF_HEADER)" << endl;
[ + - ]
460 : :
461 : :
462 [ + - ]: 614 : o.close ();
463 : :
464 : : // Generate module directory pathname and make sure it exists.
465 [ + - ]: 614 : string module_dir = s.kernel_build_tree;
466 [ + - ]: 614 : string module_dir_makefile = module_dir + "/Makefile";
467 : : struct stat st;
468 [ + - ]: 614 : rc = stat(module_dir_makefile.c_str(), &st);
469 [ - + ]: 614 : if (rc != 0)
470 : : {
471 [ # # ][ # # ]: 0 : clog << _F("Checking \" %s \" failed with error: %s\nEnsure kernel development headers & makefiles are installed.",
[ # # ][ # # ]
472 [ # # ]: 0 : module_dir_makefile.c_str(), strerror(errno)) << endl;
473 [ # # ]: 0 : s.set_try_server ();
474 : 0 : return rc;
475 : : }
476 : :
477 : : // Run make
478 [ + - ]: 614 : vector<string> make_cmd = make_make_cmd(s, s.tmpdir);
479 [ + - ]: 614 : rc = run_make_cmd(s, make_cmd);
480 [ + + ]: 614 : if (rc)
481 [ + - ]: 5 : s.set_try_server ();
482 [ + - ][ + - ]: 624 : return rc;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
483 : : }
484 : :
485 : : /*
486 : : * If uprobes was built as part of the kernel build (either built-in
487 : : * or as a module), the uprobes exports should show up. This is to be
488 : : * as distinct from the stap-built uprobes.ko from the runtime.
489 : : */
490 : : static bool
491 : 10 : kernel_built_uprobes (systemtap_session& s)
492 : : {
493 [ - + ]: 10 : if (s.runtime_usermode_p())
494 : 0 : return true; // sort of, via dyninst
495 : :
496 : : // see also tapsets.cxx:kernel_supports_inode_uprobes()
497 [ + - ][ + - ]: 20 : return ((s.kernel_config["CONFIG_ARCH_SUPPORTS_UPROBES"] == "y" && s.kernel_config["CONFIG_UPROBES"] == "y") ||
[ + - ][ # # ]
[ # # ][ # # ]
[ - + ][ # # ]
[ - + ][ + - ]
[ + - ][ + - ]
[ # # # #
# # # # ]
498 [ - + ][ # # ]: 10 : (s.kernel_exports.find("unregister_uprobe") != s.kernel_exports.end()));
[ + - ][ + - ]
[ + - ][ - + ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ # #
# # # # #
# ]
499 : : }
500 : :
501 : : static int
502 : 0 : make_uprobes (systemtap_session& s)
503 : : {
504 [ # # ]: 0 : if (s.verbose > 1)
505 [ # # ]: 0 : clog << _("Pass 4, preamble: (re)building SystemTap's version of uprobes.")
506 [ # # ]: 0 : << endl;
507 : :
508 : : // create a subdirectory for the uprobes module
509 [ # # ]: 0 : string dir(s.tmpdir + "/uprobes");
510 [ # # ][ # # ]: 0 : if (create_dir(dir.c_str()) != 0)
[ # # ]
511 : : {
512 [ # # ][ # # ]: 0 : s.print_warning("failed to create directory for build uprobes.");
[ # # ]
513 [ # # ]: 0 : s.set_try_server ();
514 : 0 : return 1;
515 : : }
516 : :
517 : : // create a simple Makefile
518 [ # # ]: 0 : string makefile(dir + "/Makefile");
519 [ # # ][ # # ]: 0 : ofstream omf(makefile.c_str());
520 [ # # ][ # # ]: 0 : omf << "obj-m := uprobes.o" << endl;
521 : : // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules
522 [ # # ][ # # ]: 0 : omf << "CONFIG_MODULE_SIG := n" << endl;
523 [ # # ]: 0 : omf.close();
524 : :
525 : : // create a simple #include-chained source file
526 [ # # ]: 0 : string runtimesourcefile(s.runtime_path + "/linux/uprobes/uprobes.c");
527 [ # # ]: 0 : string sourcefile(dir + "/uprobes.c");
528 [ # # ][ # # ]: 0 : ofstream osrc(sourcefile.c_str());
529 [ # # ][ # # ]: 0 : osrc << "#include \"" << runtimesourcefile << "\"" << endl;
[ # # ][ # # ]
530 : :
531 : : // pass --modinfo k=v to uprobes build too
532 [ # # ]: 0 : for (unsigned i = 0; i < s.modinfos.size(); i++)
533 : : {
534 : 0 : const string& mi = s.modinfos[i];
535 [ # # ]: 0 : size_t loc = mi.find('=');
536 [ # # ]: 0 : string tag = mi.substr (0, loc);
537 [ # # ]: 0 : string value = mi.substr (loc+1);
538 [ # # ][ # # ]: 0 : osrc << "MODULE_INFO(" << tag << "," << lex_cast_qstring(value) << ");" << endl;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
539 [ # # ][ # # ]: 0 : }
540 : :
541 [ # # ]: 0 : osrc.close();
542 : :
543 : : // make the module
544 [ # # ]: 0 : vector<string> make_cmd = make_make_cmd(s, dir);
545 [ # # ]: 0 : int rc = run_make_cmd(s, make_cmd);
546 [ # # ][ # # ]: 0 : if (!rc && !copy_file(dir + "/Module.symvers",
[ # # ]
547 [ # # ][ # # ]: 0 : s.tmpdir + "/Module.symvers"))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
548 : 0 : rc = -1;
549 : :
550 [ # # ]: 0 : if (s.verbose > 1)
551 [ # # ][ # # ]: 0 : clog << _("uprobes rebuild exit code: ") << rc << endl;
[ # # ]
552 [ # # ]: 0 : if (rc)
553 [ # # ]: 0 : s.set_try_server ();
554 : : else
555 [ # # ][ # # ]: 0 : s.uprobes_path = dir + "/uprobes.ko";
[ # # ]
556 [ # # ][ # # ]: 0 : return rc;
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
557 : : }
558 : :
559 : : static bool
560 : 0 : get_cached_uprobes(systemtap_session& s)
561 : : {
562 [ # # ][ # # ]: 0 : s.uprobes_hash = s.use_cache ? find_uprobes_hash(s) : "";
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
563 [ # # ]: 0 : if (!s.uprobes_hash.empty())
564 : : {
565 : : // NB: We always put uprobes.ko in its own directory, especially so
566 : : // stap-serverd can more easily locate it.
567 [ # # ]: 0 : string dir(s.tmpdir + "/uprobes");
568 [ # # ][ # # ]: 0 : if (create_dir(dir.c_str()) != 0)
[ # # ]
569 : 0 : return false;
570 : :
571 [ # # ]: 0 : string cacheko = s.uprobes_hash + ".ko";
572 [ # # ]: 0 : string tmpko = dir + "/uprobes.ko";
573 : :
574 : : // The symvers file still needs to go in the script module's directory.
575 [ # # ]: 0 : string cachesyms = s.uprobes_hash + ".symvers";
576 [ # # ]: 0 : string tmpsyms = s.tmpdir + "/Module.symvers";
577 : :
578 [ # # ][ # # ]: 0 : if (get_file_size(cacheko) > 0 && copy_file(cacheko, tmpko) &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
579 [ # # ][ # # ]: 0 : get_file_size(cachesyms) > 0 && copy_file(cachesyms, tmpsyms))
580 : : {
581 [ # # ]: 0 : s.uprobes_path = tmpko;
582 : 0 : return true;
583 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
584 : : }
585 : 0 : return false;
586 : : }
587 : :
588 : : static void
589 : 0 : set_cached_uprobes(systemtap_session& s)
590 : : {
591 [ # # ][ # # ]: 0 : if (s.use_cache && !s.uprobes_hash.empty())
[ # # ]
592 : : {
593 [ # # ]: 0 : string cacheko = s.uprobes_hash + ".ko";
594 [ # # ]: 0 : string tmpko = s.tmpdir + "/uprobes/uprobes.ko";
595 [ # # ]: 0 : copy_file(tmpko, cacheko);
596 : :
597 [ # # ]: 0 : string cachesyms = s.uprobes_hash + ".symvers";
598 [ # # ]: 0 : string tmpsyms = s.tmpdir + "/uprobes/Module.symvers";
599 [ # # ][ # # ]: 0 : copy_file(tmpsyms, cachesyms);
[ # # ][ # # ]
[ # # ]
600 : : }
601 : 0 : }
602 : :
603 : : int
604 : 624 : uprobes_pass (systemtap_session& s)
605 : : {
606 [ + + ][ - + ]: 624 : if (!s.need_uprobes || kernel_built_uprobes(s))
[ + + ]
607 : 614 : return 0;
608 : :
609 [ + - ][ + - ]: 10 : if (s.kernel_config["CONFIG_UTRACE"] != string("y"))
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
610 : : {
611 : 10 : clog << _("user-space process-tracking facilities not available [man error::process-tracking]") << endl;
612 : 10 : s.set_try_server ();
613 : 10 : return 1;
614 : : }
615 : :
616 : : /*
617 : : * We need to use the version of uprobes that comes with SystemTap. Try to
618 : : * get it from the cache first. If not found, build it and try to save it to
619 : : * the cache for future reuse.
620 : : */
621 : 0 : int rc = 0;
622 [ # # ]: 0 : if (!get_cached_uprobes(s))
623 : : {
624 : 0 : rc = make_uprobes(s);
625 [ # # ]: 0 : if (!rc)
626 : 0 : set_cached_uprobes(s);
627 : : }
628 [ # # ]: 0 : if (rc)
629 : 0 : s.set_try_server ();
630 : 624 : return rc;
631 : : }
632 : :
633 : : static
634 : : vector<string>
635 : 0 : make_dyninst_run_command (systemtap_session& s, const string& remotedir,
636 : : const string& version)
637 : : {
638 : 0 : vector<string> cmd;
639 [ # # ][ # # ]: 0 : cmd.push_back(getenv("SYSTEMTAP_STAPDYN") ?: BINDIR "/stapdyn");
[ # # ][ # # ]
640 : :
641 : : // use slightly less verbosity
642 [ # # ]: 0 : for (unsigned i=1; i<s.verbose; i++)
643 [ # # ][ # # ]: 0 : cmd.push_back("-v");
[ # # ]
644 [ # # ]: 0 : if (s.suppress_warnings)
645 [ # # ][ # # ]: 0 : cmd.push_back("-w");
[ # # ]
646 : :
647 [ # # ][ # # ]: 0 : if (!s.cmd.empty())
648 : : {
649 [ # # ][ # # ]: 0 : cmd.push_back("-c");
[ # # ]
650 [ # # ]: 0 : cmd.push_back(s.cmd);
651 : : }
652 : :
653 [ # # ]: 0 : if (s.target_pid)
654 : : {
655 [ # # ][ # # ]: 0 : cmd.push_back("-x");
[ # # ]
656 [ # # ][ # # ]: 0 : cmd.push_back(lex_cast(s.target_pid));
[ # # ]
657 : : }
658 : :
659 [ # # ]: 0 : cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir)
660 [ # # ][ # # ]: 0 : + "/" + s.module_filename());
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
661 : :
662 : 0 : return cmd;
663 : : }
664 : :
665 : : vector<string>
666 : 476 : make_run_command (systemtap_session& s, const string& remotedir,
667 : : const string& version)
668 : : {
669 [ - + ]: 476 : if (s.runtime_usermode_p())
670 [ # # ]: 0 : return make_dyninst_run_command(s, remotedir, version);
671 : :
672 : : // for now, just spawn staprun
673 [ + - ]: 476 : vector<string> staprun_cmd;
674 [ - + ][ + - ]: 476 : staprun_cmd.push_back(getenv("SYSTEMTAP_STAPRUN") ?: BINDIR "/staprun");
[ + - ][ + - ]
675 : :
676 : : // use slightly less verbosity
677 [ + + ]: 490 : for (unsigned i=1; i<s.verbose; i++)
678 [ + - ][ + - ]: 14 : staprun_cmd.push_back("-v");
[ + - ]
679 [ + + ]: 476 : if (s.suppress_warnings)
680 [ + - ][ + - ]: 24 : staprun_cmd.push_back("-w");
[ + - ]
681 : :
682 [ + - ][ + + ]: 476 : if (!s.output_file.empty())
683 : : {
684 [ + - ][ + - ]: 17 : staprun_cmd.push_back("-o");
[ + - ]
685 [ + - ]: 17 : staprun_cmd.push_back(s.output_file);
686 : : }
687 : :
688 [ + - ][ + + ]: 476 : if (!s.cmd.empty())
689 : : {
690 [ + - ][ + - ]: 172 : staprun_cmd.push_back("-c");
[ + - ]
691 [ + - ]: 172 : staprun_cmd.push_back(s.cmd);
692 : : }
693 : :
694 [ + + ]: 476 : if (s.target_pid)
695 : : {
696 [ + - ][ + - ]: 2 : staprun_cmd.push_back("-t");
[ + - ]
697 [ + - ][ + - ]: 2 : staprun_cmd.push_back(lex_cast(s.target_pid));
[ + - ]
698 : : }
699 : :
700 [ - + ]: 476 : if (s.buffer_size)
701 : : {
702 [ # # ][ # # ]: 0 : staprun_cmd.push_back("-b");
[ # # ]
703 [ # # ][ # # ]: 0 : staprun_cmd.push_back(lex_cast(s.buffer_size));
[ # # ]
704 : : }
705 : :
706 [ - + ][ # # ]: 476 : if (s.need_uprobes && !kernel_built_uprobes(s))
[ # # ][ - + ]
707 : : {
708 [ # # ]: 0 : string opt_u = "-u";
709 [ # # ]: 0 : if (!s.uprobes_path.empty() &&
[ # # # # ]
[ # # ]
710 [ # # ]: 0 : strverscmp("1.4", version.c_str()) <= 0)
711 : : {
712 [ # # ][ # # ]: 0 : if (remotedir.empty())
713 [ # # ]: 0 : opt_u.append(s.uprobes_path);
714 : : else
715 [ # # ][ # # ]: 0 : opt_u.append(remotedir + "/" + basename(s.uprobes_path.c_str()));
[ # # ][ # # ]
[ # # ][ # # ]
716 : : }
717 [ # # ][ # # ]: 0 : staprun_cmd.push_back(opt_u);
718 : : }
719 : :
720 [ + + ]: 476 : if (s.load_only)
721 [ + - ][ - + ]: 5 : staprun_cmd.push_back(s.output_file.empty() ? "-L" : "-D");
[ + - ][ + - ]
[ + - ]
722 : :
723 [ + + ][ + - ]: 476 : if(!s.modname_given && (strverscmp("1.6", version.c_str()) <= 0))
[ + - ][ + + ]
724 [ + - ][ + - ]: 466 : staprun_cmd.push_back("-R");
[ + - ]
725 : :
726 [ + - ][ + + ]: 476 : if (!s.size_option.empty())
727 : : {
728 [ + - ][ + - ]: 4 : staprun_cmd.push_back("-S");
[ + - ]
729 [ + - ]: 4 : staprun_cmd.push_back(s.size_option);
730 : : }
731 : :
732 [ + - ]: 476 : staprun_cmd.push_back((remotedir.empty() ? s.tmpdir : remotedir)
733 [ + + ][ + - ]: 476 : + "/" + s.module_filename());
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
734 : :
735 : : // add module arguments
736 : : staprun_cmd.insert(staprun_cmd.end(),
737 [ + - ][ + - ]: 476 : s.globalopts.begin(), s.globalopts.end());
[ + - ][ + - ]
738 : :
739 [ + - ][ + - ]: 476 : return staprun_cmd;
740 : : }
741 : :
742 : :
743 : : // Build tiny kernel modules to query tracepoints.
744 : : // Given a (header-file -> test-contents) map, compile them ASAP, and return
745 : : // a (header-file -> obj-filename) map.
746 : :
747 : : map<string,string>
748 : 1 : make_tracequeries(systemtap_session& s, const map<string,string>& contents)
749 : : {
750 : : static unsigned tick = 0;
751 [ + - ][ + - ]: 1 : string basename("tracequery_kmod_" + lex_cast(++tick));
[ + - ]
752 [ + - ]: 1 : map<string,string> objs;
753 : :
754 : : // create a subdirectory for the module
755 [ + - ][ + - ]: 1 : string dir(s.tmpdir + "/" + basename);
[ + - ]
756 [ + - ][ + - ]: 1 : if (create_dir(dir.c_str()) != 0)
[ - + ]
757 : : {
758 [ # # ][ # # ]: 0 : s.print_warning("failed to create directory for querying tracepoints.");
[ # # ]
759 [ # # ]: 0 : s.set_try_server ();
760 : : return objs;
761 : : }
762 : :
763 : : // create a simple Makefile
764 [ + - ]: 1 : string makefile(dir + "/Makefile");
765 [ + - ][ + - ]: 1 : ofstream omf(makefile.c_str());
766 : : // force debuginfo generation, and relax implicit functions
767 [ + - ][ - + ]: 1 : omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration" << (s.omit_werror ? "" : " -Werror") << endl;
[ + - ][ + - ]
768 : : // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules
769 [ + - ][ + - ]: 1 : omf << "CONFIG_MODULE_SIG := n" << endl;
770 : :
771 [ + - ][ + - ]: 1 : if (s.kernel_source_tree != "")
772 [ + - ][ + - ]: 1 : omf << "EXTRA_CFLAGS += -I" + s.kernel_source_tree << endl;
[ + - ][ + - ]
773 : :
774 [ + - ][ + - ]: 1 : omf << "obj-m := " << endl;
775 : : // write out each header-specific source file into a separate file
776 [ + - ][ + - ]: 51 : for (map<string,string>::const_iterator it = contents.begin(); it != contents.end(); it++)
[ + + ]
777 : : {
778 [ + - ][ + - ]: 50 : string sbasename = basename + "_" + lex_cast(++tick); // suffixed
[ + - ][ + - ]
[ + - ]
779 : :
780 : : // write out source code
781 [ + - ][ + - ]: 50 : string srcname = dir + "/" + sbasename + ".c";
[ + - ][ + - ]
[ + - ]
782 [ + - ][ + - ]: 50 : string src = it->second;
783 [ + - ][ + - ]: 50 : ofstream osrc(srcname.c_str());
784 [ + - ]: 50 : osrc << src;
785 [ + - ]: 50 : osrc.close();
786 : :
787 [ - + ]: 50 : if (s.verbose > 2)
788 [ # # ][ # # ]: 0 : clog << _F("Processing tracepoint header %s with query %s",
[ # # ][ # # ]
[ # # ][ # # ]
789 : : it->first.c_str(), srcname.c_str())
790 [ # # ]: 0 : << endl;
791 : :
792 : : // arrange to build it
793 [ + - ][ + - ]: 50 : omf << "obj-m += " + sbasename + ".o" << endl; // NB: without <dir> prefix
[ + - ][ + - ]
[ + - ][ + - ]
794 [ + - ][ + - ]: 50 : objs[it->first] = dir + "/" + sbasename + ".o";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
795 [ + - ][ + - ]: 50 : }
[ + - ][ + - ]
796 [ + - ]: 1 : omf.close();
797 : :
798 : : // make the module
799 [ + - ]: 1 : vector<string> make_cmd = make_make_objs_cmd(s, dir);
800 [ + - ][ + - ]: 1 : make_cmd.push_back ("-i"); // ignore errors, give rc 0 even in case of tracepoint header nits
[ + - ]
801 : 1 : bool quiet = (s.verbose < 4);
802 [ + - ]: 1 : int rc = run_make_cmd(s, make_cmd, quiet, quiet);
803 [ - + ]: 1 : if (rc)
804 [ # # ]: 0 : s.set_try_server ();
805 : :
806 : : // Sometimes we fail a tracequery due to PR9993 / PR11649 type
807 : : // kernel trace header problems. In this case, due to PR12729, we
808 : : // used to get a lovely "Warning: make exited with status: 2" but no
809 : : // other useful diagnostic. -vvvv would let a user see what's up,
810 : : // but the user can't fix the problem even with that.
811 : :
812 [ + - ][ + - ]: 1 : return objs;
[ + - ][ + - ]
[ + - ]
813 : : }
814 : :
815 : :
816 : : // Build a tiny kernel module to query type information
817 : : static int
818 : 7 : make_typequery_kmod(systemtap_session& s, const vector<string>& headers, string& name)
819 : : {
820 : : static unsigned tick = 0;
821 [ + - ][ + - ]: 7 : string basename("typequery_kmod_" + lex_cast(++tick));
[ + - ]
822 : :
823 : : // create a subdirectory for the module
824 [ + - ][ + - ]: 7 : string dir(s.tmpdir + "/" + basename);
[ + - ]
825 [ + - ][ + - ]: 7 : if (create_dir(dir.c_str()) != 0)
[ - + ]
826 : : {
827 [ # # ][ # # ]: 0 : s.print_warning("failed to create directory for querying types.");
[ # # ]
828 [ # # ]: 0 : s.set_try_server ();
829 : 0 : return 1;
830 : : }
831 : :
832 [ + - ][ + - ]: 7 : name = dir + "/" + basename + ".ko";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
833 : :
834 : : // create a simple Makefile
835 [ + - ]: 7 : string makefile(dir + "/Makefile");
836 [ + - ][ + - ]: 7 : ofstream omf(makefile.c_str());
837 [ + - ][ + - ]: 7 : omf << "EXTRA_CFLAGS := -g -fno-eliminate-unused-debug-types" << endl;
838 : :
839 : : // RHBZ 655231: later rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules
840 [ + - ][ + - ]: 7 : omf << "CONFIG_MODULE_SIG := n" << endl;
841 : :
842 : : // NB: We use -include instead of #include because that gives us more power.
843 : : // Using #include searches relative to the source's path, which in this case
844 : : // is /tmp/..., so that's not helpful. Using -include will search relative
845 : : // to the cwd, which will be the kernel build root. This means if you have a
846 : : // full kernel build tree, it's possible to get at types that aren't in the
847 : : // normal include path, e.g.:
848 : : // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->...
849 [ + - ][ + - ]: 7 : omf << "CFLAGS_" << basename << ".o :=";
[ + - ]
850 [ + + ]: 15 : for (size_t i = 0; i < headers.size(); ++i)
851 [ + - ][ + - ]: 8 : omf << " -include " << lex_cast_qstring(headers[i]); // XXX right quoting?
[ + - ][ + - ]
852 [ + - ]: 7 : omf << endl;
853 : :
854 [ + - ][ + - ]: 7 : omf << "obj-m := " + basename + ".o" << endl;
[ + - ][ + - ]
[ + - ][ + - ]
855 [ + - ]: 7 : omf.close();
856 : :
857 : : // create our empty source file
858 [ + - ][ + - ]: 7 : string source(dir + "/" + basename + ".c");
[ + - ][ + - ]
[ + - ]
859 [ + - ][ + - ]: 7 : ofstream osrc(source.c_str());
860 [ + - ]: 7 : osrc.close();
861 : :
862 : : // make the module
863 [ + - ]: 7 : vector<string> make_cmd = make_make_cmd(s, dir);
864 : 7 : bool quiet = (s.verbose < 4);
865 [ + - ]: 7 : int rc = run_make_cmd(s, make_cmd, quiet, quiet);
866 [ - + ]: 7 : if (rc)
867 [ # # ]: 0 : s.set_try_server ();
868 [ + - ][ + - ]: 7 : return rc;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
869 : : }
870 : :
871 : :
872 : : // Build a tiny user module to query type information
873 : : static int
874 : 3 : make_typequery_umod(systemtap_session& s, const vector<string>& headers, string& name)
875 : : {
876 : : static unsigned tick = 0;
877 : :
878 [ + - ][ + - ]: 3 : name = s.tmpdir + "/typequery_umod_" + lex_cast(++tick) + ".so";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
879 : :
880 : : // make the module
881 : : //
882 : : // NB: As with kmod, using -include makes relative paths more useful. The
883 : : // cwd in this case will be the cwd of stap itself though, which may be
884 : : // trickier to deal with. It might be better to "cd `dirname $script`"
885 : : // first...
886 [ + - ]: 3 : vector<string> cmd;
887 [ + - ][ + - ]: 3 : cmd.push_back("gcc");
[ + - ]
888 [ + - ][ + - ]: 3 : cmd.push_back("-shared");
[ + - ]
889 [ + - ][ + - ]: 3 : cmd.push_back("-g");
[ + - ]
890 [ + - ][ + - ]: 3 : cmd.push_back("-fno-eliminate-unused-debug-types");
[ + - ]
891 [ + - ][ + - ]: 3 : cmd.push_back("-xc");
[ + - ]
892 [ + - ][ + - ]: 3 : cmd.push_back("/dev/null");
[ + - ]
893 [ + - ][ + - ]: 3 : cmd.push_back("-o");
[ + - ]
894 [ + - ]: 3 : cmd.push_back(name);
895 [ + + ]: 6 : for (size_t i = 0; i < headers.size(); ++i)
896 : : {
897 [ + - ][ + - ]: 3 : cmd.push_back("-include");
[ + - ]
898 [ + - ]: 3 : cmd.push_back(headers[i]);
899 : : }
900 : 3 : bool quiet = (s.verbose < 4);
901 [ + - ]: 3 : int rc = stap_system (s.verbose, cmd, quiet, quiet);
902 [ - + ]: 3 : if (rc)
903 [ # # ]: 0 : s.set_try_server ();
904 [ + - ]: 3 : return rc;
905 : : }
906 : :
907 : :
908 : : int
909 : 10 : make_typequery(systemtap_session& s, string& module)
910 : : {
911 : : int rc;
912 [ + - ]: 10 : string new_module;
913 [ + - ]: 10 : vector<string> headers;
914 [ + - ]: 10 : bool kernel = startswith(module, "kernel");
915 : :
916 [ + + ][ + - ]: 21 : for (size_t end, i = kernel ? 6 : 0; i < module.size(); i = end + 1)
[ + + ]
917 : : {
918 [ + - ][ - + ]: 11 : if (module[i] != '<')
919 : 0 : return -1;
920 [ + - ]: 11 : end = module.find('>', ++i);
921 [ - + ]: 11 : if (end == string::npos)
922 : 0 : return -1;
923 [ + - ]: 11 : string header = module.substr(i, end - i);
924 [ + - ]: 11 : vector<string> matches;
925 [ + - ][ + - ]: 11 : if (regexp_match(header, "^[a-zA-Z0-9/_.+-]+$", matches))
[ + - ][ - + ]
926 [ # # ][ # # ]: 0 : s.print_warning("skipping malformed @cast header \""+ header + "\"");
[ # # ][ # # ]
[ # # ]
927 : : else
928 [ + - ]: 11 : headers.push_back(header);
929 [ + - ][ + - ]: 11 : }
930 [ + - ][ - + ]: 10 : if (headers.empty())
931 : 0 : return -1;
932 : :
933 [ + + ]: 10 : if (kernel)
934 [ + - ]: 7 : rc = make_typequery_kmod(s, headers, new_module);
935 : : else
936 [ + - ]: 3 : rc = make_typequery_umod(s, headers, new_module);
937 : :
938 [ + - ]: 10 : if (!rc)
939 [ + - ]: 10 : module = new_module;
940 : :
941 [ + - ][ + - ]: 10 : return rc;
942 [ + - ][ + - ]: 7242 : }
943 : :
944 : : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|