]>
Commit | Line | Data |
---|---|---|
f4b28491 | 1 | // systemtap translator/driver |
e7a0bd52 | 2 | // Copyright (C) 2005-2009 Red Hat Inc. |
f12b2552 | 3 | // Copyright (C) 2005 IBM Corp. |
77a5c1f9 | 4 | // Copyright (C) 2006 Intel Corporation. |
69c68955 FCE |
5 | // |
6 | // This file is part of systemtap, and is free software. You can | |
7 | // redistribute it and/or modify it under the terms of the GNU General | |
8 | // Public License (GPL); either version 2, or (at your option) any | |
9 | // later version. | |
2b066ec1 FCE |
10 | |
11 | #include "config.h" | |
12 | #include "staptree.h" | |
13 | #include "parse.h" | |
14 | #include "elaborate.h" | |
15 | #include "translate.h" | |
f4b28491 | 16 | #include "buildrun.h" |
dc38c0ae | 17 | #include "session.h" |
1b78aef5 DS |
18 | #include "hash.h" |
19 | #include "cache.h" | |
20 | #include "util.h" | |
c3a3c0c9 | 21 | #include "coveragedb.h" |
c0f9d4b0 | 22 | #include "git_version.h" |
2ed04863 | 23 | #include "rpm_finder.h" |
ce91eebd | 24 | #include "sys/sdt.h" |
2b066ec1 FCE |
25 | |
26 | #include <iostream> | |
27 | #include <fstream> | |
28 | #include <sstream> | |
f4b28491 | 29 | #include <cerrno> |
24cb178f | 30 | #include <cstdlib> |
e00f99a7 | 31 | #include <limits.h> |
2b066ec1 FCE |
32 | |
33 | extern "C" { | |
34 | #include <glob.h> | |
35 | #include <unistd.h> | |
49abf162 | 36 | #include <signal.h> |
f4b28491 | 37 | #include <sys/utsname.h> |
5ee1c56b | 38 | #include <sys/times.h> |
1d738eed | 39 | #include <sys/time.h> |
f59e98c4 | 40 | #include <sys/stat.h> |
f4b28491 | 41 | #include <time.h> |
f8949662 | 42 | #include <elfutils/libdwfl.h> |
5f0a03a6 | 43 | #include <getopt.h> |
2b066ec1 FCE |
44 | } |
45 | ||
46 | using namespace std; | |
47 | ||
8f222481 | 48 | #define PATH_TBD string("__TBD__") |
2b066ec1 | 49 | |
f4b28491 | 50 | void |
c0de7a8d | 51 | version () |
2b066ec1 | 52 | { |
d54d4661 | 53 | clog |
d04cf5ff | 54 | << "SystemTap translator/driver " |
c4a94c1a | 55 | << "(version " << VERSION << "/" << dwfl_version (NULL) |
2881ab63 | 56 | << " " << GIT_MESSAGE << ")" << endl |
e7a0bd52 | 57 | << "Copyright (C) 2005-2009 Red Hat, Inc. and others" << endl |
f8949662 | 58 | << "This is free software; see the source for copying conditions." << endl; |
c0de7a8d FCE |
59 | } |
60 | ||
61 | void | |
277c1957 | 62 | usage (systemtap_session& s, int exitcode) |
c0de7a8d FCE |
63 | { |
64 | version (); | |
65 | clog | |
f4b28491 | 66 | << endl |
b2d5d95c | 67 | << "Usage: stap [options] FILE Run script in file." |
f4b28491 | 68 | << endl |
b2d5d95c | 69 | << " or: stap [options] - Run script on stdin." |
f4b28491 | 70 | << endl |
d54d4661 | 71 | << " or: stap [options] -e SCRIPT Run given script." |
f4b28491 | 72 | << endl |
16442b90 FCE |
73 | << " or: stap [options] -l PROBE List matching probes." |
74 | << endl | |
d4e35ac8 WH |
75 | << " or: stap [options] -L PROBE List matching probes and local variables." |
76 | << endl | |
f4b28491 | 77 | << endl |
c0de7a8d | 78 | << "Options:" << endl |
16442b90 | 79 | << " -- end of translator options, script options follow" << endl |
c0de7a8d FCE |
80 | << " -h show help" << endl |
81 | << " -V show version" << endl | |
e0b4e89d FCE |
82 | << " -p NUM stop after pass NUM 1-5, instead of " << s.last_pass << endl |
83 | << " (parse, elaborate, translate, compile, run)" << endl | |
84 | << " -v add verbosity to all passes" << endl | |
85 | << " --vp {N}+ add per-pass verbosity ["; | |
86 | for (unsigned i=0; i<5; i++) | |
87 | clog << (s.perpass_verbose[i] <= 9 ? s.perpass_verbose[i] : 9); | |
88 | clog | |
89 | << "]" << endl | |
d5d7c2cc | 90 | << " -k keep temporary directory" << endl |
cbfbbf69 | 91 | << " -u unoptimized translation" << (s.unoptimized ? " [set]" : "") << endl |
a9e8f7e0 | 92 | << " -w suppress warnings" << (s.suppress_warnings ? " [set]" : "") << endl |
377b8831 | 93 | << " -g guru mode" << (s.guru_mode ? " [set]" : "") << endl |
dff50e09 | 94 | << " -P prologue-searching for function probes" |
44f75386 | 95 | << (s.prologue_searching ? " [set]" : "") << endl |
6dfd08d7 | 96 | << " -b bulk (percpu file) mode" << (s.bulk_mode ? " [set]" : "") << endl |
e0b4e89d | 97 | << " -s NUM buffer size in megabytes, instead of " << s.buffer_size << endl |
f4b28491 FCE |
98 | << " -I DIR look in DIR for additional .stp script files"; |
99 | if (s.include_path.size() == 0) | |
0d49d7bc | 100 | clog << endl; |
f4b28491 | 101 | else |
24cb178f | 102 | clog << ", in addition to" << endl; |
f4b28491 | 103 | for (unsigned i=0; i<s.include_path.size(); i++) |
0d49d7bc FCE |
104 | clog << " " << s.include_path[i] << endl; |
105 | clog | |
ed10c639 | 106 | << " -D NM=VAL emit macro definition into generated C code" << endl |
24cb178f | 107 | << " -R DIR look in DIR for runtime, instead of" << endl |
b5e66ada FCE |
108 | << " " << s.runtime_path << endl |
109 | << " -r DIR cross-compile to kernel with given build tree; or else" << endl | |
110 | << " -r RELEASE cross-compile to kernel /lib/modules/RELEASE/build, instead of" << endl | |
111 | << " " << s.kernel_build_tree << endl | |
112 | << " -m MODULE set probe module name, instead of " << endl | |
113 | << " " << s.module_name << endl | |
04ae1b09 | 114 | << " -o FILE send script output to file, instead of stdout. This supports" << endl |
54f1da8f | 115 | << " strftime(3) formats for FILE" << endl |
b5e66ada | 116 | << " -c CMD start the probes, run CMD, and exit when it finishes" << endl |
4c5ff1bb | 117 | << " -x PID sets target() to PID" << endl |
701c41be MH |
118 | << " -F run as on-file flight recorder with -o." << endl |
119 | << " run as on-memory flight recorder without -o." << endl | |
120 | << " -S size[,n] set maximum of the size and the number of files." << endl | |
a8368458 FCE |
121 | << " -d OBJECT add unwind/symbol data for OBJECT file"; |
122 | if (s.unwindsym_modules.size() == 0) | |
123 | clog << endl; | |
124 | else | |
125 | clog << ", in addition to" << endl; | |
1a0dbc5a FCE |
126 | { |
127 | vector<string> syms (s.unwindsym_modules.begin(), s.unwindsym_modules.end()); | |
128 | for (unsigned i=0; i<syms.size(); i++) | |
129 | clog << " " << syms[i] << endl; | |
130 | } | |
a8368458 | 131 | clog |
cbd6fc7b | 132 | << " -t collect probe timing information" << endl |
1c0b94ef | 133 | #ifdef HAVE_LIBSQLITE3 |
5f0a03a6 | 134 | << " -q generate information on tapset coverage" << endl |
1c0b94ef | 135 | #endif /* HAVE_LIBSQLITE3 */ |
2f54c4fe DB |
136 | << " --unprivileged" << endl |
137 | << " restrict usage to features available to unprivileged users" << endl | |
05ec91b4 | 138 | #if 0 /* PR6864: disable temporarily; should merge with -d somehow */ |
5f0a03a6 JK |
139 | << " --kelf make do with symbol table from vmlinux" << endl |
140 | << " --kmap[=FILE]" << endl | |
141 | << " make do with symbol table from nm listing" << endl | |
05ec91b4 FCE |
142 | #endif |
143 | // Formerly present --ignore-{vmlinux,dwarf} options are for testsuite use | |
144 | // only, and don't belong in the eyesight of a plain user. | |
3bd0d4df RA |
145 | << " --skip-badvars" << endl |
146 | << " overlook context of bad $ variables" << endl | |
c3a3c0c9 | 147 | << endl |
d5d7c2cc | 148 | ; |
2b066ec1 | 149 | |
277c1957 | 150 | exit (exitcode); |
2b066ec1 FCE |
151 | } |
152 | ||
153 | ||
1b78aef5 DS |
154 | static void |
155 | printscript(systemtap_session& s, ostream& o) | |
156 | { | |
16442b90 | 157 | if (s.listing_mode) |
83d7fcdc | 158 | { |
16442b90 FCE |
159 | // We go through some heroic measures to produce clean output. |
160 | set<string> seen; | |
83d7fcdc | 161 | |
16442b90 | 162 | for (unsigned i=0; i<s.probes.size(); i++) |
9ba8c134 | 163 | { |
f76427a2 FCE |
164 | if (pending_interrupts) return; |
165 | ||
16442b90 FCE |
166 | derived_probe* p = s.probes[i]; |
167 | // NB: p->basest() is not so interesting; | |
168 | // p->almost_basest() doesn't quite work, so ... | |
169 | vector<probe*> chain; | |
170 | p->collect_derivation_chain (chain); | |
171 | probe* second = (chain.size()>1) ? chain[chain.size()-2] : chain[0]; | |
172 | ||
173 | #if 0 | |
174 | cerr << "\tchain[" << chain.size() << "]:" << endl; | |
175 | for (unsigned i=0; i<chain.size(); i++) | |
176 | { cerr << "\t"; chain[i]->printsig(cerr); cerr << endl; } | |
177 | #endif | |
178 | ||
179 | stringstream tmps; | |
7fb2f650 FCE |
180 | const probe_alias *a = second->get_alias(); |
181 | if (a) | |
182 | { | |
183 | assert (a->alias_names.size() >= 1); | |
184 | a->alias_names[0]->print(tmps); // XXX: [0] is arbitrary; perhaps print all | |
dff50e09 | 185 | } |
7fb2f650 FCE |
186 | else |
187 | { | |
188 | assert (second->locations.size() >= 1); | |
189 | second->locations[0]->print(tmps); // XXX: [0] is less arbitrary here, but still ... | |
190 | } | |
191 | string pp = tmps.str(); | |
16442b90 FCE |
192 | |
193 | // Now duplicate-eliminate. An alias may have expanded to | |
194 | // several actual derived probe points, but we only want to | |
195 | // print the alias head name once. | |
196 | if (seen.find (pp) == seen.end()) | |
197 | { | |
d4e35ac8 | 198 | o << pp; |
223f5b6b | 199 | // Print the locals for -L mode only |
8c39844b JS |
200 | if (s.listing_mode_vars) |
201 | { | |
202 | for (unsigned j=0; j<p->locals.size(); j++) | |
203 | { | |
204 | o << " "; | |
205 | vardecl* v = p->locals[j]; | |
206 | v->printsig (o); | |
207 | } | |
208 | // Print arguments of probe if there | |
209 | p->printargs(o); | |
210 | } | |
223f5b6b | 211 | o << endl; |
16442b90 FCE |
212 | seen.insert (pp); |
213 | } | |
9ba8c134 | 214 | } |
1b78aef5 | 215 | } |
16442b90 | 216 | else |
1b78aef5 | 217 | { |
16442b90 FCE |
218 | if (s.embeds.size() > 0) |
219 | o << "# global embedded code" << endl; | |
220 | for (unsigned i=0; i<s.embeds.size(); i++) | |
1b78aef5 | 221 | { |
f76427a2 | 222 | if (pending_interrupts) return; |
16442b90 FCE |
223 | embeddedcode* ec = s.embeds[i]; |
224 | ec->print (o); | |
225 | o << endl; | |
226 | } | |
dff50e09 | 227 | |
16442b90 FCE |
228 | if (s.globals.size() > 0) |
229 | o << "# globals" << endl; | |
230 | for (unsigned i=0; i<s.globals.size(); i++) | |
1b78aef5 | 231 | { |
f76427a2 | 232 | if (pending_interrupts) return; |
16442b90 FCE |
233 | vardecl* v = s.globals[i]; |
234 | v->printsig (o); | |
235 | if (s.verbose && v->init) | |
236 | { | |
237 | o << " = "; | |
238 | v->init->print(o); | |
239 | } | |
240 | o << endl; | |
241 | } | |
dff50e09 | 242 | |
16442b90 FCE |
243 | if (s.functions.size() > 0) |
244 | o << "# functions" << endl; | |
f76427a2 | 245 | for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++) |
1b78aef5 | 246 | { |
f76427a2 FCE |
247 | if (pending_interrupts) return; |
248 | functiondecl* f = it->second; | |
16442b90 FCE |
249 | f->printsig (o); |
250 | o << endl; | |
251 | if (f->locals.size() > 0) | |
252 | o << " # locals" << endl; | |
253 | for (unsigned j=0; j<f->locals.size(); j++) | |
254 | { | |
255 | vardecl* v = f->locals[j]; | |
256 | o << " "; | |
257 | v->printsig (o); | |
258 | o << endl; | |
259 | } | |
260 | if (s.verbose) | |
261 | { | |
262 | f->body->print (o); | |
263 | o << endl; | |
264 | } | |
265 | } | |
dff50e09 | 266 | |
16442b90 FCE |
267 | if (s.probes.size() > 0) |
268 | o << "# probes" << endl; | |
269 | for (unsigned i=0; i<s.probes.size(); i++) | |
1b78aef5 | 270 | { |
f76427a2 | 271 | if (pending_interrupts) return; |
16442b90 FCE |
272 | derived_probe* p = s.probes[i]; |
273 | p->printsig (o); | |
274 | o << endl; | |
275 | if (p->locals.size() > 0) | |
276 | o << " # locals" << endl; | |
277 | for (unsigned j=0; j<p->locals.size(); j++) | |
278 | { | |
279 | vardecl* v = p->locals[j]; | |
280 | o << " "; | |
281 | v->printsig (o); | |
282 | o << endl; | |
283 | } | |
284 | if (s.verbose) | |
285 | { | |
286 | p->body->print (o); | |
287 | o << endl; | |
288 | } | |
289 | } | |
290 | } | |
277f2b79 | 291 | } |
1b78aef5 | 292 | |
49abf162 FCE |
293 | |
294 | int pending_interrupts; | |
295 | ||
296 | extern "C" | |
82737bef | 297 | void handle_interrupt (int sig) |
49abf162 | 298 | { |
4cc40e82 | 299 | kill_stap_spawn(sig); |
49abf162 | 300 | pending_interrupts ++; |
4cc40e82 | 301 | if (pending_interrupts > 1) // XXX: should be configurable? time-based? |
49abf162 FCE |
302 | { |
303 | char msg[] = "Too many interrupts received, exiting.\n"; | |
304 | int rc = write (2, msg, sizeof(msg)-1); | |
9ceec314 | 305 | if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;} |
49abf162 FCE |
306 | _exit (1); |
307 | } | |
308 | } | |
309 | ||
310 | ||
3972b443 DS |
311 | void |
312 | setup_signals (sighandler_t handler) | |
313 | { | |
314 | struct sigaction sa; | |
315 | ||
316 | sa.sa_handler = handler; | |
317 | sigemptyset (&sa.sa_mask); | |
318 | if (handler != SIG_IGN) | |
319 | { | |
320 | sigaddset (&sa.sa_mask, SIGHUP); | |
321 | sigaddset (&sa.sa_mask, SIGPIPE); | |
322 | sigaddset (&sa.sa_mask, SIGINT); | |
323 | sigaddset (&sa.sa_mask, SIGTERM); | |
324 | } | |
4cc40e82 | 325 | sa.sa_flags = SA_RESTART; |
3972b443 DS |
326 | |
327 | sigaction (SIGHUP, &sa, NULL); | |
328 | sigaction (SIGPIPE, &sa, NULL); | |
329 | sigaction (SIGINT, &sa, NULL); | |
330 | sigaction (SIGTERM, &sa, NULL); | |
331 | } | |
332 | ||
4d0a3330 KS |
333 | void |
334 | setup_kernel_release (systemtap_session &s, const char* kstr) { | |
335 | if (kstr[0] == '/') // fully specified path | |
336 | { | |
337 | s.kernel_build_tree = kstr; | |
338 | string version_file_name = s.kernel_build_tree + "/include/config/kernel.release"; | |
339 | // The file include/config/kernel.release within the | |
340 | // build tree is used to pull out the version information | |
341 | ifstream version_file (version_file_name.c_str()); | |
342 | if (version_file.fail ()) | |
343 | { | |
344 | cerr << "Missing " << version_file_name << endl; | |
345 | exit(1); | |
346 | } | |
347 | else | |
348 | { | |
349 | char c; | |
350 | s.kernel_release = ""; | |
351 | while (version_file.get(c) && c != '\n') | |
352 | s.kernel_release.push_back(c); | |
353 | } | |
354 | } | |
355 | else | |
356 | { | |
357 | s.kernel_release = string (kstr); | |
358 | s.kernel_build_tree = "/lib/modules/" + s.kernel_release + "/build"; | |
359 | } | |
360 | } | |
3972b443 | 361 | |
8f222481 DB |
362 | static void |
363 | checkOptions (systemtap_session &s) | |
364 | { | |
365 | bool optionsConflict = false; | |
366 | ||
367 | if(!s.bulk_mode && !s.merge) | |
368 | { | |
369 | cerr << "-M option is valid only for bulk (relayfs) mode." <<endl; | |
370 | optionsConflict = true; | |
371 | } | |
372 | ||
373 | if(!s.output_file.empty() && s.bulk_mode && !s.merge) | |
374 | { | |
375 | cerr << "You can't specify -M, -b and -o options together." <<endl; | |
376 | optionsConflict = true; | |
377 | } | |
378 | ||
379 | if((s.cmd != "") && (s.target_pid)) | |
380 | { | |
381 | cerr << "You can't specify -c and -x options together." <<endl; | |
382 | optionsConflict = true; | |
383 | } | |
384 | ||
385 | if (s.unprivileged) | |
386 | { | |
387 | if (s.guru_mode) | |
388 | { | |
389 | cerr << "You can't specify -g and --unprivileged together." << endl; | |
390 | optionsConflict = true; | |
391 | } | |
392 | if (s.include_path.size () > 1) | |
393 | { | |
394 | cerr << "You can't specify -I and --unprivileged together." << endl; | |
395 | optionsConflict = true; | |
396 | } | |
397 | if (s.runtime_path != string(PKGDATADIR) + "/runtime") | |
398 | { | |
399 | cerr << "You can't use -R to specify an alternate runtime path when --unprivileged is specified." << endl; | |
400 | optionsConflict = true; | |
401 | } | |
402 | if (s.kernel_build_tree.substr(0, 13) != "/lib/modules/") | |
403 | { | |
404 | cerr << "You can't use -r to specify a kernel release which is not installed when --unprivileged is specified." << endl; | |
405 | optionsConflict = true; | |
406 | } | |
407 | if (! s.macros.empty ()) | |
408 | { | |
409 | cerr << "You can't specify -D and --unprivileged together." << endl; | |
410 | optionsConflict = true; | |
411 | } | |
412 | ||
413 | if (getenv ("SYSTEMTAP_TAPSET")) | |
414 | { | |
415 | cerr << "The environment variable SYSTEMTAP_TAPSET can not be defined when --unprivileged is specified." << endl; | |
416 | optionsConflict = true; | |
417 | } | |
418 | if (getenv ("SYSTEMTAP_RUNTIME")) | |
419 | { | |
420 | cerr << "The environment variable SYSTEMTAP_RUNTIME can not be defined when --unprivileged is specified." << endl; | |
421 | optionsConflict = true; | |
422 | } | |
423 | if (getenv ("SYSTEMTAP_DEBUGINFO_PATH")) | |
424 | { | |
425 | cerr << "The environment variable SYSTEMTAP_DEBUGINFO_PATH can not be defined when --unprivileged is specified." << endl; | |
426 | optionsConflict = true; | |
427 | } | |
428 | } | |
429 | ||
430 | if (!s.kernel_symtab_path.empty()) | |
431 | { | |
432 | if (s.consult_symtab) | |
433 | { | |
434 | cerr << "You can't specify --kelf and --kmap together." << endl; | |
435 | optionsConflict = true; | |
436 | } | |
437 | s.consult_symtab = true; | |
438 | if (s.kernel_symtab_path == PATH_TBD) | |
439 | s.kernel_symtab_path = string("/boot/System.map-") + s.kernel_release; | |
440 | } | |
441 | ||
442 | if (optionsConflict) | |
443 | usage (s, 1); | |
444 | } | |
445 | ||
2b066ec1 FCE |
446 | int |
447 | main (int argc, char * const argv []) | |
448 | { | |
2b066ec1 FCE |
449 | string cmdline_script; // -e PROGRAM |
450 | string script_file; // FILE | |
451 | bool have_script = false; | |
fc52ef5b | 452 | bool save_module = false; |
f4b28491 FCE |
453 | |
454 | // Initialize defaults | |
455 | systemtap_session s; | |
456 | struct utsname buf; | |
457 | (void) uname (& buf); | |
458 | s.kernel_release = string (buf.release); | |
b5e66ada FCE |
459 | s.kernel_build_tree = "/lib/modules/" + s.kernel_release + "/build"; |
460 | ||
44ce8ed5 | 461 | s.architecture = string (buf.machine); |
e0b4e89d | 462 | for (unsigned i=0; i<5; i++) s.perpass_verbose[i]=0; |
a9e8f7e0 | 463 | s.timing = false; |
377b8831 | 464 | s.guru_mode = false; |
16d8de1b | 465 | s.bulk_mode = false; |
cbfbbf69 | 466 | s.unoptimized = false; |
a9e8f7e0 | 467 | s.suppress_warnings = false; |
16442b90 | 468 | s.listing_mode = false; |
8c39844b | 469 | s.listing_mode_vars = false; |
44f75386 FCE |
470 | |
471 | #ifdef ENABLE_PROLOGUES | |
472 | s.prologue_searching = true; | |
473 | #else | |
474 | s.prologue_searching = false; | |
475 | #endif | |
476 | ||
16d8de1b | 477 | s.buffer_size = 0; |
f4b28491 | 478 | s.last_pass = 5; |
ae24723e | 479 | s.module_name = "stap_" + stringify(getpid()); |
de0db58a | 480 | s.stapconf_name = "stapconf_" + stringify(getpid()) + ".h"; |
08c68653 | 481 | s.output_file = ""; // -o FILE |
f4b28491 | 482 | s.keep_tmpdir = false; |
4c5ff1bb MH |
483 | s.cmd = ""; |
484 | s.target_pid = 0; | |
f272aacc | 485 | s.merge=true; |
47dd066d | 486 | s.perfmon=0; |
f1bad60c | 487 | s.symtab = false; |
1b78aef5 | 488 | s.use_cache = true; |
c3a3c0c9 | 489 | s.tapset_compile_coverage = false; |
12dc24bc | 490 | s.need_uprobes = false; |
5f0a03a6 JK |
491 | s.consult_symtab = false; |
492 | s.ignore_vmlinux = false; | |
493 | s.ignore_dwarf = false; | |
2fa2a091 | 494 | s.load_only = false; |
28f569c2 | 495 | s.skip_badvars = false; |
2f54c4fe DB |
496 | s.unprivileged = false; |
497 | ||
4c797c5e | 498 | // Location of our signing certificate. |
2f54c4fe DB |
499 | // If we're root, use the database in SYSCONFDIR, otherwise |
500 | // use the one in our $HOME directory. */ | |
501 | if (getuid() == 0) | |
502 | s.cert_db_path = SYSCONFDIR "/systemtap/ssl/server"; | |
503 | else | |
504 | s.cert_db_path = getenv("HOME") + string ("/.systemtap/ssl/server"); | |
24cb178f FCE |
505 | |
506 | const char* s_p = getenv ("SYSTEMTAP_TAPSET"); | |
dff50e09 | 507 | if (s_p != NULL) |
ec819dc3 | 508 | { |
24cb178f | 509 | s.include_path.push_back (s_p); |
ec819dc3 | 510 | } |
24cb178f | 511 | else |
ec819dc3 | 512 | { |
24cb178f | 513 | s.include_path.push_back (string(PKGDATADIR) + "/tapset"); |
ec819dc3 | 514 | } |
24cb178f FCE |
515 | |
516 | const char* s_r = getenv ("SYSTEMTAP_RUNTIME"); | |
517 | if (s_r != NULL) | |
518 | s.runtime_path = s_r; | |
519 | else | |
520 | s.runtime_path = string(PKGDATADIR) + "/runtime"; | |
f4b28491 | 521 | |
1b78aef5 DS |
522 | const char* s_d = getenv ("SYSTEMTAP_DIR"); |
523 | if (s_d != NULL) | |
524 | s.data_path = s_d; | |
525 | else | |
526 | s.data_path = get_home_directory() + string("/.systemtap"); | |
527 | if (create_dir(s.data_path.c_str()) == 1) | |
528 | { | |
529 | const char* e = strerror (errno); | |
f4d5049b FCE |
530 | if (! s.suppress_warnings) |
531 | cerr << "Warning: failed to create systemtap data directory (\"" | |
532 | << s.data_path << "\"): " << e | |
533 | << ", disabling cache support." << endl; | |
1b78aef5 DS |
534 | s.use_cache = false; |
535 | } | |
536 | ||
537 | if (s.use_cache) | |
538 | { | |
539 | s.cache_path = s.data_path + "/cache"; | |
540 | if (create_dir(s.cache_path.c_str()) == 1) | |
541 | { | |
542 | const char* e = strerror (errno); | |
f4d5049b FCE |
543 | if (! s.suppress_warnings) |
544 | cerr << "Warning: failed to create cache directory (\"" | |
545 | << s.cache_path << "\"): " << e | |
546 | << ", disabling cache support." << endl; | |
1b78aef5 DS |
547 | s.use_cache = false; |
548 | } | |
549 | } | |
550 | ||
36b66efa DB |
551 | // Location of our signing certificate. |
552 | // If we're root, use the database in SYSCONFDIR, otherwise | |
553 | // use the one in s.data_path. */ | |
554 | if (geteuid() == 0) | |
555 | s.cert_db_path = SYSCONFDIR "/systemtap/ssl/server"; | |
556 | else | |
557 | s.cert_db_path = s.data_path + "/ssl/server"; | |
558 | ||
c3a3c0c9 WC |
559 | const char* s_tc = getenv ("SYSTEMTAP_COVERAGE"); |
560 | if (s_tc != NULL) | |
561 | s.tapset_compile_coverage = true; | |
562 | ||
755cdd9b KS |
563 | const char* s_kr = getenv ("SYSTEMTAP_RELEASE"); |
564 | if (s_kr != NULL) { | |
4d0a3330 | 565 | setup_kernel_release(s, s_kr); |
755cdd9b KS |
566 | } |
567 | ||
568 | ||
2b066ec1 FCE |
569 | while (true) |
570 | { | |
5f0a03a6 | 571 | int long_opt; |
877bbb20 | 572 | char * num_endptr; |
5f0a03a6 JK |
573 | #define LONG_OPT_KELF 1 |
574 | #define LONG_OPT_KMAP 2 | |
575 | #define LONG_OPT_IGNORE_VMLINUX 3 | |
576 | #define LONG_OPT_IGNORE_DWARF 4 | |
e0b4e89d | 577 | #define LONG_OPT_VERBOSE_PASS 5 |
3bd0d4df | 578 | #define LONG_OPT_SKIP_BADVARS 6 |
4c797c5e | 579 | #define LONG_OPT_UNPRIVILEGED 7 |
a9e8f7e0 | 580 | // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page |
5f0a03a6 JK |
581 | static struct option long_options[] = { |
582 | { "kelf", 0, &long_opt, LONG_OPT_KELF }, | |
583 | { "kmap", 2, &long_opt, LONG_OPT_KMAP }, | |
584 | { "ignore-vmlinux", 0, &long_opt, LONG_OPT_IGNORE_VMLINUX }, | |
585 | { "ignore-dwarf", 0, &long_opt, LONG_OPT_IGNORE_DWARF }, | |
3bd0d4df | 586 | { "skip-badvars", 0, &long_opt, LONG_OPT_SKIP_BADVARS }, |
e0b4e89d | 587 | { "vp", 1, &long_opt, LONG_OPT_VERBOSE_PASS }, |
2f54c4fe | 588 | { "unprivileged", 0, &long_opt, LONG_OPT_UNPRIVILEGED }, |
5f0a03a6 JK |
589 | { NULL, 0, NULL, 0 } |
590 | }; | |
01116596 | 591 | int grc = getopt_long (argc, argv, "hVMvtp:I:e:o:R:r:m:kgPc:x:D:bs:uqwl:d:L:FS:", |
5f0a03a6 | 592 | long_options, NULL); |
2b066ec1 FCE |
593 | if (grc < 0) |
594 | break; | |
595 | switch (grc) | |
596 | { | |
c0de7a8d FCE |
597 | case 'V': |
598 | version (); | |
599 | exit (0); | |
600 | ||
f272aacc LG |
601 | case 'M': |
602 | s.merge = false; | |
603 | break; | |
604 | ||
bd2b1e68 | 605 | case 'v': |
e0b4e89d FCE |
606 | for (unsigned i=0; i<5; i++) |
607 | s.perpass_verbose[i] ++; | |
bd2b1e68 GH |
608 | break; |
609 | ||
4b17d6af | 610 | case 't': |
a9e8f7e0 FCE |
611 | s.timing = true; |
612 | break; | |
613 | ||
614 | case 'w': | |
615 | s.suppress_warnings = true; | |
4b17d6af WC |
616 | break; |
617 | ||
2b066ec1 | 618 | case 'p': |
16442b90 FCE |
619 | if (s.listing_mode) |
620 | { | |
621 | cerr << "Listing (-l) mode implies pass 2." << endl; | |
622 | usage (s, 1); | |
623 | } | |
877bbb20 SW |
624 | s.last_pass = (int)strtoul(optarg, &num_endptr, 10); |
625 | if (*num_endptr != '\0' || s.last_pass < 1 || s.last_pass > 5) | |
2b066ec1 | 626 | { |
277c1957 DS |
627 | cerr << "Invalid pass number (should be 1-5)." << endl; |
628 | usage (s, 1); | |
2b066ec1 FCE |
629 | } |
630 | break; | |
631 | ||
632 | case 'I': | |
f4b28491 | 633 | s.include_path.push_back (string (optarg)); |
2b066ec1 FCE |
634 | break; |
635 | ||
a8368458 | 636 | case 'd': |
1a0dbc5a | 637 | s.unwindsym_modules.insert (string (optarg)); |
a8368458 FCE |
638 | break; |
639 | ||
2b066ec1 FCE |
640 | case 'e': |
641 | if (have_script) | |
277c1957 DS |
642 | { |
643 | cerr << "Only one script can be given on the command line." | |
644 | << endl; | |
645 | usage (s, 1); | |
646 | } | |
2b066ec1 FCE |
647 | cmdline_script = string (optarg); |
648 | have_script = true; | |
649 | break; | |
650 | ||
651 | case 'o': | |
08c68653 | 652 | s.output_file = string (optarg); |
2b066ec1 FCE |
653 | break; |
654 | ||
f4b28491 FCE |
655 | case 'R': |
656 | s.runtime_path = string (optarg); | |
657 | break; | |
658 | ||
659 | case 'm': | |
660 | s.module_name = string (optarg); | |
fc52ef5b | 661 | save_module = true; |
3b942fed DS |
662 | { |
663 | string::size_type len = s.module_name.length(); | |
664 | ||
665 | // If the module name ends with '.ko', chop it off since | |
666 | // modutils doesn't like modules named 'foo.ko.ko'. | |
667 | if (len > 3 && s.module_name.substr(len - 3, 3) == ".ko") | |
668 | { | |
669 | s.module_name.erase(len - 3); | |
670 | len -= 3; | |
671 | cerr << "Truncating module name to '" << s.module_name | |
672 | << "'" << endl; | |
673 | } | |
674 | ||
675 | // Make sure an empty module name wasn't specified (-m "") | |
676 | if (len == 0) | |
677 | { | |
678 | cerr << "Module name cannot be empty." << endl; | |
679 | usage (s, 1); | |
680 | } | |
681 | ||
682 | // Make sure the module name is only composed of the | |
683 | // following chars: [_a-zA-Z0-9] | |
684 | const string identchars("_" "abcdefghijklmnopqrstuvwxyz" | |
685 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"); | |
686 | if (s.module_name.find_first_not_of(identchars) != string::npos) | |
687 | { | |
688 | cerr << "Invalid module name (must only be composed of" | |
689 | " characters [_a-zA-Z0-9])." << endl; | |
690 | usage (s, 1); | |
691 | } | |
98aab489 DS |
692 | |
693 | // Make sure module name isn't too long. | |
694 | if (s.module_name.size() >= (MODULE_NAME_LEN - 1)) | |
695 | { | |
696 | s.module_name.resize(MODULE_NAME_LEN - 1); | |
697 | cerr << "Truncating module name to '" << s.module_name | |
698 | << "'" << endl; | |
699 | } | |
3b942fed DS |
700 | } |
701 | ||
1b78aef5 | 702 | s.use_cache = false; |
f4b28491 FCE |
703 | break; |
704 | ||
705 | case 'r': | |
4d0a3330 | 706 | setup_kernel_release(s, optarg); |
f4b28491 FCE |
707 | break; |
708 | ||
709 | case 'k': | |
710 | s.keep_tmpdir = true; | |
f53a92f9 | 711 | s.use_cache = false; /* User wants to keep a usable build tree. */ |
f4b28491 FCE |
712 | break; |
713 | ||
377b8831 FCE |
714 | case 'g': |
715 | s.guru_mode = true; | |
716 | break; | |
717 | ||
44f75386 FCE |
718 | case 'P': |
719 | s.prologue_searching = true; | |
720 | break; | |
721 | ||
16d8de1b TZ |
722 | case 'b': |
723 | s.bulk_mode = true; | |
16d8de1b TZ |
724 | break; |
725 | ||
cbfbbf69 FCE |
726 | case 'u': |
727 | s.unoptimized = true; | |
728 | break; | |
729 | ||
16d8de1b | 730 | case 's': |
5d8d4509 SW |
731 | s.buffer_size = (int) strtoul (optarg, &num_endptr, 10); |
732 | if (*num_endptr != '\0' || s.buffer_size < 1 || s.buffer_size > 4095) | |
16d8de1b | 733 | { |
453b58ed | 734 | cerr << "Invalid buffer size (should be 1-4095)." << endl; |
277c1957 | 735 | usage (s, 1); |
16d8de1b TZ |
736 | } |
737 | break; | |
738 | ||
4c5ff1bb MH |
739 | case 'c': |
740 | s.cmd = string (optarg); | |
741 | break; | |
742 | ||
743 | case 'x': | |
c897e941 SW |
744 | s.target_pid = (int) strtoul(optarg, &num_endptr, 10); |
745 | if (*num_endptr != '\0') | |
746 | { | |
747 | cerr << "Invalid target process ID number." << endl; | |
748 | usage (s, 1); | |
749 | } | |
4c5ff1bb MH |
750 | break; |
751 | ||
ed10c639 FCE |
752 | case 'D': |
753 | s.macros.push_back (string (optarg)); | |
754 | break; | |
755 | ||
701c41be MH |
756 | case 'S': |
757 | s.size_option = string (optarg); | |
758 | break; | |
759 | ||
c3a3c0c9 WC |
760 | case 'q': |
761 | s.tapset_compile_coverage = true; | |
762 | break; | |
763 | ||
2b066ec1 | 764 | case 'h': |
277c1957 DS |
765 | usage (s, 0); |
766 | break; | |
767 | ||
d4e35ac8 | 768 | case 'L': |
8c39844b | 769 | s.listing_mode_vars = true; |
1044139f | 770 | s.unoptimized = true; // This causes retention of variables for listing_mode |
d4e35ac8 | 771 | |
16442b90 | 772 | case 'l': |
4bd48e4b | 773 | s.suppress_warnings = true; |
16442b90 FCE |
774 | s.listing_mode = true; |
775 | s.last_pass = 2; | |
776 | if (have_script) | |
777 | { | |
778 | cerr << "Only one script can be given on the command line." | |
779 | << endl; | |
780 | usage (s, 1); | |
781 | } | |
782 | cmdline_script = string("probe ") + string(optarg) + " {}"; | |
783 | have_script = true; | |
784 | break; | |
785 | ||
2fa2a091 NT |
786 | case 'F': |
787 | s.load_only = true; | |
788 | break; | |
789 | ||
5f0a03a6 JK |
790 | case 0: |
791 | switch (long_opt) | |
792 | { | |
793 | case LONG_OPT_KELF: | |
794 | s.consult_symtab = true; | |
795 | break; | |
796 | case LONG_OPT_KMAP: | |
797 | // Leave s.consult_symtab unset for now, to ease error checking. | |
798 | if (!s.kernel_symtab_path.empty()) | |
799 | { | |
800 | cerr << "You can't specify multiple --kmap options." << endl; | |
801 | usage(s, 1); | |
802 | } | |
803 | if (optarg) | |
804 | s.kernel_symtab_path = optarg; | |
805 | else | |
5f0a03a6 JK |
806 | s.kernel_symtab_path = PATH_TBD; |
807 | break; | |
808 | case LONG_OPT_IGNORE_VMLINUX: | |
809 | s.ignore_vmlinux = true; | |
810 | break; | |
811 | case LONG_OPT_IGNORE_DWARF: | |
812 | s.ignore_dwarf = true; | |
813 | break; | |
e0b4e89d FCE |
814 | case LONG_OPT_VERBOSE_PASS: |
815 | { | |
816 | bool ok = true; | |
817 | if (strlen(optarg) < 1 || strlen(optarg) > 5) | |
818 | ok = false; | |
819 | if (ok) | |
b688229d | 820 | for (unsigned i=0; i<strlen(optarg); i++) |
e0b4e89d FCE |
821 | if (isdigit (optarg[i])) |
822 | s.perpass_verbose[i] += optarg[i]-'0'; | |
823 | else | |
824 | ok = false; | |
825 | ||
826 | if (! ok) | |
827 | { | |
828 | cerr << "Invalid --vp argument: it takes 1 to 5 digits." << endl; | |
829 | usage (s, 1); | |
830 | } | |
831 | // NB: we don't do this: s.last_pass = strlen(optarg); | |
832 | break; | |
833 | } | |
3bd0d4df RA |
834 | case LONG_OPT_SKIP_BADVARS: |
835 | s.skip_badvars = true; | |
836 | break; | |
2f54c4fe DB |
837 | case LONG_OPT_UNPRIVILEGED: |
838 | s.unprivileged = true; | |
839 | break; | |
5f0a03a6 JK |
840 | default: |
841 | cerr << "Internal error parsing command arguments." << endl; | |
842 | usage(s, 1); | |
843 | } | |
844 | break; | |
845 | ||
2b066ec1 | 846 | default: |
277c1957 DS |
847 | usage (s, 1); |
848 | break; | |
2b066ec1 FCE |
849 | } |
850 | } | |
851 | ||
8f222481 DB |
852 | // Check for options conflicts. |
853 | checkOptions (s); | |
5f0a03a6 | 854 | |
b5e66ada FCE |
855 | // Warn in case the target kernel release doesn't match the running one. |
856 | if (s.last_pass > 4 && | |
857 | (string(buf.release) != s.kernel_release || | |
858 | string(buf.machine) != s.architecture)) | |
859 | { | |
860 | if(! s.suppress_warnings) | |
861 | cerr << "WARNING: kernel release/architecture mismatch with host forces last-pass 4." << endl; | |
862 | s.last_pass = 4; | |
863 | } | |
ea3f75ae | 864 | |
2b066ec1 FCE |
865 | for (int i = optind; i < argc; i++) |
866 | { | |
867 | if (! have_script) | |
868 | { | |
869 | script_file = string (argv[i]); | |
870 | have_script = true; | |
871 | } | |
872 | else | |
f4b28491 | 873 | s.args.push_back (string (argv[i])); |
2b066ec1 FCE |
874 | } |
875 | ||
876 | // need a user file | |
877 | if (! have_script) | |
277c1957 DS |
878 | { |
879 | cerr << "A script must be specified." << endl; | |
880 | usage(s, 1); | |
881 | } | |
f4b28491 | 882 | |
a929fd0f Z |
883 | // translate path of runtime to absolute path |
884 | if (s.runtime_path[0] != '/') | |
885 | { | |
886 | char cwd[PATH_MAX]; | |
887 | if (getcwd(cwd, sizeof(cwd))) | |
888 | { | |
889 | s.runtime_path = string(cwd) + "/" + s.runtime_path; | |
890 | } | |
891 | } | |
892 | ||
f4b28491 | 893 | int rc = 0; |
c31df222 FCE |
894 | |
895 | // PASS 0: setting up | |
896 | s.verbose = s.perpass_verbose[0]; | |
ce91eebd KS |
897 | STAP_PROBE1(stap, pass0__start, &s); |
898 | ||
2b066ec1 | 899 | |
d0a7f5a9 FCE |
900 | // For PR1477, we used to override $PATH and $LC_ALL and other stuff |
901 | // here. We seem to use complete pathnames in | |
902 | // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further, | |
903 | // it interferes with util.cxx:find_executable(), used for $PATH | |
904 | // resolution. | |
861c2f28 | 905 | |
197a4d62 JS |
906 | s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-')); |
907 | ||
2b066ec1 | 908 | // arguments parsed; get down to business |
72d18b98 | 909 | if (s.verbose > 1) |
c0e526f0 FCE |
910 | { |
911 | version (); | |
912 | clog << "Session arch: " << s.architecture | |
913 | << " release: " << s.kernel_release | |
914 | << endl; | |
915 | } | |
2b066ec1 | 916 | |
f4b28491 FCE |
917 | // Create a temporary directory to build within. |
918 | // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end. | |
919 | { | |
c72dc86c | 920 | const char* tmpdir_env = getenv("TMPDIR"); |
ea8ea02c FCE |
921 | if (! tmpdir_env) |
922 | tmpdir_env = "/tmp"; | |
dff50e09 | 923 | |
ea8ea02c FCE |
924 | string stapdir = "/stapXXXXXX"; |
925 | string tmpdirt = tmpdir_env + stapdir; | |
533af4f0 | 926 | mode_t mask = umask(0); |
ea8ea02c | 927 | const char* tmpdir = mkdtemp((char *)tmpdirt.c_str()); |
533af4f0 | 928 | umask(mask); |
f4b28491 FCE |
929 | if (! tmpdir) |
930 | { | |
931 | const char* e = strerror (errno); | |
ea8ea02c FCE |
932 | cerr << "ERROR: cannot create temporary directory (\"" << tmpdirt << "\"): " << e << endl; |
933 | exit (1); // die | |
f4b28491 FCE |
934 | } |
935 | else | |
936 | s.tmpdir = tmpdir; | |
0d49d7bc | 937 | |
b0ee93c4 | 938 | if (s.verbose>1) |
0d49d7bc | 939 | clog << "Created temporary directory \"" << s.tmpdir << "\"" << endl; |
f4b28491 | 940 | } |
2b066ec1 | 941 | |
1b78aef5 DS |
942 | // Create the name of the C source file within the temporary |
943 | // directory. | |
944 | s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c"; | |
945 | ||
dff50e09 | 946 | // Set up our handler to catch routine signals, to allow clean |
49abf162 | 947 | // and reasonably timely exit. |
3972b443 | 948 | setup_signals(&handle_interrupt); |
49abf162 | 949 | |
ce91eebd KS |
950 | STAP_PROBE1(stap, pass0__end, &s); |
951 | ||
5ee1c56b FCE |
952 | struct tms tms_before; |
953 | times (& tms_before); | |
1d738eed FCE |
954 | struct timeval tv_before; |
955 | gettimeofday (&tv_before, NULL); | |
2b066ec1 FCE |
956 | |
957 | // PASS 1a: PARSING USER SCRIPT | |
ce91eebd | 958 | STAP_PROBE1(stap, pass1a__start, &s); |
f59e98c4 FCE |
959 | |
960 | struct stat user_file_stat; | |
961 | int user_file_stat_rc = -1; | |
962 | ||
69c68955 | 963 | if (script_file == "-") |
129be0ac FCE |
964 | { |
965 | s.user_file = parser::parse (s, cin, s.guru_mode); | |
966 | user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat); | |
967 | } | |
69c68955 | 968 | else if (script_file != "") |
f59e98c4 FCE |
969 | { |
970 | s.user_file = parser::parse (s, script_file, s.guru_mode); | |
971 | user_file_stat_rc = stat (script_file.c_str(), & user_file_stat); | |
972 | } | |
2b066ec1 FCE |
973 | else |
974 | { | |
975 | istringstream ii (cmdline_script); | |
177a8ead | 976 | s.user_file = parser::parse (s, ii, s.guru_mode); |
2b066ec1 FCE |
977 | } |
978 | if (s.user_file == 0) | |
979 | // syntax errors already printed | |
980 | rc ++; | |
377b8831 | 981 | |
5519d363 | 982 | // Construct arch / kernel-versioning search path |
377b8831 | 983 | vector<string> version_suffixes; |
6f9f33e2 | 984 | string kvr = s.kernel_release; |
5519d363 KS |
985 | const string& arch = s.architecture; |
986 | // add full kernel-version-release (2.6.NN-FOOBAR) + arch | |
987 | version_suffixes.push_back ("/" + kvr + "/" + arch); | |
377b8831 | 988 | version_suffixes.push_back ("/" + kvr); |
5519d363 | 989 | // add kernel version (2.6.NN) + arch |
197a4d62 JS |
990 | if (kvr != s.kernel_base_release) { |
991 | kvr = s.kernel_base_release; | |
6f9f33e2 JS |
992 | version_suffixes.push_back ("/" + kvr + "/" + arch); |
993 | version_suffixes.push_back ("/" + kvr); | |
5519d363 KS |
994 | } |
995 | // add kernel family (2.6) + arch | |
6f9f33e2 JS |
996 | string::size_type dot1_index = kvr.find ('.'); |
997 | string::size_type dot2_index = kvr.rfind ('.'); | |
998 | while (dot2_index > dot1_index && dot2_index != string::npos) { | |
999 | kvr.erase(dot2_index); | |
1000 | version_suffixes.push_back ("/" + kvr + "/" + arch); | |
1001 | version_suffixes.push_back ("/" + kvr); | |
1002 | dot2_index = kvr.rfind ('.'); | |
5519d363 KS |
1003 | } |
1004 | // add architecture search path | |
1005 | version_suffixes.push_back("/" + arch); | |
377b8831 FCE |
1006 | // add empty string as last element |
1007 | version_suffixes.push_back (""); | |
2b066ec1 FCE |
1008 | |
1009 | // PASS 1b: PARSING LIBRARY SCRIPTS | |
ce91eebd KS |
1010 | STAP_PROBE1(stap, pass1b__start, &s); |
1011 | ||
f4b28491 | 1012 | for (unsigned i=0; i<s.include_path.size(); i++) |
2b066ec1 | 1013 | { |
377b8831 FCE |
1014 | // now iterate upon it |
1015 | for (unsigned k=0; k<version_suffixes.size(); k++) | |
2b066ec1 | 1016 | { |
377b8831 FCE |
1017 | glob_t globbuf; |
1018 | string dir = s.include_path[i] + version_suffixes[k] + "/*.stp"; | |
1019 | int r = glob(dir.c_str (), 0, NULL, & globbuf); | |
1020 | if (r == GLOB_NOSPACE || r == GLOB_ABORTED) | |
2b066ec1 | 1021 | rc ++; |
377b8831 FCE |
1022 | // GLOB_NOMATCH is acceptable |
1023 | ||
c4a94c1a | 1024 | if (s.verbose>1 && globbuf.gl_pathc > 0) |
377b8831 | 1025 | clog << "Searched '" << dir << "', " |
c4a94c1a | 1026 | << "found " << globbuf.gl_pathc << endl; |
2b066ec1 | 1027 | |
377b8831 FCE |
1028 | for (unsigned j=0; j<globbuf.gl_pathc; j++) |
1029 | { | |
49abf162 FCE |
1030 | if (pending_interrupts) |
1031 | break; | |
1032 | ||
1033 | // XXX: privilege only for /usr/share/systemtap? | |
177a8ead | 1034 | stapfile* f = parser::parse (s, globbuf.gl_pathv[j], true); |
377b8831 FCE |
1035 | if (f == 0) |
1036 | rc ++; | |
1037 | else | |
24cb178f | 1038 | s.library_files.push_back (f); |
f59e98c4 FCE |
1039 | |
1040 | struct stat tapset_file_stat; | |
1041 | int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat); | |
1042 | if (stat_rc == 0 && user_file_stat_rc == 0 && | |
1043 | user_file_stat.st_dev == tapset_file_stat.st_dev && | |
1044 | user_file_stat.st_ino == tapset_file_stat.st_ino) | |
1045 | { | |
129be0ac FCE |
1046 | clog << "usage error: tapset file '" << globbuf.gl_pathv[j] |
1047 | << "' cannot be run directly as a session script." << endl; | |
f59e98c4 FCE |
1048 | rc ++; |
1049 | } | |
1050 | ||
377b8831 | 1051 | } |
d54d4661 | 1052 | |
377b8831 FCE |
1053 | globfree (& globbuf); |
1054 | } | |
2b066ec1 FCE |
1055 | } |
1056 | ||
f4b28491 | 1057 | if (rc == 0 && s.last_pass == 1) |
2b066ec1 | 1058 | { |
f4b28491 FCE |
1059 | cout << "# parse tree dump" << endl; |
1060 | s.user_file->print (cout); | |
1061 | cout << endl; | |
ae56fddd FCE |
1062 | if (s.verbose) |
1063 | for (unsigned i=0; i<s.library_files.size(); i++) | |
1064 | { | |
1065 | s.library_files[i]->print (cout); | |
1066 | cout << endl; | |
1067 | } | |
2b066ec1 FCE |
1068 | } |
1069 | ||
5ee1c56b FCE |
1070 | struct tms tms_after; |
1071 | times (& tms_after); | |
1072 | unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK); | |
1d738eed FCE |
1073 | struct timeval tv_after; |
1074 | gettimeofday (&tv_after, NULL); | |
5ee1c56b FCE |
1075 | |
1076 | #define TIMESPRINT \ | |
1077 | (tms_after.tms_cutime + tms_after.tms_utime \ | |
1d738eed | 1078 | - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \ |
5ee1c56b | 1079 | << (tms_after.tms_cstime + tms_after.tms_stime \ |
1d738eed FCE |
1080 | - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \ |
1081 | << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \ | |
1082 | ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms." | |
5ee1c56b | 1083 | |
eaf134e7 | 1084 | // syntax errors, if any, are already printed |
5ee1c56b FCE |
1085 | if (s.verbose) |
1086 | { | |
1087 | clog << "Pass 1: parsed user script and " | |
1088 | << s.library_files.size() | |
1089 | << " library script(s) in " | |
1090 | << TIMESPRINT | |
1091 | << endl; | |
1092 | } | |
0d49d7bc | 1093 | |
708ce1f3 | 1094 | if (rc && !s.listing_mode) |
2cfb0e46 | 1095 | cerr << "Pass 1: parse failed. " |
c3157bcd | 1096 | << "Try again with another '--vp 1' option." |
2cfb0e46 FCE |
1097 | << endl; |
1098 | ||
ce91eebd KS |
1099 | STAP_PROBE1(stap, pass1__end, &s); |
1100 | ||
49abf162 | 1101 | if (rc || s.last_pass == 1 || pending_interrupts) goto cleanup; |
f4b28491 | 1102 | |
5ee1c56b | 1103 | times (& tms_before); |
1d738eed | 1104 | gettimeofday (&tv_before, NULL); |
5ee1c56b | 1105 | |
2b066ec1 | 1106 | // PASS 2: ELABORATION |
e0b4e89d | 1107 | s.verbose = s.perpass_verbose[1]; |
ce91eebd | 1108 | STAP_PROBE1(stap, pass2__start, &s); |
0d49d7bc | 1109 | rc = semantic_pass (s); |
f4b28491 | 1110 | |
16442b90 | 1111 | if (s.listing_mode || (rc == 0 && s.last_pass == 2)) |
1b78aef5 | 1112 | printscript(s, cout); |
2b066ec1 | 1113 | |
5ee1c56b | 1114 | times (& tms_after); |
1d738eed FCE |
1115 | gettimeofday (&tv_after, NULL); |
1116 | ||
b0ee93c4 | 1117 | if (s.verbose) clog << "Pass 2: analyzed script: " |
0d49d7bc FCE |
1118 | << s.probes.size() << " probe(s), " |
1119 | << s.functions.size() << " function(s), " | |
b20febf3 | 1120 | << s.embeds.size() << " embed(s), " |
5ee1c56b FCE |
1121 | << s.globals.size() << " global(s) in " |
1122 | << TIMESPRINT | |
1123 | << endl; | |
0d49d7bc | 1124 | |
708ce1f3 | 1125 | if (rc && !s.listing_mode) |
377b8831 | 1126 | cerr << "Pass 2: analysis failed. " |
c3157bcd | 1127 | << "Try again with another '--vp 01' option." |
2cfb0e46 | 1128 | << endl; |
1b78aef5 DS |
1129 | // Generate hash. There isn't any point in generating the hash |
1130 | // if last_pass is 2, since we'll quit before using it. | |
1131 | else if (s.last_pass != 2 && s.use_cache) | |
1132 | { | |
1133 | ostringstream o; | |
1134 | unsigned saved_verbose; | |
1b78aef5 | 1135 | |
9abec538 FCE |
1136 | { |
1137 | // Make sure we're in verbose mode, so that printscript() | |
1138 | // will output function/probe bodies. | |
1139 | saved_verbose = s.verbose; | |
1140 | s.verbose = 3; | |
1141 | printscript(s, o); // Print script to 'o' | |
1142 | s.verbose = saved_verbose; | |
1143 | } | |
1b78aef5 DS |
1144 | |
1145 | // Generate hash | |
1146 | find_hash (s, o.str()); | |
1147 | ||
1148 | // See if we can use cached source/module. | |
1149 | if (get_from_cache(s)) | |
1150 | { | |
db3a383b JK |
1151 | // If our last pass isn't 5, we're done (since passes 3 and |
1152 | // 4 just generate what we just pulled out of the cache). | |
49abf162 | 1153 | if (s.last_pass < 5 || pending_interrupts) goto cleanup; |
1b78aef5 | 1154 | |
db3a383b JK |
1155 | // Short-circuit to pass 5. |
1156 | goto pass_5; | |
1b78aef5 DS |
1157 | } |
1158 | } | |
377b8831 | 1159 | |
2ed04863 WC |
1160 | /* Print out list of missing files */ |
1161 | missing_rpm_list_print(s); | |
1162 | ||
ce91eebd KS |
1163 | STAP_PROBE1(stap, pass2__end, &s); |
1164 | ||
16442b90 | 1165 | if (rc || s.listing_mode || s.last_pass == 2 || pending_interrupts) goto cleanup; |
f4b28491 | 1166 | |
2b066ec1 | 1167 | // PASS 3: TRANSLATION |
e0b4e89d | 1168 | s.verbose = s.perpass_verbose[2]; |
5ee1c56b | 1169 | times (& tms_before); |
1d738eed | 1170 | gettimeofday (&tv_before, NULL); |
ce91eebd | 1171 | STAP_PROBE1(stap, pass3__start, &s); |
1d738eed | 1172 | |
0d49d7bc | 1173 | rc = translate_pass (s); |
f4b28491 FCE |
1174 | |
1175 | if (rc == 0 && s.last_pass == 3) | |
1176 | { | |
1177 | ifstream i (s.translated_source.c_str()); | |
1178 | cout << i.rdbuf(); | |
1179 | } | |
0d49d7bc | 1180 | |
5ee1c56b | 1181 | times (& tms_after); |
1d738eed | 1182 | gettimeofday (&tv_after, NULL); |
5ee1c56b | 1183 | |
0d49d7bc FCE |
1184 | if (s.verbose) clog << "Pass 3: translated to C into \"" |
1185 | << s.translated_source | |
5ee1c56b FCE |
1186 | << "\" in " |
1187 | << TIMESPRINT | |
1188 | << endl; | |
0d49d7bc | 1189 | |
377b8831 | 1190 | if (rc) |
2cfb0e46 | 1191 | cerr << "Pass 3: translation failed. " |
c3157bcd | 1192 | << "Try again with another '--vp 001' option." |
2cfb0e46 | 1193 | << endl; |
377b8831 | 1194 | |
ce91eebd KS |
1195 | STAP_PROBE1(stap, pass3__end, &s); |
1196 | ||
49abf162 | 1197 | if (rc || s.last_pass == 3 || pending_interrupts) goto cleanup; |
d54d4661 | 1198 | |
f4b28491 | 1199 | // PASS 4: COMPILATION |
e0b4e89d | 1200 | s.verbose = s.perpass_verbose[3]; |
5ee1c56b | 1201 | times (& tms_before); |
1d738eed | 1202 | gettimeofday (&tv_before, NULL); |
ce91eebd | 1203 | STAP_PROBE1(stap, pass4__start, &s); |
0d49d7bc | 1204 | rc = compile_pass (s); |
9abec538 FCE |
1205 | |
1206 | if (rc == 0 && s.last_pass == 4) | |
422dc4e1 FCE |
1207 | { |
1208 | cout << ((s.hash_path == "") ? (s.module_name + string(".ko")) : s.hash_path); | |
1209 | cout << endl; | |
1210 | } | |
9abec538 | 1211 | |
5ee1c56b | 1212 | times (& tms_after); |
1d738eed | 1213 | gettimeofday (&tv_after, NULL); |
5ee1c56b FCE |
1214 | |
1215 | if (s.verbose) clog << "Pass 4: compiled C into \"" | |
1216 | << s.module_name << ".ko" | |
1217 | << "\" in " | |
1218 | << TIMESPRINT | |
1219 | << endl; | |
f4b28491 | 1220 | |
eaf134e7 FCE |
1221 | if (rc) |
1222 | cerr << "Pass 4: compilation failed. " | |
c3157bcd | 1223 | << "Try again with another '--vp 0001' option." |
2cfb0e46 | 1224 | << endl; |
fc52ef5b | 1225 | else |
1b78aef5 | 1226 | { |
06c7e057 | 1227 | // Update cache. Cache cleaning is kicked off at the end of this function. |
fc52ef5b | 1228 | if (s.use_cache) |
f4d5049b | 1229 | add_to_cache(s); |
fc52ef5b | 1230 | |
f4d5049b FCE |
1231 | // We may need to save the module in $CWD if the cache was |
1232 | // inaccessible for some reason. | |
1233 | if (! s.use_cache && s.last_pass == 4) | |
1234 | save_module = true; | |
1235 | ||
fc52ef5b | 1236 | // Copy module to the current directory. |
49abf162 | 1237 | if (save_module && !pending_interrupts) |
fc52ef5b DS |
1238 | { |
1239 | string module_src_path = s.tmpdir + "/" + s.module_name + ".ko"; | |
1240 | string module_dest_path = s.module_name + ".ko"; | |
1241 | ||
1242 | if (s.verbose > 1) | |
1243 | clog << "Copying " << module_src_path << " to " | |
1244 | << module_dest_path << endl; | |
1245 | if (copy_file(module_src_path.c_str(), module_dest_path.c_str()) != 0) | |
1246 | cerr << "Copy failed (\"" << module_src_path << "\" to \"" | |
1247 | << module_dest_path << "\"): " << strerror(errno) << endl; | |
98f552c2 DB |
1248 | |
1249 | #if HAVE_NSS | |
4c797c5e DB |
1250 | // Save the signature as well. |
1251 | assert (! s.cert_db_path.empty()); | |
1252 | module_src_path += ".sgn"; | |
c3a47b9b DB |
1253 | if (file_exists (module_src_path)) |
1254 | { | |
1255 | module_dest_path += ".sgn"; | |
1256 | ||
1257 | if (s.verbose > 1) | |
1258 | clog << "Copying " << module_src_path << " to " | |
1259 | << module_dest_path << endl; | |
1260 | if (copy_file(module_src_path.c_str(), module_dest_path.c_str()) != 0) | |
1261 | cerr << "Copy failed (\"" << module_src_path << "\" to \"" | |
1262 | << module_dest_path << "\"): " << strerror(errno) << endl; | |
1263 | } | |
98f552c2 | 1264 | #endif |
fc52ef5b | 1265 | } |
1b78aef5 | 1266 | } |
eaf134e7 | 1267 | |
ce91eebd KS |
1268 | STAP_PROBE1(stap, pass4__end, &s); |
1269 | ||
49abf162 | 1270 | if (rc || s.last_pass == 4 || pending_interrupts) goto cleanup; |
f4b28491 | 1271 | |
9abec538 | 1272 | |
0d49d7bc | 1273 | // PASS 5: RUN |
1b78aef5 | 1274 | pass_5: |
e0b4e89d | 1275 | s.verbose = s.perpass_verbose[4]; |
5ee1c56b | 1276 | times (& tms_before); |
1d738eed | 1277 | gettimeofday (&tv_before, NULL); |
03d569d3 FCE |
1278 | // NB: this message is a judgement call. The other passes don't emit |
1279 | // a "hello, I'm starting" message, but then the others aren't interactive | |
1280 | // and don't take an indefinite amount of time. | |
ce91eebd | 1281 | STAP_PROBE1(stap, pass5__start, &s); |
03d569d3 | 1282 | if (s.verbose) clog << "Pass 5: starting run." << endl; |
0d49d7bc | 1283 | rc = run_pass (s); |
5ee1c56b | 1284 | times (& tms_after); |
1d738eed | 1285 | gettimeofday (&tv_after, NULL); |
5ee1c56b FCE |
1286 | if (s.verbose) clog << "Pass 5: run completed in " |
1287 | << TIMESPRINT | |
1288 | << endl; | |
f4b28491 | 1289 | |
eaf134e7 FCE |
1290 | if (rc) |
1291 | cerr << "Pass 5: run failed. " | |
c3157bcd | 1292 | << "Try again with another '--vp 00001' option." |
2cfb0e46 | 1293 | << endl; |
eaf134e7 | 1294 | |
0d49d7bc | 1295 | // if (rc) goto cleanup; |
2b066ec1 | 1296 | |
ce91eebd KS |
1297 | STAP_PROBE1(stap, pass5__end, &s); |
1298 | ||
c31df222 | 1299 | // PASS 6: cleaning up |
0d49d7bc | 1300 | cleanup: |
c3a3c0c9 | 1301 | |
ce91eebd KS |
1302 | STAP_PROBE1(stap, pass6__start, &s); |
1303 | ||
c3a3c0c9 | 1304 | // update the database information |
49abf162 | 1305 | if (!rc && s.tapset_compile_coverage && !pending_interrupts) { |
1c0b94ef | 1306 | #ifdef HAVE_LIBSQLITE3 |
c3a3c0c9 | 1307 | update_coverage_db(s); |
1c0b94ef FCE |
1308 | #else |
1309 | cerr << "Coverage database not available without libsqlite3" << endl; | |
1310 | #endif | |
c3a3c0c9 WC |
1311 | } |
1312 | ||
f4b28491 FCE |
1313 | // Clean up temporary directory. Obviously, be careful with this. |
1314 | if (s.tmpdir == "") | |
1315 | ; // do nothing | |
1316 | else | |
1317 | { | |
1318 | if (s.keep_tmpdir) | |
0d49d7bc | 1319 | clog << "Keeping temporary directory \"" << s.tmpdir << "\"" << endl; |
f4b28491 FCE |
1320 | else |
1321 | { | |
3972b443 DS |
1322 | // Ignore signals while we're deleting the temporary directory. |
1323 | setup_signals (SIG_IGN); | |
1324 | ||
1325 | // Remove the temporary directory. | |
ce3187ac | 1326 | string cleanupcmd = "rm -rf "; |
f4b28491 | 1327 | cleanupcmd += s.tmpdir; |
b0ee93c4 | 1328 | if (s.verbose>1) clog << "Running " << cleanupcmd << endl; |
4cc40e82 | 1329 | int status = stap_system (cleanupcmd.c_str()); |
b0ee93c4 | 1330 | if (status != 0 && s.verbose>1) |
d54d4661 | 1331 | clog << "Cleanup command failed, status: " << status << endl; |
f4b28491 FCE |
1332 | } |
1333 | } | |
2b066ec1 | 1334 | |
ce91eebd KS |
1335 | STAP_PROBE1(stap, pass6__end, &s); |
1336 | ||
49abf162 | 1337 | return (rc||pending_interrupts) ? EXIT_FAILURE : EXIT_SUCCESS; |
2b066ec1 | 1338 | } |
73267b89 JS |
1339 | |
1340 | /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ |