]>
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 FCE |
76 | // Clever hacks copied from vmware modules |
77 | o << "stap_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo \"$(1)\"; else echo \"$(2)\"; fi)" << endl; | |
b54581ce | 78 | o << "stap_check_build = $(shell 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; |
522518f1 | 79 | |
255e4c68 FCE |
80 | |
81 | o << "SYSTEMTAP_RUNTIME = \"" << s.runtime_path << "\"" << endl; | |
82 | ||
83 | // "autoconf" options go here | |
84 | ||
85 | // enum hrtimer_mode renaming near 2.6.21; see tapsets.cxx hrtimer_derived_probe_group::emit_module_decls | |
522518f1 FCE |
86 | string module_cflags = "CFLAGS_" + s.module_name + ".o"; |
87 | o << module_cflags << " :=" << endl; | |
88 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-hrtimer-rel.c, -DSTAPCONF_HRTIMER_REL,)" << endl; | |
89 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-inode-private.c, -DSTAPCONF_INODE_PRIVATE,)" << endl; | |
ca99ed19 MH |
90 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-constant-tsc.c, -DSTAPCONF_CONSTANT_TSC,)" << endl; |
91 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-tsc-khz.c, -DSTAPCONF_TSC_KHZ,)" << endl; | |
92 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-ktime-get-real.c, -DSTAPCONF_KTIME_GET_REAL,)" << endl; | |
c7bcf451 SD |
93 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-x86-uniregs.c, -DSTAPCONF_X86_UNIREGS,)" << endl; |
94 | ||
95 | o << module_cflags << " += $(call stap_check_build, $(SYSTEMTAP_RUNTIME)/autoconf-nameidata.c, -DSTAPCONF_NAMEIDATA_CLEANUP,)" << endl; | |
255e4c68 | 96 | |
ed10c639 | 97 | for (unsigned i=0; i<s.macros.size(); i++) |
0986ac38 | 98 | o << "EXTRA_CFLAGS += -D " << lex_cast_qstring(s.macros[i]) << endl; |
ed10c639 | 99 | |
e4c58386 | 100 | if (s.verbose > 3) |
0986ac38 | 101 | o << "EXTRA_CFLAGS += -ftime-report -Q" << endl; |
db22e55f | 102 | |
ee6dda6f FCE |
103 | // XXX: unfortunately, -save-temps can't work since linux kbuild cwd |
104 | // is not writeable. | |
105 | // | |
106 | // if (s.keep_tmpdir) | |
107 | // o << "CFLAGS += -fverbose-asm -save-temps" << endl; | |
108 | ||
0986ac38 | 109 | o << "EXTRA_CFLAGS += -freorder-blocks" << endl; // improve on -Os |
35d4ab18 FCE |
110 | |
111 | // o << "CFLAGS += -fno-unit-at-a-time" << endl; | |
112 | ||
cbfbbf69 | 113 | // Assumes linux 2.6 kbuild |
0986ac38 DS |
114 | o << "EXTRA_CFLAGS += -Wno-unused -Werror" << endl; |
115 | o << "EXTRA_CFLAGS += -I\"" << s.runtime_path << "\"" << endl; | |
4b2c4ab5 FCE |
116 | // XXX: this may help ppc toc overflow |
117 | // o << "CFLAGS := $(subst -Os,-O2,$(CFLAGS)) -fminimal-toc" << endl; | |
cbfbbf69 | 118 | o << "obj-m := " << s.module_name << ".o" << endl; |
f4b28491 | 119 | |
ed10c639 FCE |
120 | o.close (); |
121 | ||
b40af7ee | 122 | // Generate module directory pathname and make sure it exists. |
cbfbbf69 FCE |
123 | string module_dir = string("/lib/modules/") |
124 | + s.kernel_release + "/build"; | |
b40af7ee DS |
125 | struct stat st; |
126 | rc = stat(module_dir.c_str(), &st); | |
127 | if (rc != 0) | |
128 | { | |
129 | clog << "Module directory " << module_dir << " check failed: " | |
130 | << strerror(errno) << endl | |
131 | << "Make sure kernel devel is installed." << endl; | |
132 | return rc; | |
133 | } | |
134 | ||
135 | // Run make | |
cbfbbf69 FCE |
136 | string make_cmd = string("make") |
137 | + string (" -C \"") + module_dir + string("\""); | |
138 | make_cmd += string(" M=\"") + s.tmpdir + string("\" modules"); | |
522518f1 | 139 | |
6274464e | 140 | rc = run_make_cmd(s, make_cmd); |
cbfbbf69 | 141 | |
f4b28491 FCE |
142 | return rc; |
143 | } | |
144 | ||
db3a383b | 145 | static const string uprobes_home = string(PKGDATADIR "/runtime/uprobes"); |
f4b28491 | 146 | |
db3a383b JK |
147 | /* |
148 | * If uprobes was built as part of the kernel build (either built-in | |
149 | * or as a module), the uprobes exports should show up in | |
150 | * /lib/modules/`uname -r`/build/Module.symvers. Return true if so. | |
151 | */ | |
152 | static bool | |
153 | kernel_built_uprobes (systemtap_session& s) | |
6274464e | 154 | { |
db3a383b JK |
155 | string grep_cmd = string ("/bin/grep -q unregister_uprobe /lib/modules/") |
156 | + s.kernel_release + string ("/build/Module.symvers"); | |
157 | int rc = system (grep_cmd.c_str()); | |
6274464e JK |
158 | return (rc == 0); |
159 | } | |
160 | ||
db3a383b JK |
161 | static bool |
162 | verify_uprobes_uptodate (systemtap_session& s) | |
6274464e | 163 | { |
db3a383b JK |
164 | if (s.verbose) |
165 | clog << "Pass 4, preamble: " | |
166 | << "verifying that SystemTap's version of uprobes is up to date." | |
167 | << endl; | |
168 | ||
169 | string make_cmd = string("make -q -C ") + uprobes_home | |
170 | + string(" uprobes.ko"); | |
171 | int rc = run_make_cmd(s, make_cmd); | |
172 | if (rc) { | |
173 | clog << "SystemTap's version of uprobes is out of date." << endl; | |
174 | clog << "As root, run \"make\" in " << uprobes_home << "." << endl; | |
175 | } | |
6274464e | 176 | |
db3a383b JK |
177 | return rc; |
178 | } | |
6274464e | 179 | |
db3a383b JK |
180 | static int |
181 | make_uprobes (systemtap_session& s) | |
182 | { | |
6274464e | 183 | if (s.verbose) |
db3a383b | 184 | clog << "Pass 4, preamble: " |
6274464e JK |
185 | << "(re)building SystemTap's version of uprobes." |
186 | << endl; | |
187 | ||
188 | string make_cmd = string("make -C ") + uprobes_home; | |
189 | int rc = run_make_cmd(s, make_cmd); | |
db3a383b JK |
190 | if (s.verbose) { |
191 | if (rc) | |
192 | clog << "Uprobes (re)build failed." << endl; | |
193 | else | |
194 | clog << "Uprobes (re)build complete." << endl; | |
195 | } | |
6274464e JK |
196 | |
197 | return rc; | |
198 | } | |
199 | ||
db3a383b JK |
200 | /* |
201 | * Copy uprobes' exports (in Module.symvers) into the temporary directory | |
202 | * so the script-module build can find them. | |
203 | */ | |
204 | static int | |
205 | copy_uprobes_symbols (systemtap_session& s) | |
206 | { | |
207 | string cp_cmd = string("/bin/cp ") + uprobes_home + | |
208 | string("/Module.symvers ") + s.tmpdir; | |
209 | int rc = system (cp_cmd.c_str()); | |
210 | return rc; | |
211 | } | |
212 | ||
213 | static int | |
214 | uprobes_pass (systemtap_session& s) | |
215 | { | |
216 | if (!s.need_uprobes || kernel_built_uprobes(s)) | |
217 | return 0; | |
218 | /* | |
219 | * We need to use the version of uprobes that comes with SystemTap, so | |
220 | * we may need to rebuild uprobes.ko there. Unfortunately, this is | |
221 | * never a no-op; e.g., the modpost step gets run every time. We don't | |
222 | * want non-root users modifying uprobes, so we keep the uprobes | |
223 | * directory writable only by root. But that means a non-root member | |
224 | * of group stapdev can't run the make even if everything's up to date. | |
225 | * | |
226 | * So for non-root users, we just use "make -q" with a fake target to | |
227 | * verify that uprobes doesn't need to be rebuilt. If that's not so, | |
228 | * stap must fail. | |
229 | */ | |
230 | int rc; | |
231 | if (geteuid() == 0) { | |
232 | rc = make_uprobes(s); | |
233 | if (rc == 0) | |
234 | rc = copy_uprobes_symbols(s); | |
235 | } else | |
236 | rc = verify_uprobes_uptodate(s); | |
237 | return rc; | |
238 | } | |
239 | ||
f4b28491 FCE |
240 | int |
241 | run_pass (systemtap_session& s) | |
242 | { | |
92ade41d FCE |
243 | int rc = 0; |
244 | ||
70404fc5 MH |
245 | struct passwd *pw = getpwuid(getuid()); |
246 | string username = string(pw->pw_name); | |
247 | ||
a63a95dc | 248 | // for now, just spawn staprun |
98aab489 | 249 | string staprun_cmd = string(BINDIR) + "/staprun " |
e65b03c1 | 250 | + (s.verbose>1 ? "-v " : "") |
639948b1 | 251 | + (s.verbose>2 ? "-v " : "") |
cbfbbf69 FCE |
252 | + (s.output_file.empty() ? "" : "-o " + s.output_file + " "); |
253 | ||
a63a95dc | 254 | staprun_cmd += "-d " + stringify(getpid()) + " "; |
cbfbbf69 FCE |
255 | |
256 | if (s.cmd != "") | |
8c711d30 | 257 | staprun_cmd += "-c " + cmdstr_quoted(s.cmd) + " "; |
cbfbbf69 FCE |
258 | |
259 | if (s.target_pid) | |
a63a95dc | 260 | staprun_cmd += "-t " + stringify(s.target_pid) + " "; |
cbfbbf69 FCE |
261 | |
262 | if (s.buffer_size) | |
a63a95dc | 263 | staprun_cmd += "-b " + stringify(s.buffer_size) + " "; |
cbfbbf69 | 264 | |
6274464e JK |
265 | if (s.need_uprobes) |
266 | staprun_cmd += "-u "; | |
267 | ||
a63a95dc | 268 | staprun_cmd += s.tmpdir + "/" + s.module_name + ".ko"; |
cbfbbf69 | 269 | |
a63a95dc | 270 | if (s.verbose>1) clog << "Running " << staprun_cmd << endl; |
cbfbbf69 | 271 | |
a63a95dc | 272 | rc = system (staprun_cmd.c_str ()); |
92ade41d | 273 | return rc; |
f4b28491 | 274 | } |