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