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