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