]> sourceware.org Git - systemtap.git/blob - main.cxx
PR14929: tweak error->man page reference blurb, add a few starters
[systemtap.git] / main.cxx
1 // systemtap translator/driver
2 // Copyright (C) 2005-2011 Red Hat Inc.
3 // Copyright (C) 2005 IBM Corp.
4 // Copyright (C) 2006 Intel Corporation.
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.
10
11 #include "config.h"
12 #include "staptree.h"
13 #include "parse.h"
14 #include "elaborate.h"
15 #include "translate.h"
16 #include "buildrun.h"
17 #include "session.h"
18 #include "hash.h"
19 #include "cache.h"
20 #include "util.h"
21 #include "coveragedb.h"
22 #include "rpm_finder.h"
23 #include "task_finder.h"
24 #include "csclient.h"
25 #include "remote.h"
26 #include "tapsets.h"
27 #include "setupdwfl.h"
28
29 #include <libintl.h>
30 #include <locale.h>
31
32 #include "stap-probe.h"
33
34 #include <cstdlib>
35
36 extern "C" {
37 #include <glob.h>
38 #include <unistd.h>
39 #include <signal.h>
40 #include <sys/utsname.h>
41 #include <sys/times.h>
42 #include <sys/time.h>
43 #include <sys/stat.h>
44 #include <time.h>
45 #include <unistd.h>
46 #include <wordexp.h>
47 }
48
49 using namespace std;
50
51 static void
52 uniq_list(list<string>& l)
53 {
54 set<string> s;
55 list<string>::iterator i = l.begin();
56 while (i != l.end())
57 if (s.insert(*i).second)
58 ++i;
59 else
60 i = l.erase(i);
61 }
62
63 static void
64 printscript(systemtap_session& s, ostream& o)
65 {
66 if (s.listing_mode)
67 {
68 // We go through some heroic measures to produce clean output.
69 // Record the alias and probe pointer as <name, set<derived_probe *> >
70 map<string,set<derived_probe *> > probe_list;
71
72 // Pre-process the probe alias
73 for (unsigned i=0; i<s.probes.size(); i++)
74 {
75 assert_no_interrupts();
76
77 derived_probe* p = s.probes[i];
78 // NB: p->basest() is not so interesting;
79 // p->almost_basest() doesn't quite work, so ...
80 vector<probe*> chain;
81 p->collect_derivation_chain (chain);
82 probe* second = (chain.size()>1) ? chain[chain.size()-2] : chain[0];
83
84 if (s.verbose > 5) {
85 p->printsig(cerr); cerr << endl;
86 cerr << "chain[" << chain.size() << "]:" << endl;
87 for (unsigned j=0; j<chain.size(); j++)
88 {
89 cerr << " [" << j << "]: " << endl;
90 cerr << "\tlocations[" << chain[j]->locations.size() << "]:" << endl;
91 for (unsigned k=0; k<chain[j]->locations.size(); k++)
92 {
93 cerr << "\t [" << k << "]: ";
94 chain[j]->locations[k]->print(cerr);
95 cerr << endl;
96 }
97 const probe_alias *a = chain[j]->get_alias();
98 if (a)
99 {
100 cerr << "\taliases[" << a->alias_names.size() << "]:" << endl;
101 for (unsigned k=0; k<a->alias_names.size(); k++)
102 {
103 cerr << "\t [" << k << "]: ";
104 a->alias_names[k]->print(cerr);
105 cerr << endl;
106 }
107 }
108 }
109 }
110
111 stringstream tmps;
112 // XXX PR14297 make this more accurate wrt complex wildcard expansions
113 const probe_point *a = second->get_alias_loc();
114 if (a)
115 {
116 a->print(tmps);
117 }
118 else
119 {
120 assert (second->locations.size() >= 1);
121 second->locations[0]->print(tmps); // XXX: choosing only one location is less arbitrary here than in get_alias_loc(), but still ...
122 }
123 string pp = tmps.str();
124
125 // Now duplicate-eliminate. An alias may have expanded to
126 // several actual derived probe points, but we only want to
127 // print the alias head name once.
128 probe_list[pp].insert(p);
129 }
130
131 // print probe name and variables if there
132 for (map<string, set<derived_probe *> >::iterator it=probe_list.begin(); it!=probe_list.end(); ++it)
133 {
134 o << it->first; // probe name or alias
135
136 // Print the locals and arguments for -L mode only
137 if (s.listing_mode_vars)
138 {
139 map<string,unsigned> var_count; // format <"name:type",count>
140 map<string,unsigned> arg_count;
141 list<string> var_list;
142 list<string> arg_list;
143 // traverse set<derived_probe *> to collect all locals and arguments
144 for (set<derived_probe *>::iterator ix=it->second.begin(); ix!=it->second.end(); ++ix)
145 {
146 derived_probe* p = *ix;
147 // collect available locals of the probe
148 for (unsigned j=0; j<p->locals.size(); j++)
149 {
150 stringstream tmps;
151 vardecl* v = p->locals[j];
152 v->printsig (tmps);
153 var_count[tmps.str()]++;
154 var_list.push_back(tmps.str());
155 }
156 // collect arguments of the probe if there
157 list<string> arg_set;
158 p->getargs(arg_set);
159 for (list<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) {
160 arg_count[*ia]++;
161 arg_list.push_back(*ia);
162 }
163 }
164
165 uniq_list(arg_list);
166 uniq_list(var_list);
167
168 // print the set-intersection only
169 for (list<string>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir)
170 if (var_count.find(*ir)->second == it->second.size()) // print locals
171 o << " " << *ir;
172 for (list<string>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir)
173 if (arg_count.find(*ir)->second == it->second.size()) // print arguments
174 o << " " << *ir;
175 }
176 o << endl;
177 }
178 }
179 else
180 {
181 if (s.embeds.size() > 0)
182 o << _("# global embedded code") << endl;
183 for (unsigned i=0; i<s.embeds.size(); i++)
184 {
185 assert_no_interrupts();
186 embeddedcode* ec = s.embeds[i];
187 ec->print (o);
188 o << endl;
189 }
190
191 if (s.globals.size() > 0)
192 o << _("# globals") << endl;
193 for (unsigned i=0; i<s.globals.size(); i++)
194 {
195 assert_no_interrupts();
196 vardecl* v = s.globals[i];
197 v->printsig (o);
198 if (s.verbose && v->init)
199 {
200 o << " = ";
201 v->init->print(o);
202 }
203 o << endl;
204 }
205
206 if (s.functions.size() > 0)
207 o << _("# functions") << endl;
208 for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
209 {
210 assert_no_interrupts();
211 functiondecl* f = it->second;
212 f->printsig (o);
213 o << endl;
214 if (f->locals.size() > 0)
215 o << _(" # locals") << endl;
216 for (unsigned j=0; j<f->locals.size(); j++)
217 {
218 vardecl* v = f->locals[j];
219 o << " ";
220 v->printsig (o);
221 o << endl;
222 }
223 if (s.verbose)
224 {
225 f->body->print (o);
226 o << endl;
227 }
228 }
229
230 if (s.probes.size() > 0)
231 o << _("# probes") << endl;
232 for (unsigned i=0; i<s.probes.size(); i++)
233 {
234 assert_no_interrupts();
235 derived_probe* p = s.probes[i];
236 p->printsig (o);
237 o << endl;
238 if (p->locals.size() > 0)
239 o << _(" # locals") << endl;
240 for (unsigned j=0; j<p->locals.size(); j++)
241 {
242 vardecl* v = p->locals[j];
243 o << " ";
244 v->printsig (o);
245 o << endl;
246 }
247 if (s.verbose)
248 {
249 p->body->print (o);
250 o << endl;
251 }
252 }
253 }
254 }
255
256
257 int pending_interrupts;
258
259 extern "C"
260 void handle_interrupt (int sig)
261 {
262 // This might be nice, but we don't know our current verbosity...
263 // clog << _F("Received signal %d", sig) << endl << flush;
264 kill_stap_spawn(SIGTERM);
265
266 pending_interrupts ++;
267 // Absorb the first two signals. This used to be one, but when
268 // stap is run under sudo, and then interrupted, sudo relays a
269 // redundant copy of the signal to stap, leading to an unclean shutdown.
270 if (pending_interrupts > 2) // XXX: should be configurable? time-based?
271 {
272 char msg[] = "Too many interrupts received, exiting.\n";
273 int rc = write (2, msg, sizeof(msg)-1);
274 if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;}
275 _exit (1);
276 }
277 }
278
279
280 void
281 setup_signals (sighandler_t handler)
282 {
283 struct sigaction sa;
284
285 memset(&sa, 0, sizeof(sa));
286 sa.sa_handler = handler;
287 sigemptyset (&sa.sa_mask);
288 if (handler != SIG_IGN)
289 {
290 sigaddset (&sa.sa_mask, SIGHUP);
291 sigaddset (&sa.sa_mask, SIGPIPE);
292 sigaddset (&sa.sa_mask, SIGINT);
293 sigaddset (&sa.sa_mask, SIGTERM);
294 sigaddset (&sa.sa_mask, SIGXFSZ);
295 sigaddset (&sa.sa_mask, SIGXCPU);
296 }
297 sa.sa_flags = SA_RESTART;
298
299 sigaction (SIGHUP, &sa, NULL);
300 sigaction (SIGPIPE, &sa, NULL);
301 sigaction (SIGINT, &sa, NULL);
302 sigaction (SIGTERM, &sa, NULL);
303 sigaction (SIGXFSZ, &sa, NULL);
304 sigaction (SIGXCPU, &sa, NULL);
305 }
306
307
308 // Compilation passes 0 through 4
309 static int
310 passes_0_4 (systemtap_session &s)
311 {
312 int rc = 0;
313
314 // If we don't know the release, there's no hope either locally or on a server.
315 if (s.kernel_release.empty())
316 {
317 if (s.kernel_build_tree.empty())
318 cerr << _("ERROR: kernel release isn't specified") << endl;
319 else
320 cerr << _F("ERROR: kernel release isn't found in \"%s\"",
321 s.kernel_build_tree.c_str()) << endl;
322 return 1;
323 }
324
325 // Perform passes 0 through 4 using a compile server?
326 if (! s.specified_servers.empty ())
327 {
328 #if HAVE_NSS
329 compile_server_client client (s);
330 int rc = client.passes_0_4 ();
331 // Need to give a user a better diagnostic, if she didn't
332 // even ask for a server
333 if (rc && s.automatic_server_mode) {
334 cerr << _("Note: --use-server --unprivileged was selected because of stapusr membership.") << endl;
335 }
336 return rc;
337 #else
338 s.print_warning("Without NSS, using a compile-server is not supported by this version of systemtap");
339 // This cannot be an attempt to use a server after a local compile failed
340 // since --use-server-on-error is locked to 'no' if we don't have
341 // NSS.
342 assert (! s.try_server ());
343 #endif
344 }
345
346 // PASS 0: setting up
347 s.verbose = s.perpass_verbose[0];
348 PROBE1(stap, pass0__start, &s);
349
350 // For PR1477, we used to override $PATH and $LC_ALL and other stuff
351 // here. We seem to use complete pathnames in
352 // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
353 // it interferes with util.cxx:find_executable(), used for $PATH
354 // resolution.
355
356 s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
357
358 // Update various paths to include the sysroot, if provided.
359 if (!s.sysroot.empty())
360 {
361 if (s.update_release_sysroot && !s.sysroot.empty())
362 s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
363 debuginfo_path_insert_sysroot(s.sysroot);
364 }
365
366 // Now that no further changes to s.kernel_build_tree can occur, let's use it.
367 if ((rc = s.parse_kernel_config ()) != 0
368 || (rc = s.parse_kernel_exports ()) != 0
369 || (rc = s.parse_kernel_functions ()) != 0)
370 {
371 // Try again with a server
372 s.set_try_server ();
373 return rc;
374 }
375
376 // Create the name of the C source file within the temporary
377 // directory. Note the _src prefix, explained in
378 // buildrun.cxx:compile_pass()
379 s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c";
380
381 PROBE1(stap, pass0__end, &s);
382
383 struct tms tms_before;
384 times (& tms_before);
385 struct timeval tv_before;
386 gettimeofday (&tv_before, NULL);
387
388 // PASS 1a: PARSING LIBRARY SCRIPTS
389 PROBE1(stap, pass1a__start, &s);
390
391 // We need to handle the library scripts first because this pass
392 // gathers information on .stpm files that might be needed to
393 // parse the user script.
394
395 // We need to first ascertain the status of the user script, though.
396 struct stat user_file_stat;
397 int user_file_stat_rc = -1;
398
399 if (s.script_file == "-")
400 {
401 user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat);
402 }
403 else if (s.script_file != "")
404 {
405 user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
406 }
407 // otherwise, rc is 0 for a command line script
408
409 vector<string> version_suffixes;
410 if (s.runtime_mode == systemtap_session::kernel_runtime)
411 {
412 // Construct kernel-versioning search path
413 string kvr = s.kernel_release;
414
415 // add full kernel-version-release (2.6.NN-FOOBAR)
416 version_suffixes.push_back ("/" + kvr);
417
418 // add kernel version (2.6.NN)
419 if (kvr != s.kernel_base_release)
420 {
421 kvr = s.kernel_base_release;
422 version_suffixes.push_back ("/" + kvr);
423 }
424
425 // add kernel family (2.6)
426 string::size_type dot1_index = kvr.find ('.');
427 string::size_type dot2_index = kvr.rfind ('.');
428 while (dot2_index > dot1_index && dot2_index != string::npos)
429 {
430 kvr.erase(dot2_index);
431 version_suffixes.push_back ("/" + kvr);
432 dot2_index = kvr.rfind ('.');
433 }
434 }
435
436 // add empty string as last element
437 version_suffixes.push_back ("");
438
439 // Add arch variants of every path, just before each
440 const string& arch = s.architecture;
441 for (unsigned i=0; i<version_suffixes.size(); i+=2)
442 version_suffixes.insert(version_suffixes.begin() + i,
443 version_suffixes[i] + "/" + arch);
444
445 // Add runtime variants of every path, before everything else
446 string runtime_prefix;
447 if (s.runtime_mode == systemtap_session::kernel_runtime)
448 runtime_prefix = "/linux";
449 else if (s.runtime_mode == systemtap_session::dyninst_runtime)
450 runtime_prefix = "/dyninst";
451 if (!runtime_prefix.empty())
452 for (unsigned i=0; i<version_suffixes.size(); i+=2)
453 version_suffixes.insert(version_suffixes.begin() + i/2,
454 runtime_prefix + version_suffixes[i]);
455
456 // First, parse .stpm files on the include path. We need to have the
457 // resulting macro definitions available for parsing library files,
458 // but since .stpm files can consist only of '@define' constructs,
459 // we can parse each one without reference to the others.
460 set<pair<dev_t, ino_t> > seen_library_macro_files;
461
462 for (unsigned i=0; i<s.include_path.size(); i++)
463 {
464 // now iterate upon it
465 for (unsigned k=0; k<version_suffixes.size(); k++)
466 {
467 glob_t globbuf;
468 string dir = s.include_path[i] + version_suffixes[k] + "/*.stpm";
469 int r = glob(dir.c_str (), 0, NULL, & globbuf);
470 if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
471 rc ++;
472 // GLOB_NOMATCH is acceptable
473
474 unsigned prev_s_library_files = s.library_files.size();
475
476 for (unsigned j=0; j<globbuf.gl_pathc; j++)
477 {
478 assert_no_interrupts();
479
480 struct stat tapset_file_stat;
481 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
482 if (stat_rc == 0 && user_file_stat_rc == 0 &&
483 user_file_stat.st_dev == tapset_file_stat.st_dev &&
484 user_file_stat.st_ino == tapset_file_stat.st_ino)
485 {
486 cerr
487 << _F("usage error: macro tapset file '%s' cannot be run directly as a session script.",
488 globbuf.gl_pathv[j]) << endl;
489 rc ++;
490 }
491
492 // PR11949: duplicate-eliminate tapset files
493 if (stat_rc == 0)
494 {
495 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
496 tapset_file_stat.st_ino);
497 if (seen_library_macro_files.find(here)
498 != seen_library_macro_files.end())
499 continue;
500 seen_library_macro_files.insert (here);
501 }
502
503 // XXX: privilege only for /usr/share/systemtap?
504 stapfile* f = parse_library_macros (s, globbuf.gl_pathv[j]);
505 if (f == 0)
506 s.print_warning("macro tapset '" + string(globbuf.gl_pathv[j])
507 + "' has errors, and will be skipped."); // TODOXXX internationalization?
508 else
509 s.library_files.push_back (f);
510 }
511
512 unsigned next_s_library_files = s.library_files.size();
513 if (s.verbose>1 && globbuf.gl_pathc > 0)
514 //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
515 clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u",
516 dir.c_str(), globbuf.gl_pathc,
517 (next_s_library_files-prev_s_library_files)) << endl;
518
519 globfree (&globbuf);
520 }
521 }
522
523 // Next, gather and parse the library files.
524 set<pair<dev_t, ino_t> > seen_library_files;
525
526 for (unsigned i=0; i<s.include_path.size(); i++)
527 {
528 // now iterate upon it
529 for (unsigned k=0; k<version_suffixes.size(); k++)
530 {
531 glob_t globbuf;
532 string dir = s.include_path[i] + version_suffixes[k] + "/*.stp";
533 int r = glob(dir.c_str (), 0, NULL, & globbuf);
534 if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
535 rc ++;
536 // GLOB_NOMATCH is acceptable
537
538 unsigned prev_s_library_files = s.library_files.size();
539
540 for (unsigned j=0; j<globbuf.gl_pathc; j++)
541 {
542 assert_no_interrupts();
543
544 struct stat tapset_file_stat;
545 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
546 if (stat_rc == 0 && user_file_stat_rc == 0 &&
547 user_file_stat.st_dev == tapset_file_stat.st_dev &&
548 user_file_stat.st_ino == tapset_file_stat.st_ino)
549 {
550 cerr
551 << _F("usage error: tapset file '%s' cannot be run directly as a session script.",
552 globbuf.gl_pathv[j]) << endl;
553 rc ++;
554 }
555
556 // PR11949: duplicate-eliminate tapset files
557 if (stat_rc == 0)
558 {
559 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
560 tapset_file_stat.st_ino);
561 if (seen_library_files.find(here) != seen_library_files.end())
562 continue;
563 seen_library_files.insert (here);
564 }
565
566 // XXX: privilege only for /usr/share/systemtap?
567 stapfile* f = parse (s, globbuf.gl_pathv[j], true);
568 if (f == 0)
569 s.print_warning("tapset '" + string(globbuf.gl_pathv[j])
570 + "' has errors, and will be skipped."); // TODOXXX internationalization?
571 else
572 s.library_files.push_back (f);
573 }
574
575 unsigned next_s_library_files = s.library_files.size();
576 if (s.verbose>1 && globbuf.gl_pathc > 0)
577 //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
578 clog << _F("Searched: \"%s\", found: %zu, processed: %u",
579 dir.c_str(), globbuf.gl_pathc,
580 (next_s_library_files-prev_s_library_files)) << endl;
581
582 globfree (& globbuf);
583 }
584 }
585 if (s.num_errors())
586 rc ++;
587
588 // PASS 1b: PARSING USER SCRIPT
589 PROBE1(stap, pass1b__start, &s);
590
591 if (s.script_file == "-")
592 {
593 s.user_file = parse (s, cin, s.guru_mode);
594 }
595 else if (s.script_file != "")
596 {
597 s.user_file = parse (s, s.script_file, s.guru_mode);
598 }
599 else
600 {
601 istringstream ii (s.cmdline_script);
602 s.user_file = parse (s, ii, s.guru_mode);
603 }
604 if (s.user_file == 0)
605 {
606 // Syntax errors already printed.
607 rc ++;
608 }
609
610 if (rc == 0 && s.last_pass == 1)
611 {
612 cout << _("# parse tree dump") << endl;
613 s.user_file->print (cout);
614 cout << endl;
615 if (s.verbose)
616 for (unsigned i=0; i<s.library_files.size(); i++)
617 {
618 s.library_files[i]->print (cout);
619 cout << endl;
620 }
621 }
622
623 struct tms tms_after;
624 times (& tms_after);
625 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
626 struct timeval tv_after;
627 gettimeofday (&tv_after, NULL);
628
629 #define TIMESPRINT "in " << \
630 (tms_after.tms_cutime + tms_after.tms_utime \
631 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
632 << (tms_after.tms_cstime + tms_after.tms_stime \
633 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
634 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
635 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
636
637 // syntax errors, if any, are already printed
638 if (s.verbose)
639 {
640 // XXX also include a count of helper macro files loaded (.stpm)?
641 clog << "Pass 1: parsed user script and "
642 << s.library_files.size()
643 << " library script(s) "
644 << getmemusage()
645 << TIMESPRINT
646 << endl;
647 }
648
649 if (rc && !s.listing_mode)
650 cerr << _("Pass 1: parse failed. Try again with another '--vp 1' option.") << endl;
651 //cerr << "Pass 1: parse failed. "
652 // << "Try again with another '--vp 1' option."
653 // << endl;
654
655 PROBE1(stap, pass1__end, &s);
656
657 assert_no_interrupts();
658 if (rc || s.last_pass == 1) return rc;
659
660 times (& tms_before);
661 gettimeofday (&tv_before, NULL);
662
663 // PASS 2: ELABORATION
664 s.verbose = s.perpass_verbose[1];
665 PROBE1(stap, pass2__start, &s);
666 rc = semantic_pass (s);
667
668 // Dump a list of known probe point types, if requested.
669 if (s.dump_probe_types)
670 s.pattern_root->dump (s);
671
672 if (s.listing_mode || (rc == 0 && s.last_pass == 2))
673 printscript(s, cout);
674
675 times (& tms_after);
676 gettimeofday (&tv_after, NULL);
677
678 if (s.verbose) clog << "Pass 2: analyzed script: "
679 << s.probes.size() << " probe(s), "
680 << s.functions.size() << " function(s), "
681 << s.embeds.size() << " embed(s), "
682 << s.globals.size() << " global(s) "
683 << getmemusage()
684 << TIMESPRINT
685 << endl;
686
687 if (rc && !s.listing_mode && !s.try_server ())
688 cerr << _("Pass 2: analysis failed. Try again with another '--vp 01' option.") << endl;
689 //cerr << "Pass 2: analysis failed. "
690 // << "Try again with another '--vp 01' option."
691 // << endl;
692
693 /* Print out list of missing files. XXX should be "if (rc)" ? */
694 missing_rpm_list_print(s,"-debuginfo");
695
696 PROBE1(stap, pass2__end, &s);
697
698 assert_no_interrupts();
699 if (rc || s.listing_mode || s.last_pass == 2) return rc;
700
701 rc = prepare_translate_pass (s);
702 assert_no_interrupts();
703 if (rc) return rc;
704
705 // Generate hash. There isn't any point in generating the hash
706 // if last_pass is 2, since we'll quit before using it.
707 if (s.use_script_cache)
708 {
709 ostringstream o;
710 unsigned saved_verbose;
711
712 {
713 // Make sure we're in verbose mode, so that printscript()
714 // will output function/probe bodies.
715 saved_verbose = s.verbose;
716 s.verbose = 3;
717 printscript(s, o); // Print script to 'o'
718 s.verbose = saved_verbose;
719 }
720
721 // Generate hash
722 find_script_hash (s, o.str());
723
724 // See if we can use cached source/module.
725 if (get_script_from_cache(s))
726 {
727 // We may still need to build uprobes, if it's not also cached.
728 if (s.need_uprobes)
729 rc = uprobes_pass(s);
730
731 // If our last pass isn't 5, we're done (since passes 3 and
732 // 4 just generate what we just pulled out of the cache).
733 assert_no_interrupts();
734 if (rc || s.last_pass < 5) return rc;
735
736 // Short-circuit to pass 5.
737 return 0;
738 }
739 }
740
741 // PASS 3: TRANSLATION
742 s.verbose = s.perpass_verbose[2];
743 times (& tms_before);
744 gettimeofday (&tv_before, NULL);
745 PROBE1(stap, pass3__start, &s);
746
747 rc = translate_pass (s);
748 if (! rc && s.last_pass == 3)
749 {
750 ifstream i (s.translated_source.c_str());
751 cout << i.rdbuf();
752 }
753
754 times (& tms_after);
755 gettimeofday (&tv_after, NULL);
756
757 if (s.verbose)
758 clog << "Pass 3: translated to C into \""
759 << s.translated_source
760 << "\" "
761 << getmemusage()
762 << TIMESPRINT
763 << endl;
764
765 if (rc && ! s.try_server ())
766 cerr << _("Pass 3: translation failed. Try again with another '--vp 001' option.") << endl;
767 //cerr << "Pass 3: translation failed. "
768 // << "Try again with another '--vp 001' option."
769 // << endl;
770
771 PROBE1(stap, pass3__end, &s);
772
773 assert_no_interrupts();
774 if (rc || s.last_pass == 3) return rc;
775
776 // PASS 4: COMPILATION
777 s.verbose = s.perpass_verbose[3];
778 times (& tms_before);
779 gettimeofday (&tv_before, NULL);
780 PROBE1(stap, pass4__start, &s);
781
782 if (s.use_cache)
783 {
784 find_stapconf_hash(s);
785 get_stapconf_from_cache(s);
786 }
787 rc = compile_pass (s);
788 if (! rc && s.last_pass == 4)
789 {
790 cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path);
791 cout << endl;
792 }
793
794 times (& tms_after);
795 gettimeofday (&tv_after, NULL);
796
797 if (s.verbose) clog << "Pass 4: compiled C into \""
798 << s.module_filename()
799 << "\" "
800 << TIMESPRINT
801 << endl;
802
803 if (rc && ! s.try_server ())
804 cerr << _("Pass 4: compilation failed. Try again with another '--vp 0001' option.") << endl
805 << _("\tMore error information at man page error::pass4(7stap)") << endl;
806
807 else
808 {
809 // Update cache. Cache cleaning is kicked off at the beginning of this function.
810 if (s.use_script_cache)
811 add_script_to_cache(s);
812 if (s.use_cache && !s.runtime_usermode_p())
813 add_stapconf_to_cache(s);
814
815 // We may need to save the module in $CWD if the cache was
816 // inaccessible for some reason.
817 if (! s.use_script_cache && s.last_pass == 4)
818 s.save_module = true;
819
820 // Copy module to the current directory.
821 if (s.save_module && !pending_interrupts)
822 {
823 string module_src_path = s.tmpdir + "/" + s.module_filename();
824 string module_dest_path = s.module_filename();
825 copy_file(module_src_path, module_dest_path, s.verbose > 1);
826 }
827 }
828
829 PROBE1(stap, pass4__end, &s);
830
831 return rc;
832 }
833
834 static int
835 pass_5 (systemtap_session &s, vector<remote*> targets)
836 {
837 // PASS 5: RUN
838 s.verbose = s.perpass_verbose[4];
839 struct tms tms_before;
840 times (& tms_before);
841 struct timeval tv_before;
842 gettimeofday (&tv_before, NULL);
843 // NB: this message is a judgement call. The other passes don't emit
844 // a "hello, I'm starting" message, but then the others aren't interactive
845 // and don't take an indefinite amount of time.
846 PROBE1(stap, pass5__start, &s);
847 if (s.verbose) clog << _("Pass 5: starting run.") << endl;
848 int rc = remote::run(targets);
849 struct tms tms_after;
850 times (& tms_after);
851 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
852 struct timeval tv_after;
853 gettimeofday (&tv_after, NULL);
854 if (s.verbose) clog << "Pass 5: run completed "
855 << TIMESPRINT
856 << endl;
857
858 if (rc)
859 cerr << _("Pass 5: run failed. Try again with another '--vp 00001' option.") << endl;
860 //cerr << "Pass 5: run failed. "
861 // << "Try again with another '--vp 00001' option."
862 // << endl;
863 else
864 // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below.
865 pending_interrupts = 0;
866
867 PROBE1(stap, pass5__end, &s);
868
869 return rc;
870 }
871
872 static void
873 cleanup (systemtap_session &s, int rc)
874 {
875 // PASS 6: cleaning up
876 PROBE1(stap, pass6__start, &s);
877
878 for (systemtap_session::session_map_t::iterator it = s.subsessions.begin();
879 it != s.subsessions.end(); ++it)
880 cleanup (*it->second, rc);
881
882 // update the database information
883 if (!rc && s.tapset_compile_coverage && !pending_interrupts) {
884 #ifdef HAVE_LIBSQLITE3
885 update_coverage_db(s);
886 #else
887 cerr << _("Coverage database not available without libsqlite3") << endl;
888 #endif
889 }
890
891 PROBE1(stap, pass6__end, &s);
892 }
893
894 static int
895 passes_0_4_again_with_server (systemtap_session &s)
896 {
897 // Not a server and not already using a server.
898 assert (! s.client_options);
899 assert (s.specified_servers.empty ());
900
901 // Specify default server(s).
902 s.specified_servers.push_back ("");
903
904 // Reset the previous temporary directory and start fresh
905 s.reset_tmp_dir();
906
907 // Try to compile again, using the server
908 clog << _("Attempting compilation using a compile server")
909 << endl;
910
911 int rc = passes_0_4 (s);
912 return rc;
913 }
914
915 int
916 main (int argc, char * const argv [])
917 {
918 // Initialize defaults.
919 try {
920 systemtap_session s;
921
922 setlocale (LC_ALL, "");
923 bindtextdomain (PACKAGE, LOCALEDIR);
924 textdomain (PACKAGE);
925
926 // Set up our handler to catch routine signals, to allow clean
927 // and reasonably timely exit.
928 setup_signals(&handle_interrupt);
929
930 // PR13520: Parse $SYSTEMTAP_DIR/rc for extra options
931 string rc_file = s.data_path + "/rc";
932 ifstream rcf (rc_file.c_str());
933 string rcline;
934 wordexp_t words;
935 memset (& words, 0, sizeof(words));
936 int rc = 0;
937 int linecount = 0;
938 while (getline (rcf, rcline))
939 {
940 rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF|
941 (linecount > 0 ? WRDE_APPEND : 0));
942 // NB: WRDE_APPEND automagically reallocates words.* as more options are added.
943 linecount ++;
944 if (rc) break;
945 }
946 int extended_argc = words.we_wordc + argc;
947 char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*));
948 if (rc || !extended_argv)
949 {
950 clog << _F("Error processing extra options in %s", rc_file.c_str());
951 return EXIT_FAILURE;
952 }
953 // Copy over the arguments *by reference*, first the ones from the rc file.
954 char **p = & extended_argv[0];
955 *p++ = argv[0];
956 for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i];
957 for (int j=1; j<argc; j++) *p++ = argv[j];
958 *p++ = NULL;
959
960 // Process the command line.
961 rc = s.parse_cmdline (extended_argc, extended_argv);
962 if (rc != 0)
963 return rc;
964
965 if (words.we_wordc > 0 && s.verbose > 1)
966 clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc);
967
968 // Check for options conflicts. Exits if errors are detected.
969 s.check_options (extended_argc, extended_argv);
970
971 // We don't need these strings any more.
972 wordfree (& words);
973 free (extended_argv);
974
975 // arguments parsed; get down to business
976 if (s.verbose > 1)
977 s.version ();
978
979 // Need to send the verbose message here, rather than in the session ctor, since
980 // we didn't know if verbose was set.
981 if (rc == 0 && s.verbose>1)
982 clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
983
984 // Prepare connections for each specified remote target.
985 vector<remote*> targets;
986 bool fake_remote=false;
987 if (s.remote_uris.empty())
988 {
989 fake_remote=true;
990 s.remote_uris.push_back("direct:");
991 }
992 for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i)
993 {
994 // PR13354: pass remote id#/url only in non --remote=HOST cases
995 remote *target = remote::create(s, s.remote_uris[i],
996 fake_remote ? -1 : (int)i);
997 if (target)
998 targets.push_back(target);
999 else
1000 rc = 1;
1001 }
1002
1003 // Discover and loop over each unique session created by the remote targets.
1004 set<systemtap_session*> sessions;
1005 for (unsigned i = 0; i < targets.size(); ++i)
1006 sessions.insert(targets[i]->get_session());
1007 for (set<systemtap_session*>::iterator it = sessions.begin();
1008 rc == 0 && !pending_interrupts && it != sessions.end(); ++it)
1009 {
1010 systemtap_session& ss = **it;
1011 if (ss.verbose > 1)
1012 clog << _F("Session arch: %s release: %s",
1013 ss.architecture.c_str(), ss.kernel_release.c_str()) << endl;
1014
1015 #if HAVE_NSS
1016 // If requested, query server status. This is independent of other tasks.
1017 query_server_status (ss);
1018
1019 // If requested, manage trust of servers. This is independent of other tasks.
1020 manage_server_trust (ss);
1021 #endif
1022
1023 // Run the passes only if a script has been specified. The requirement for
1024 // a script has already been checked in systemtap_session::check_options.
1025 // Run the passes also if a dump of supported probe types has been requested via a server.
1026 if (ss.have_script || (ss.dump_probe_types && ! s.specified_servers.empty ()))
1027 {
1028 // Run passes 0-4 for each unique session,
1029 // either locally or using a compile-server.
1030 ss.init_try_server ();
1031 if ((rc = passes_0_4 (ss)))
1032 {
1033 // Compilation failed.
1034 // Try again using a server if appropriate.
1035 if (ss.try_server ())
1036 rc = passes_0_4_again_with_server (ss);
1037 }
1038 }
1039 else if (ss.dump_probe_types)
1040 {
1041 // Dump a list of known probe point types, if requested.
1042 register_standard_tapsets(ss);
1043 ss.pattern_root->dump (ss);
1044 }
1045 }
1046
1047 // Run pass 5, if requested
1048 if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts)
1049 rc = pass_5 (s, targets);
1050
1051 // Pass 6. Cleanup
1052 for (unsigned i = 0; i < targets.size(); ++i)
1053 delete targets[i];
1054 cleanup (s, rc);
1055
1056 assert_no_interrupts();
1057 return (rc) ? EXIT_FAILURE : EXIT_SUCCESS;
1058 }
1059 catch (const interrupt_exception& e) {
1060 // User entered ctrl-c, exit quietly.
1061 return EXIT_FAILURE;
1062 }
1063 catch (const exit_exception& e) {
1064 // Exiting for any quiet reason.
1065 return e.rc;
1066 }
1067 catch (const runtime_error &e) {
1068 // Some other uncaught runtime_error exception.
1069 cerr << e.what() << endl;
1070 return EXIT_FAILURE;
1071 }
1072 catch (...) {
1073 // Catch all other unknown exceptions.
1074 cerr << _("ERROR: caught unknown exception!") << endl;
1075 return EXIT_FAILURE;
1076 }
1077 }
1078
1079 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.11043 seconds and 6 git commands to generate.