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