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