]> sourceware.org Git - systemtap.git/blame - main.cxx
Use a proper session copier when cloning
[systemtap.git] / main.cxx
CommitLineData
f4b28491 1// systemtap translator/driver
44edbcd6 2// Copyright (C) 2005-2011 Red Hat Inc.
f12b2552 3// Copyright (C) 2005 IBM Corp.
77a5c1f9 4// Copyright (C) 2006 Intel Corporation.
69c68955
FCE
5//
6// This file is part of systemtap, and is free software. You can
7// redistribute it and/or modify it under the terms of the GNU General
8// Public License (GPL); either version 2, or (at your option) any
9// later version.
2b066ec1
FCE
10
11#include "config.h"
85007c04
DB
12#include "staptree.h"
13#include "parse.h"
14#include "elaborate.h"
15#include "translate.h"
16#include "buildrun.h"
dc38c0ae 17#include "session.h"
85007c04
DB
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"
daa75206 25#include "remote.h"
85007c04 26
79bc39ab
LB
27#include <libintl.h>
28#include <locale.h>
29#include "autosprintf.h"
30
0f5d597d 31#include "stap-probe.h"
aa4d21c0 32
24cb178f 33#include <cstdlib>
73267b89 34
85007c04
DB
35extern "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}
46
47using namespace std;
79bc39ab 48using namespace gnu;
85007c04 49
40a50254
JS
50static void
51uniq_list(list<string>& l)
e2012a7a 52{
40a50254
JS
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);
85007c04 60}
2dce8c42 61
85007c04
DB
62static void
63printscript(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;
6e683641 70
85007c04
DB
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
7977a734 83 if (s.verbose > 5) {
85007c04
DB
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 }
7977a734 108 }
85007c04
DB
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
2dce8c42 179 {
85007c04 180 if (s.embeds.size() > 0)
79bc39ab 181 o << _("# global embedded code") << endl;
85007c04
DB
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 }
2dce8c42 189
85007c04 190 if (s.globals.size() > 0)
79bc39ab 191 o << _("# globals") << endl;
85007c04
DB
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)
79bc39ab 206 o << _("# functions") << endl;
85007c04
DB
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)
79bc39ab 214 o << _(" # locals") << endl;
85007c04
DB
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)
79bc39ab 230 o << _("# probes") << endl;
85007c04
DB
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)
79bc39ab 238 o << _(" # locals") << endl;
85007c04
DB
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 }
2dce8c42 252 }
85007c04 253}
e2012a7a 254
e2012a7a 255
85007c04
DB
256int pending_interrupts;
257
258extern "C"
259void handle_interrupt (int sig)
260{
261 kill_stap_spawn(sig);
262 pending_interrupts ++;
263 if (pending_interrupts > 1) // XXX: should be configurable? time-based?
264 {
265 char msg[] = "Too many interrupts received, exiting.\n";
266 int rc = write (2, msg, sizeof(msg)-1);
267 if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;}
268 _exit (1);
269 }
270}
271
272
273void
274setup_signals (sighandler_t handler)
275{
276 struct sigaction sa;
277
278 sa.sa_handler = handler;
279 sigemptyset (&sa.sa_mask);
280 if (handler != SIG_IGN)
281 {
282 sigaddset (&sa.sa_mask, SIGHUP);
283 sigaddset (&sa.sa_mask, SIGPIPE);
284 sigaddset (&sa.sa_mask, SIGINT);
285 sigaddset (&sa.sa_mask, SIGTERM);
286 }
287 sa.sa_flags = SA_RESTART;
288
289 sigaction (SIGHUP, &sa, NULL);
290 sigaction (SIGPIPE, &sa, NULL);
291 sigaction (SIGINT, &sa, NULL);
292 sigaction (SIGTERM, &sa, NULL);
e2012a7a 293}
6e683641 294
85007c04
DB
295int parse_kernel_config (systemtap_session &s)
296{
297 // PR10702: pull config options
298 string kernel_config_file = s.kernel_build_tree + "/.config";
299 struct stat st;
300 int rc = stat(kernel_config_file.c_str(), &st);
301 if (rc != 0)
76c87907 302 {
c578b859
LB
303 clog << autosprintf(_("Checking \"%s\" failed with error: %s"),
304 kernel_config_file.c_str(), strerror(errno)) << endl;
79bc39ab 305 //clog << "Checking \"" << kernel_config_file << "\" failed: " << strerror(errno) << endl;
76c87907
LB
306 find_devel_rpms(s, s.kernel_build_tree.c_str());
307 missing_rpm_list_print(s,"-devel");
85007c04
DB
308 return rc;
309 }
6861e056 310
85007c04
DB
311 ifstream kcf (kernel_config_file.c_str());
312 string line;
313 while (getline (kcf, line))
314 {
315 if (!startswith(line, "CONFIG_")) continue;
316 size_t off = line.find('=');
317 if (off == string::npos) continue;
318 string key = line.substr(0, off);
319 string value = line.substr(off+1, string::npos);
320 s.kernel_config[key] = value;
321 }
322 if (s.verbose > 2)
c578b859 323 clog << autosprintf( _("Parsed kernel \"%s\", "), kernel_config_file.c_str())
79bc39ab 324 << autosprintf(ngettext("containing %zu tuple", "containing %zu tuples",
c578b859 325 s.kernel_config.size()), s.kernel_config.size()) << endl;
79bc39ab 326 //clog << "Parsed kernel \"" << kernel_config_file << "\", number of tuples: " << s.kernel_config.size() << endl;
85007c04
DB
327
328 kcf.close();
329 return 0;
330}
331
332
333int parse_kernel_exports (systemtap_session &s)
334{
335 string kernel_exports_file = s.kernel_build_tree + "/Module.symvers";
336 struct stat st;
337 int rc = stat(kernel_exports_file.c_str(), &st);
338 if (rc != 0)
339 {
c578b859
LB
340 clog << autosprintf( _("Checking \"%s\" failed with error: %s"),
341 kernel_exports_file.c_str(), strerror(errno)) << endl
79bc39ab
LB
342 //clog << "Checking \"" << kernel_exports_file << "\" failed: " << strerror(errno) << endl
343 << _("Ensure kernel development headers & makefiles are installed.") << endl;
85007c04
DB
344 return rc;
345 }
346
347 ifstream kef (kernel_exports_file.c_str());
348 string line;
349 while (getline (kef, line))
350 {
351 vector<string> tokens;
352 tokenize (line, tokens, "\t");
353 if (tokens.size() == 4 &&
354 tokens[2] == "vmlinux" &&
355 tokens[3].substr(0,13) == string("EXPORT_SYMBOL"))
356 s.kernel_exports.insert (tokens[1]);
357 }
358 if (s.verbose > 2)
79bc39ab 359 clog << autosprintf(_("Parsed kernel \"%s\", "),kernel_exports_file.c_str())
c578b859
LB
360 << autosprintf(ngettext("which contained one vmlinux export", "which contained %zu vmlinux exports",
361 s.kernel_exports.size()), s.kernel_exports.size()) << endl;
79bc39ab 362 //clog << "Parsed kernel \"" << kernel_exports_file << "\", number of vmlinux exports: " << s.kernel_exports.size() << endl;
85007c04
DB
363
364 kef.close();
365 return 0;
366}
367
368
369static void
370create_temp_dir (systemtap_session &s)
371{
372 // Create a temporary directory to build within.
373 // Be careful with this, as "tmpdir" is "rm -rf"'d at the end.
374 const char* tmpdir_env = getenv("TMPDIR");
375 if (! tmpdir_env)
376 tmpdir_env = "/tmp";
377
378 string stapdir = "/stapXXXXXX";
379 string tmpdirt = tmpdir_env + stapdir;
380 mode_t mask = umask(0);
381 const char *tmpdir_name = mkdtemp((char *)tmpdirt.c_str());
382 umask(mask);
383 if (! tmpdir_name)
384 {
385 const char* e = strerror (errno);
79bc39ab 386 //we can't make the directory due to the error
8ca9631d 387 cerr << autosprintf(_("ERROR: cannot create temporary directory (\" %s \"): %s"), tmpdirt.c_str(), e) << endl;
79bc39ab 388 //cerr << "ERROR: cannot create temporary directory (\"" << tmpdirt << "\"): " << e << endl;
85007c04
DB
389 exit (1); // die
390 }
391 else
392 s.tmpdir = tmpdir_name;
393
394 if (s.verbose>1)
3e1ec884 395 clog << autosprintf(_("Created temporary directory \"%s\""), s.tmpdir.c_str()) << endl;
79bc39ab 396 //clog << "Created temporary directory \"" << s.tmpdir << "\"" << endl;
85007c04
DB
397}
398
399static void
400remove_temp_dir (systemtap_session &s)
401{
402 if (s.tmpdir != "")
403 {
404 if (s.keep_tmpdir)
405 // NB: the format of this message needs to match the expectations
406 // of stap-server-connect.c.
3e1ec884 407 clog << autosprintf(_("Keeping temporary directory \"%s\""), s.tmpdir.c_str()) << endl;
79bc39ab 408 //clog << "Keeping temporary directory \"" << s.tmpdir << "\"" << endl;
85007c04
DB
409 else
410 {
411 // Ignore signals while we're deleting the temporary directory.
412 setup_signals (SIG_IGN);
413
414 // Remove the temporary directory.
415 string cleanupcmd = "rm -rf ";
416 cleanupcmd += s.tmpdir;
417
418 (void) stap_system (s.verbose, cleanupcmd);
419 }
420 }
421}
422
44edbcd6 423// Compilation passes 0 through 4
85007c04
DB
424static int
425passes_0_4 (systemtap_session &s)
426{
427 int rc = 0;
daa75206 428
85007c04
DB
429 // Create a temporary directory to build within.
430 // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end.
431 create_temp_dir (s);
432
433 // Perform passes 0 through 4 using a compile server?
434 if (! s.specified_servers.empty ())
435 {
0d1534e8 436#if HAVE_NSS
85007c04
DB
437 compile_server_client client (s);
438 return client.passes_0_4 ();
0d1534e8 439#else
79bc39ab 440 cerr << _("WARNING: Without NSS, using a compile-server is not supported by this version of systemtap") << endl;
3e1ec884
DB
441 // This cannot be an attempt to use a server after a local compile failed
442 // since --use-server-on-error is locked to 'no' if we don't have
443 // NSS.
444 assert (! s.try_server ());
0d1534e8 445#endif
85007c04
DB
446 }
447
448 // PASS 0: setting up
449 s.verbose = s.perpass_verbose[0];
0f5d597d 450 PROBE1(stap, pass0__start, &s);
85007c04 451
85007c04
DB
452 // For PR1477, we used to override $PATH and $LC_ALL and other stuff
453 // here. We seem to use complete pathnames in
454 // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
455 // it interferes with util.cxx:find_executable(), used for $PATH
456 // resolution.
457
458 s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
459
460 // arguments parsed; get down to business
461 if (s.verbose > 1)
462 {
463 s.version ();
79bc39ab
LB
464 clog << autosprintf( _("Session arch: %s release: %s"), s.architecture.c_str(), s.kernel_release.c_str()) << endl;
465 //clog << "Session arch: " << s.architecture
466 //<< " release: " << s.kernel_release
467 //<< endl;
85007c04
DB
468 }
469
470 // Now that no further changes to s.kernel_build_tree can occur, let's use it.
44edbcd6
JS
471 if ((rc = parse_kernel_config (s)) != 0)
472 {
473 // Try again with a server
474 s.set_try_server ();
475 return rc;
476 }
85007c04 477
44edbcd6
JS
478 if ((rc = parse_kernel_exports (s)) != 0)
479 {
480 // Try again with a server
481 s.set_try_server ();
482 return rc;
483 }
85007c04
DB
484
485 // Create the name of the C source file within the temporary
486 // directory.
487 s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
488
489 // Set up our handler to catch routine signals, to allow clean
490 // and reasonably timely exit.
491 setup_signals(&handle_interrupt);
492
0f5d597d 493 PROBE1(stap, pass0__end, &s);
85007c04
DB
494
495 struct tms tms_before;
496 times (& tms_before);
497 struct timeval tv_before;
498 gettimeofday (&tv_before, NULL);
499
500 // PASS 1a: PARSING USER SCRIPT
0f5d597d 501 PROBE1(stap, pass1a__start, &s);
85007c04
DB
502
503 struct stat user_file_stat;
504 int user_file_stat_rc = -1;
505
506 if (s.script_file == "-")
507 {
508 s.user_file = parse (s, cin, s.guru_mode);
509 user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat);
510 }
511 else if (s.script_file != "")
512 {
513 s.user_file = parse (s, s.script_file, s.guru_mode);
514 user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
515 }
516 else
517 {
518 istringstream ii (s.cmdline_script);
519 s.user_file = parse (s, ii, s.guru_mode);
520 }
521 if (s.user_file == 0)
44edbcd6
JS
522 {
523 // Syntax errors already printed.
524 rc ++;
44edbcd6 525 }
85007c04
DB
526
527 // Construct arch / kernel-versioning search path
528 vector<string> version_suffixes;
529 string kvr = s.kernel_release;
530 const string& arch = s.architecture;
531 // add full kernel-version-release (2.6.NN-FOOBAR) + arch
532 version_suffixes.push_back ("/" + kvr + "/" + arch);
533 version_suffixes.push_back ("/" + kvr);
534 // add kernel version (2.6.NN) + arch
535 if (kvr != s.kernel_base_release) {
536 kvr = s.kernel_base_release;
537 version_suffixes.push_back ("/" + kvr + "/" + arch);
538 version_suffixes.push_back ("/" + kvr);
539 }
540 // add kernel family (2.6) + arch
541 string::size_type dot1_index = kvr.find ('.');
542 string::size_type dot2_index = kvr.rfind ('.');
543 while (dot2_index > dot1_index && dot2_index != string::npos) {
544 kvr.erase(dot2_index);
545 version_suffixes.push_back ("/" + kvr + "/" + arch);
546 version_suffixes.push_back ("/" + kvr);
547 dot2_index = kvr.rfind ('.');
548 }
549 // add architecture search path
550 version_suffixes.push_back("/" + arch);
551 // add empty string as last element
552 version_suffixes.push_back ("");
553
554 // PASS 1b: PARSING LIBRARY SCRIPTS
0f5d597d 555 PROBE1(stap, pass1b__start, &s);
85007c04 556
ad7c8e43
FCE
557 set<pair<dev_t, ino_t> > seen_library_files;
558
85007c04
DB
559 for (unsigned i=0; i<s.include_path.size(); i++)
560 {
561 // now iterate upon it
562 for (unsigned k=0; k<version_suffixes.size(); k++)
563 {
564 glob_t globbuf;
565 string dir = s.include_path[i] + version_suffixes[k] + "/*.stp";
566 int r = glob(dir.c_str (), 0, NULL, & globbuf);
567 if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
3e1ec884 568 rc ++;
44edbcd6 569 // GLOB_NOMATCH is acceptable
85007c04 570
ad7c8e43 571 unsigned prev_s_library_files = s.library_files.size();
85007c04
DB
572
573 for (unsigned j=0; j<globbuf.gl_pathc; j++)
574 {
575 if (pending_interrupts)
576 break;
577
85007c04
DB
578 struct stat tapset_file_stat;
579 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
580 if (stat_rc == 0 && user_file_stat_rc == 0 &&
581 user_file_stat.st_dev == tapset_file_stat.st_dev &&
582 user_file_stat.st_ino == tapset_file_stat.st_ino)
583 {
79bc39ab
LB
584 cerr
585 << autosprintf(_("usage error: tapset file '%s' cannot be run directly as a session script."),
586 globbuf.gl_pathv[j]) << endl;
587 //cerr << "usage error: tapset file '" << globbuf.gl_pathv[j]
588 // << "' cannot be run directly as a session script." << endl;
85007c04
DB
589 rc ++;
590 }
591
ad7c8e43
FCE
592 // PR11949: duplicate-eliminate tapset files
593 if (stat_rc == 0)
594 {
595 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
596 tapset_file_stat.st_ino);
597 if (seen_library_files.find(here) != seen_library_files.end())
598 continue;
599 seen_library_files.insert (here);
600 }
601
602 // XXX: privilege only for /usr/share/systemtap?
603 stapfile* f = parse (s, globbuf.gl_pathv[j], true);
604 if (f == 0 && !s.suppress_warnings)
605 s.print_warning("tapset '" + string(globbuf.gl_pathv[j])
606 + "' has errors, and will be skipped.");
607 else
608 s.library_files.push_back (f);
85007c04
DB
609 }
610
ad7c8e43
FCE
611 unsigned next_s_library_files = s.library_files.size();
612 if (s.verbose>1 && globbuf.gl_pathc > 0)
79bc39ab
LB
613 // search a directory, report a number of found with number of processed
614 clog << autosprintf(_("Searched: \" %s \", found: %zu, processed: %u"),
c578b859 615 dir.c_str(), globbuf.gl_pathc, (next_s_library_files-prev_s_library_files)) << endl;
79bc39ab
LB
616 //clog << "Searched \"" << dir << "\","
617 // << " found " << globbuf.gl_pathc
618 // << " processed " << (next_s_library_files-prev_s_library_files) << endl;
ad7c8e43 619
85007c04
DB
620 globfree (& globbuf);
621 }
622 }
623 if (s.num_errors())
3e1ec884 624 rc ++;
85007c04
DB
625
626 if (rc == 0 && s.last_pass == 1)
627 {
79bc39ab 628 cout << _("# parse tree dump") << endl;
85007c04
DB
629 s.user_file->print (cout);
630 cout << endl;
631 if (s.verbose)
632 for (unsigned i=0; i<s.library_files.size(); i++)
633 {
634 s.library_files[i]->print (cout);
635 cout << endl;
636 }
637 }
638
639 struct tms tms_after;
640 times (& tms_after);
641 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
642 struct timeval tv_after;
643 gettimeofday (&tv_after, NULL);
644
645#define TIMESPRINT "in " << \
646 (tms_after.tms_cutime + tms_after.tms_utime \
647 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
648 << (tms_after.tms_cstime + tms_after.tms_stime \
649 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
650 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
651 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
652
653 // syntax errors, if any, are already printed
654 if (s.verbose)
655 {
656 clog << "Pass 1: parsed user script and "
657 << s.library_files.size()
658 << " library script(s) "
659 << getmemusage()
660 << TIMESPRINT
661 << endl;
662 }
663
664 if (rc && !s.listing_mode)
79bc39ab
LB
665 cerr << _("Pass 1: parse failed. Try again with another '--vp 1' option.") << endl;
666 //cerr << "Pass 1: parse failed. "
667 // << "Try again with another '--vp 1' option."
668 // << endl;
85007c04 669
0f5d597d 670 PROBE1(stap, pass1__end, &s);
85007c04
DB
671
672 if (rc || s.last_pass == 1 || pending_interrupts) return rc;
673
674 times (& tms_before);
675 gettimeofday (&tv_before, NULL);
676
677 // PASS 2: ELABORATION
678 s.verbose = s.perpass_verbose[1];
0f5d597d 679 PROBE1(stap, pass2__start, &s);
85007c04
DB
680 rc = semantic_pass (s);
681
682 if (s.listing_mode || (rc == 0 && s.last_pass == 2))
683 printscript(s, cout);
684
685 times (& tms_after);
686 gettimeofday (&tv_after, NULL);
687
688 if (s.verbose) clog << "Pass 2: analyzed script: "
689 << s.probes.size() << " probe(s), "
690 << s.functions.size() << " function(s), "
691 << s.embeds.size() << " embed(s), "
692 << s.globals.size() << " global(s) "
693 << getmemusage()
694 << TIMESPRINT
695 << endl;
696
44edbcd6 697 if (rc && !s.listing_mode && !s.try_server ())
3e1ec884 698 cerr << _("Pass 2: analysis failed. Try again with another '--vp 01' option.") << endl;
79bc39ab
LB
699 //cerr << "Pass 2: analysis failed. "
700 // << "Try again with another '--vp 01' option."
701 // << endl;
85007c04
DB
702
703 /* Print out list of missing files. XXX should be "if (rc)" ? */
76c87907 704 missing_rpm_list_print(s,"-debuginfo");
85007c04 705
0f5d597d 706 PROBE1(stap, pass2__end, &s);
85007c04
DB
707
708 if (rc || s.listing_mode || s.last_pass == 2 || pending_interrupts) return rc;
709
d13bcfd8
JS
710 rc = prepare_translate_pass (s);
711 if (rc || pending_interrupts) return rc;
712
85007c04
DB
713 // Generate hash. There isn't any point in generating the hash
714 // if last_pass is 2, since we'll quit before using it.
715 if (s.use_script_cache)
716 {
717 ostringstream o;
718 unsigned saved_verbose;
719
720 {
721 // Make sure we're in verbose mode, so that printscript()
722 // will output function/probe bodies.
723 saved_verbose = s.verbose;
724 s.verbose = 3;
725 printscript(s, o); // Print script to 'o'
726 s.verbose = saved_verbose;
727 }
728
729 // Generate hash
730 find_script_hash (s, o.str());
731
732 // See if we can use cached source/module.
733 if (get_script_from_cache(s))
734 {
735 // If our last pass isn't 5, we're done (since passes 3 and
736 // 4 just generate what we just pulled out of the cache).
737 if (s.last_pass < 5 || pending_interrupts) return rc;
738
739 // Short-circuit to pass 5.
740 return 0;
741 }
742 }
743
744 // PASS 3: TRANSLATION
745 s.verbose = s.perpass_verbose[2];
746 times (& tms_before);
747 gettimeofday (&tv_before, NULL);
0f5d597d 748 PROBE1(stap, pass3__start, &s);
85007c04
DB
749
750 rc = translate_pass (s);
3e1ec884 751 if (! rc && s.last_pass == 3)
85007c04
DB
752 {
753 ifstream i (s.translated_source.c_str());
754 cout << i.rdbuf();
755 }
756
757 times (& tms_after);
758 gettimeofday (&tv_after, NULL);
759
79bc39ab
LB
760 if (s.verbose)
761 clog << "Pass 3: translated to C into \""
762 << s.translated_source
763 << "\" "
764 << getmemusage()
765 << TIMESPRINT
85007c04
DB
766 << endl;
767
44edbcd6 768 if (rc && ! s.try_server ())
79bc39ab
LB
769 cerr << _("Pass 3: translation failed. Try again with another '--vp 001' option.") << endl;
770 //cerr << "Pass 3: translation failed. "
771 // << "Try again with another '--vp 001' option."
772 // << endl;
773
0f5d597d 774 PROBE1(stap, pass3__end, &s);
85007c04
DB
775
776 if (rc || s.last_pass == 3 || pending_interrupts) return rc;
777
778 // PASS 4: COMPILATION
779 s.verbose = s.perpass_verbose[3];
780 times (& tms_before);
781 gettimeofday (&tv_before, NULL);
0f5d597d 782 PROBE1(stap, pass4__start, &s);
85007c04
DB
783
784 if (s.use_cache)
785 {
786 find_stapconf_hash(s);
787 get_stapconf_from_cache(s);
788 }
789 rc = compile_pass (s);
3e1ec884 790 if (! rc && s.last_pass == 4)
85007c04
DB
791 {
792 cout << ((s.hash_path == "") ? (s.module_name + string(".ko")) : s.hash_path);
793 cout << endl;
794 }
795
796 times (& tms_after);
797 gettimeofday (&tv_after, NULL);
798
799 if (s.verbose) clog << "Pass 4: compiled C into \""
800 << s.module_name << ".ko"
801 << "\" "
802 << TIMESPRINT
803 << endl;
804
44edbcd6 805 if (rc && ! s.try_server ())
79bc39ab
LB
806 cerr << _("Pass 4: compilation failed. Try again with another '--vp 0001' option.") << endl;
807 //cerr << "Pass 4: compilation failed. "
808 // << "Try again with another '--vp 0001' option."
809 // << endl;
85007c04
DB
810 else
811 {
812 // Update cache. Cache cleaning is kicked off at the beginning of this function.
813 if (s.use_script_cache)
814 add_script_to_cache(s);
815 if (s.use_cache)
816 add_stapconf_to_cache(s);
817
818 // We may need to save the module in $CWD if the cache was
819 // inaccessible for some reason.
820 if (! s.use_script_cache && s.last_pass == 4)
821 s.save_module = true;
822
823 // Copy module to the current directory.
824 if (s.save_module && !pending_interrupts)
825 {
826 string module_src_path = s.tmpdir + "/" + s.module_name + ".ko";
827 string module_dest_path = s.module_name + ".ko";
828 copy_file(module_src_path, module_dest_path, s.verbose > 1);
829 }
830 }
831
0f5d597d 832 PROBE1(stap, pass4__end, &s);
85007c04
DB
833
834 return rc;
835}
836
837static int
ebff2ed0 838pass_5 (systemtap_session &s, vector<remote*> targets)
85007c04
DB
839{
840 // PASS 5: RUN
841 s.verbose = s.perpass_verbose[4];
842 struct tms tms_before;
843 times (& tms_before);
844 struct timeval tv_before;
845 gettimeofday (&tv_before, NULL);
846 // NB: this message is a judgement call. The other passes don't emit
847 // a "hello, I'm starting" message, but then the others aren't interactive
848 // and don't take an indefinite amount of time.
0f5d597d 849 PROBE1(stap, pass5__start, &s);
79bc39ab 850 if (s.verbose) clog << _("Pass 5: starting run.") << endl;
94a8b578 851 int rc = 0; // XXX with multiple targets, need to deal with partial failure
ebff2ed0
JS
852 for (unsigned i = 0; i < targets.size() && !pending_interrupts; ++i)
853 rc |= targets[i]->start();
854 for (unsigned i = 0; i < targets.size(); ++i)
855 rc |= targets[i]->finish();
85007c04
DB
856 struct tms tms_after;
857 times (& tms_after);
858 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
859 struct timeval tv_after;
860 gettimeofday (&tv_after, NULL);
861 if (s.verbose) clog << "Pass 5: run completed "
862 << TIMESPRINT
863 << endl;
864
865 if (rc)
79bc39ab
LB
866 cerr << _("Pass 5: run failed. Try again with another '--vp 00001' option.") << endl;
867 //cerr << "Pass 5: run failed. "
868 // << "Try again with another '--vp 00001' option."
869 // << endl;
85007c04
DB
870 else
871 // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below.
872 pending_interrupts = 0;
873
0f5d597d 874 PROBE1(stap, pass5__end, &s);
85007c04
DB
875
876 return rc;
877}
878
879static void
880cleanup (systemtap_session &s, int rc)
881{
882 // PASS 6: cleaning up
0f5d597d 883 PROBE1(stap, pass6__start, &s);
85007c04 884
ebff2ed0
JS
885 for (systemtap_session::session_map_t::iterator it = s.subsessions.begin();
886 it != s.subsessions.end(); ++it)
887 cleanup (*it->second, rc);
888
85007c04
DB
889 // update the database information
890 if (!rc && s.tapset_compile_coverage && !pending_interrupts) {
891#ifdef HAVE_LIBSQLITE3
892 update_coverage_db(s);
893#else
79bc39ab 894 cerr << _("Coverage database not available without libsqlite3") << endl;
85007c04
DB
895#endif
896 }
897
898 // Clean up temporary directory. Obviously, be careful with this.
899 remove_temp_dir (s);
900
0f5d597d 901 PROBE1(stap, pass6__end, &s);
85007c04
DB
902}
903
44edbcd6
JS
904static int
905passes_0_4_again_with_server (systemtap_session &s)
906{
907 // Not a server and not already using a server.
908 assert (! s.client_options);
909 assert (s.specified_servers.empty ());
910
911 // Specify default server(s).
912 s.specified_servers.push_back ("");
913
914 // Remove the previous temporary directory and start fresh.
915 remove_temp_dir (s);
916
917 // Try to compile again, using the server
918 clog << "Attempting compilation using a compile server"
919 << endl;
920 int rc = passes_0_4 (s);
921 return rc;
922}
923
85007c04
DB
924int
925main (int argc, char * const argv [])
926{
927 // Initialize defaults.
928 systemtap_session s;
929
79bc39ab
LB
930 setlocale (LC_ALL, "");
931 bindtextdomain (PACKAGE, LOCALEDIR);
932 textdomain (PACKAGE);
933
85007c04
DB
934 // Process the command line.
935 int rc = s.parse_cmdline (argc, argv);
936 if (rc != 0)
937 exit (rc);
938
939 // Check for options conflicts. Exits if errors are detected.
940 s.check_options (argc, argv);
941
942 // If requested, query server status. This is independent of other tasks.
943 query_server_status (s);
944
c77af0d0
DB
945 // If requested, manage trust of servers. This is independent of other tasks.
946 manage_server_trust (s);
947
85007c04
DB
948 // Run the passes only if a script has been specified. The requirement for
949 // a script has already been checked in systemtap_session::check_options.
950 if (s.have_script)
951 {
ebff2ed0
JS
952 vector<remote*> targets;
953 if (s.remote_uris.empty())
954 {
955 remote* target = remote::create(s, "direct");
956 if (target)
957 targets.push_back(target);
958 else
959 rc = 1;
960 }
daa75206 961 else
ebff2ed0
JS
962 for (unsigned i = 0; i < s.remote_uris.size(); ++i)
963 {
964 remote *target = remote::create(s, s.remote_uris[i]);
965 if (target)
966 targets.push_back(target);
967 else
968 {
969 rc = 1;
970 break;
971 }
972 }
973
974 // Run passes 0-4 for each unique session,
975 // either locally or using a compile-server.
daa75206 976 if (rc == 0)
ebff2ed0
JS
977 {
978 set<systemtap_session*> sessions;
979 for (unsigned i = 0; i < targets.size(); ++i)
980 sessions.insert(targets[i]->get_session());
981 for (set<systemtap_session*>::iterator it = sessions.begin();
982 it != sessions.end(); ++it)
44edbcd6
JS
983 {
984 (*it)->init_try_server ();
985 if ((rc = passes_0_4 (**it)))
986 {
987 // Compilation failed.
988 // Try again using a server if appropriate.
989 if ((*it)->try_server ())
990 rc = passes_0_4_again_with_server (**it);
991 if (rc)
992 break;
993 }
994 }
ebff2ed0 995 }
85007c04
DB
996
997 // Run pass 5, if requested
998 if (rc == 0 && s.last_pass >= 5 && ! pending_interrupts)
ebff2ed0
JS
999 rc = pass_5 (s, targets);
1000
1001 for (unsigned i = 0; i < targets.size(); ++i)
1002 delete targets[i];
85007c04
DB
1003 }
1004
1005 // Pass 6. Cleanup
1006 cleanup (s, rc);
1007
1008 return (rc||pending_interrupts) ? EXIT_FAILURE : EXIT_SUCCESS;
1009}
1010
1011/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.221535 seconds and 5 git commands to generate.