]> sourceware.org Git - systemtap.git/blame - buildrun.cxx
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
[systemtap.git] / buildrun.cxx
CommitLineData
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
18extern "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
30using namespace std;
31
db3a383b
JK
32static int uprobes_pass (systemtap_session& s);
33
6274464e
JK
34/* Adjust and run make_cmd to build a kernel module. */
35static int
36run_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
63int
64compile_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 164static 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 */
171static bool
172kernel_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
180static bool
181verify_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
199static int
200make_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 */
223static int
224copy_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
232static int
233uprobes_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
259int
260run_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}
This page took 0.101158 seconds and 5 git commands to generate.