]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // build/run probes |
255e4c68 | 2 | // Copyright (C) 2005-2007 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" |
f4b28491 | 13 | |
3b579393 | 14 | #include <cstdlib> |
f4b28491 | 15 | #include <fstream> |
d04cf5ff FCE |
16 | #include <sstream> |
17 | ||
18 | extern "C" { | |
49abf162 | 19 | #include <signal.h> |
0c6296b2 | 20 | #include <sys/wait.h> |
70404fc5 | 21 | #include <pwd.h> |
b40af7ee DS |
22 | #include <sys/types.h> |
23 | #include <sys/stat.h> | |
24 | #include <unistd.h> | |
25 | #include <string.h> | |
26 | #include <errno.h> | |
d04cf5ff FCE |
27 | } |
28 | ||
f4b28491 FCE |
29 | |
30 | using namespace std; | |
31 | ||
db3a383b JK |
32 | static int uprobes_pass (systemtap_session& s); |
33 | ||
6274464e JK |
34 | /* Adjust and run make_cmd to build a kernel module. */ |
35 | static int | |
36 | run_make_cmd(systemtap_session& s, string& make_cmd) | |
37 | { | |
38 | // Before running make, fix up the environment a bit. PATH should | |
39 | // already be overridden. Clean out a few variables that | |
40 | // /lib/modules/${KVER}/build/Makefile uses. | |
41 | int rc = unsetenv("ARCH") || unsetenv("KBUILD_EXTMOD") | |
42 | || unsetenv("CROSS_COMPILE") || unsetenv("KBUILD_IMAGE") | |
43 | || unsetenv("KCONFIG_CONFIG") || unsetenv("INSTALL_PATH"); | |
44 | if (rc) | |
45 | { | |
46 | const char* e = strerror (errno); | |
47 | cerr << "unsetenv failed: " << e << endl; | |
48 | } | |
49 | ||
b54581ce | 50 | if (s.verbose > 2) |
6274464e | 51 | make_cmd += " V=1"; |
b54581ce FCE |
52 | else if (s.verbose > 1) |
53 | make_cmd += " >/dev/null"; | |
6274464e JK |
54 | else |
55 | make_cmd += " -s >/dev/null 2>&1"; | |
56 | ||
57 | if (s.verbose > 1) clog << "Running " << make_cmd << endl; | |
58 | rc = system (make_cmd.c_str()); | |
59 | ||
60 | return rc; | |
61 | } | |
f4b28491 FCE |
62 | |
63 | int | |
64 | compile_pass (systemtap_session& s) | |
65 | { | |
db3a383b JK |
66 | int rc = uprobes_pass (s); |
67 | if (rc) | |
68 | return rc; | |
69 | ||
f4b28491 | 70 | // fill in a quick Makefile |
92ade41d FCE |
71 | string makefile_nm = s.tmpdir + "/Makefile"; |
72 | ofstream o (makefile_nm.c_str()); | |
92ade41d FCE |
73 | |
74 | // Create makefile | |
ed10c639 | 75 | |
255e4c68 | 76 | // Clever hacks copied from vmware modules |
ecf19454 FCE |
77 | string superverbose; |
78 | if (s.verbose > 3) | |
79 | superverbose = "set -x;"; | |
522518f1 | 80 | |
ecf19454 FCE |
81 | 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; |
82 | o << "stap_check_build = $(shell " << superverbose << " if $(CC) $(KBUILD_CPPFLAGS) $(CPPFLAGS) $(KBUILD_CFLAGS) $(CFLAGS_KERNEL) $(EXTRA_CFLAGS) $(CFLAGS) -DKBUILD_BASENAME=\\\"" << s.module_name << "\\\" -Werror -S -o /dev/null -xc $(1) > /dev/null 2>&1 ; then echo \"$(2)\"; else echo \"$(3)\"; fi)" << endl; | |
255e4c68 FCE |
83 | |
84 | o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl; | |
85 | ||
86 | // "autoconf" options go here | |
87 | ||
ecf19454 | 88 | string module_cflags = "EXTRA_CFLAGS"; |
522518f1 | 89 | o << module_cflags << " :=" << endl; |
84c4da88 FCE |
90 | |
91 | // XXX: This gruesome hack is needed on some kernels built with separate O=directory, | |
92 | // where files like 2.6.27 x86's asm/mach-*/mach_mpspec.h are not found on the cpp path. | |
93 | // This could be a bug in arch/x86/Makefile that names | |
94 | // mflags-y += -Iinclude/asm-x86/mach-default | |
95 | // but that path does not exist in an O= build tree. | |
96 | o << module_cflags << " += -Iinclude2/asm/mach-default" << endl; | |
97 | ||
522518f1 FCE |
98 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-hrtimer-rel.c, -DSTAPCONF_HRTIMER_REL,)" << endl; |
99 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-inode-private.c, -DSTAPCONF_INODE_PRIVATE,)" << endl; | |
ca99ed19 MH |
100 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-constant-tsc.c, -DSTAPCONF_CONSTANT_TSC,)" << endl; |
101 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-tsc-khz.c, -DSTAPCONF_TSC_KHZ,)" << endl; | |
102 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-ktime-get-real.c, -DSTAPCONF_KTIME_GET_REAL,)" << endl; | |
c7bcf451 | 103 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-x86-uniregs.c, -DSTAPCONF_X86_UNIREGS,)" << endl; |
c7bcf451 | 104 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-nameidata.c, -DSTAPCONF_NAMEIDATA_CLEANUP,)" << endl; |
42cb22bd | 105 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-unregister-kprobes.c, -DSTAPCONF_UNREGISTER_KPROBES,)" << endl; |
25814e6c | 106 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-real-parent.c, -DSTAPCONF_REAL_PARENT,)" << endl; |
f1743f00 | 107 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-uaccess.c, -DSTAPCONF_LINUX_UACCESS_H,)" << endl; |
c2ffad10 | 108 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-oneachcpu-retry.c, -DSTAPCONF_ONEACHCPU_RETRY,)" << endl; |
2cda5f46 JS |
109 | #if 0 |
110 | /* NB: For now, the performance hit of probe_kernel_read/write (vs. our | |
111 | * homegrown safe-access functions) is deemed undesireable, so we'll skip | |
112 | * this autoconf. */ | |
113 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-probe-kernel.c, -DSTAPCONF_PROBE_KERNEL,)" << endl; | |
114 | #endif | |
255e4c68 | 115 | |
ed10c639 | 116 | for (unsigned i=0; i<s.macros.size(); i++) |
0986ac38 | 117 | o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl; |
ed10c639 | 118 | |
e4c58386 | 119 | if (s.verbose > 3) |
0986ac38 | 120 | o << "EXTRA_CFLAGS += -ftime-report -Q" << endl; |
db22e55f | 121 | |
ee6dda6f FCE |
122 | // XXX: unfortunately, -save-temps can't work since linux kbuild cwd |
123 | // is not writeable. | |
124 | // | |
125 | // if (s.keep_tmpdir) | |
126 | // o << "CFLAGS += -fverbose-asm -save-temps" << endl; | |
127 | ||
0986ac38 | 128 | o << "EXTRA_CFLAGS += -freorder-blocks" << endl; // improve on -Os |
35d4ab18 FCE |
129 | |
130 | // o << "CFLAGS += -fno-unit-at-a-time" << endl; | |
131 | ||
cbfbbf69 | 132 | // Assumes linux 2.6 kbuild |
0986ac38 DS |
133 | o << "EXTRA_CFLAGS += -Wno-unused -Werror" << endl; |
134 | o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl; | |
4b2c4ab5 FCE |
135 | // XXX: this may help ppc toc overflow |
136 | // o << "CFLAGS := $(subst -Os,-O2,$(CFLAGS)) -fminimal-toc" << endl; | |
cbfbbf69 | 137 | o << "obj-m := " << s.module_name << ".o" << endl; |
f4b28491 | 138 | |
ed10c639 FCE |
139 | o.close (); |
140 | ||
b40af7ee | 141 | // Generate module directory pathname and make sure it exists. |
cbfbbf69 FCE |
142 | string module_dir = string("/lib/modules/") |
143 | + s.kernel_release + "/build"; | |
b40af7ee DS |
144 | struct stat st; |
145 | rc = stat(module_dir.c_str(), &st); | |
146 | if (rc != 0) | |
147 | { | |
148 | clog << "Module directory " << module_dir << " check failed: " | |
149 | << strerror(errno) << endl | |
150 | << "Make sure kernel devel is installed." << endl; | |
151 | return rc; | |
152 | } | |
153 | ||
154 | // Run make | |
cbfbbf69 FCE |
155 | string make_cmd = string("make") |
156 | + string (" -C \"") + module_dir + string("\""); | |
157 | make_cmd += string(" M=\"") + s.tmpdir + string("\" modules"); | |
522518f1 | 158 | |
6274464e | 159 | rc = run_make_cmd(s, make_cmd); |
cbfbbf69 | 160 | |
f4b28491 FCE |
161 | return rc; |
162 | } | |
163 | ||
db3a383b | 164 | static const string uprobes_home = string(PKGDATADIR "/runtime/uprobes"); |
f4b28491 | 165 | |
db3a383b JK |
166 | /* |
167 | * If uprobes was built as part of the kernel build (either built-in | |
168 | * or as a module), the uprobes exports should show up in | |
169 | * /lib/modules/`uname -r`/build/Module.symvers. Return true if so. | |
170 | */ | |
171 | static bool | |
172 | kernel_built_uprobes (systemtap_session& s) | |
6274464e | 173 | { |
db3a383b JK |
174 | string grep_cmd = string ("/bin/grep -q unregister_uprobe /lib/modules/") |
175 | + s.kernel_release + string ("/build/Module.symvers"); | |
176 | int rc = system (grep_cmd.c_str()); | |
6274464e JK |
177 | return (rc == 0); |
178 | } | |
179 | ||
db3a383b JK |
180 | static bool |
181 | verify_uprobes_uptodate (systemtap_session& s) | |
6274464e | 182 | { |
db3a383b JK |
183 | if (s.verbose) |
184 | clog << "Pass 4, preamble: " | |
185 | << "verifying that SystemTap's version of uprobes is up to date." | |
186 | << endl; | |
187 | ||
188 | string make_cmd = string("make -q -C ") + uprobes_home | |
189 | + string(" uprobes.ko"); | |
190 | int rc = run_make_cmd(s, make_cmd); | |
191 | if (rc) { | |
192 | clog << "SystemTap's version of uprobes is out of date." << endl; | |
193 | clog << "As root, run \"make\" in " << uprobes_home << "." << endl; | |
194 | } | |
6274464e | 195 | |
db3a383b JK |
196 | return rc; |
197 | } | |
6274464e | 198 | |
db3a383b JK |
199 | static int |
200 | make_uprobes (systemtap_session& s) | |
201 | { | |
6274464e | 202 | if (s.verbose) |
db3a383b | 203 | clog << "Pass 4, preamble: " |
6274464e JK |
204 | << "(re)building SystemTap's version of uprobes." |
205 | << endl; | |
206 | ||
207 | string make_cmd = string("make -C ") + uprobes_home; | |
208 | int rc = run_make_cmd(s, make_cmd); | |
db3a383b JK |
209 | if (s.verbose) { |
210 | if (rc) | |
211 | clog << "Uprobes (re)build failed." << endl; | |
212 | else | |
213 | clog << "Uprobes (re)build complete." << endl; | |
214 | } | |
6274464e JK |
215 | |
216 | return rc; | |
217 | } | |
218 | ||
db3a383b JK |
219 | /* |
220 | * Copy uprobes' exports (in Module.symvers) into the temporary directory | |
221 | * so the script-module build can find them. | |
222 | */ | |
223 | static int | |
224 | copy_uprobes_symbols (systemtap_session& s) | |
225 | { | |
226 | string cp_cmd = string("/bin/cp ") + uprobes_home + | |
227 | string("/Module.symvers ") + s.tmpdir; | |
228 | int rc = system (cp_cmd.c_str()); | |
229 | return rc; | |
230 | } | |
231 | ||
232 | static int | |
233 | uprobes_pass (systemtap_session& s) | |
234 | { | |
235 | if (!s.need_uprobes || kernel_built_uprobes(s)) | |
236 | return 0; | |
237 | /* | |
238 | * We need to use the version of uprobes that comes with SystemTap, so | |
239 | * we may need to rebuild uprobes.ko there. Unfortunately, this is | |
240 | * never a no-op; e.g., the modpost step gets run every time. We don't | |
241 | * want non-root users modifying uprobes, so we keep the uprobes | |
242 | * directory writable only by root. But that means a non-root member | |
243 | * of group stapdev can't run the make even if everything's up to date. | |
244 | * | |
245 | * So for non-root users, we just use "make -q" with a fake target to | |
246 | * verify that uprobes doesn't need to be rebuilt. If that's not so, | |
247 | * stap must fail. | |
248 | */ | |
249 | int rc; | |
250 | if (geteuid() == 0) { | |
251 | rc = make_uprobes(s); | |
252 | if (rc == 0) | |
253 | rc = copy_uprobes_symbols(s); | |
254 | } else | |
255 | rc = verify_uprobes_uptodate(s); | |
256 | return rc; | |
257 | } | |
258 | ||
f4b28491 FCE |
259 | int |
260 | run_pass (systemtap_session& s) | |
261 | { | |
92ade41d FCE |
262 | int rc = 0; |
263 | ||
70404fc5 MH |
264 | struct passwd *pw = getpwuid(getuid()); |
265 | string username = string(pw->pw_name); | |
266 | ||
a63a95dc | 267 | // for now, just spawn staprun |
98aab489 | 268 | string staprun_cmd = string(BINDIR) + "/staprun " |
e65b03c1 | 269 | + (s.verbose>1 ? "-v " : "") |
639948b1 | 270 | + (s.verbose>2 ? "-v " : "") |
cbfbbf69 FCE |
271 | + (s.output_file.empty() ? "" : "-o " + s.output_file + " "); |
272 | ||
cbfbbf69 | 273 | if (s.cmd != "") |
8c711d30 | 274 | staprun_cmd += "-c " + cmdstr_quoted(s.cmd) + " "; |
cbfbbf69 FCE |
275 | |
276 | if (s.target_pid) | |
a63a95dc | 277 | staprun_cmd += "-t " + stringify(s.target_pid) + " "; |
cbfbbf69 FCE |
278 | |
279 | if (s.buffer_size) | |
a63a95dc | 280 | staprun_cmd += "-b " + stringify(s.buffer_size) + " "; |
cbfbbf69 | 281 | |
6274464e JK |
282 | if (s.need_uprobes) |
283 | staprun_cmd += "-u "; | |
284 | ||
a63a95dc | 285 | staprun_cmd += s.tmpdir + "/" + s.module_name + ".ko"; |
cbfbbf69 | 286 | |
a63a95dc | 287 | if (s.verbose>1) clog << "Running " << staprun_cmd << endl; |
cbfbbf69 | 288 | |
a63a95dc | 289 | rc = system (staprun_cmd.c_str ()); |
92ade41d | 290 | return rc; |
f4b28491 | 291 | } |