]> sourceware.org Git - systemtap.git/blame - main.cxx
Use std::thread for threading and CPU counts
[systemtap.git] / main.cxx
CommitLineData
f4b28491 1// systemtap translator/driver
4eb12770 2// Copyright (C) 2005-2016 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"
9ac12b89 28#ifdef HAVE_LIBREADLINE
11a046b7 29#include "interactive.h"
9ac12b89 30#endif
85007c04 31
52c2652f 32#if ENABLE_NLS
79bc39ab
LB
33#include <libintl.h>
34#include <locale.h>
52c2652f 35#endif
79bc39ab 36
0f5d597d 37#include "stap-probe.h"
aa4d21c0 38
24cb178f 39#include <cstdlib>
636e55b8 40#include <thread>
73267b89 41
85007c04
DB
42extern "C" {
43#include <glob.h>
44#include <unistd.h>
45#include <signal.h>
46#include <sys/utsname.h>
47#include <sys/times.h>
48#include <sys/time.h>
49#include <sys/stat.h>
50#include <time.h>
51#include <unistd.h>
222e16ed 52#include <wordexp.h>
85007c04
DB
53}
54
55using namespace std;
56
40a50254
JS
57static void
58uniq_list(list<string>& l)
e2012a7a 59{
40a50254
JS
60 set<string> s;
61 list<string>::iterator i = l.begin();
62 while (i != l.end())
63 if (s.insert(*i).second)
64 ++i;
65 else
66 i = l.erase(i);
85007c04 67}
2dce8c42 68
85007c04
DB
69static void
70printscript(systemtap_session& s, ostream& o)
71{
bba368c5
JL
72 if (s.dump_mode == systemtap_session::dump_matched_probes ||
73 s.dump_mode == systemtap_session::dump_matched_probes_vars)
85007c04
DB
74 {
75 // We go through some heroic measures to produce clean output.
76 // Record the alias and probe pointer as <name, set<derived_probe *> >
77 map<string,set<derived_probe *> > probe_list;
6e683641 78
85007c04
DB
79 // Pre-process the probe alias
80 for (unsigned i=0; i<s.probes.size(); i++)
81 {
e19ebcf7 82 assert_no_interrupts();
85007c04
DB
83
84 derived_probe* p = s.probes[i];
ede0102c
JS
85 vector<probe*> chain;
86 p->collect_derivation_chain (chain);
87
8159bf55 88 if (s.verbose > 2) {
8159bf55
FCE
89 p->printsig(cerr); cerr << endl;
90 cerr << "chain[" << chain.size() << "]:" << endl;
91 for (unsigned j=0; j<chain.size(); j++)
92 {
93 cerr << " [" << j << "]: " << endl;
94 cerr << "\tlocations[" << chain[j]->locations.size() << "]:" << endl;
95 for (unsigned k=0; k<chain[j]->locations.size(); k++)
96 {
97 cerr << "\t [" << k << "]: ";
98 chain[j]->locations[k]->print(cerr);
99 cerr << endl;
100 }
101 const probe_alias *a = chain[j]->get_alias();
102 if (a)
103 {
104 cerr << "\taliases[" << a->alias_names.size() << "]:" << endl;
105 for (unsigned k=0; k<a->alias_names.size(); k++)
106 {
107 cerr << "\t [" << k << "]: ";
108 a->alias_names[k]->print(cerr);
109 cerr << endl;
110 }
111 }
112 }
7977a734 113 }
eb55dce6
JS
114
115 const string& pp = lex_cast(*p->script_location());
116
117 // PR16730: We should only list probes that can be traced back to the
118 // user's spec, not any auxiliary probes in the tapsets.
ba48c27a
AJ
119 // Also, do not want to the probes that are from the additional
120 // scripts (-E SCRIPT) to be listed.
1ee0d3ba
JL
121 if (!s.is_primary_probe(p))
122 continue;
85007c04
DB
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
bba368c5 136 if (s.dump_mode == systemtap_session::dump_matched_probes_vars)
85007c04
DB
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 {
e19ebcf7 184 assert_no_interrupts();
85007c04
DB
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 {
e19ebcf7 194 assert_no_interrupts();
85007c04
DB
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 {
e19ebcf7 209 assert_no_interrupts();
85007c04
DB
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 {
e19ebcf7 233 assert_no_interrupts();
85007c04
DB
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"
dabd71bb 259void handle_interrupt (int)
85007c04 260{
c9c8c406
JS
261 // This might be nice, but we don't know our current verbosity...
262 // clog << _F("Received signal %d", sig) << endl << flush;
878b2f3f
CM
263 kill_stap_spawn(SIGTERM);
264
85007c04 265 pending_interrupts ++;
536a1b69
FCE
266 // Absorb the first two signals. This used to be one, but when
267 // stap is run under sudo, and then interrupted, sudo relays a
268 // redundant copy of the signal to stap, leading to an unclean shutdown.
269 if (pending_interrupts > 2) // XXX: should be configurable? time-based?
85007c04
DB
270 {
271 char msg[] = "Too many interrupts received, exiting.\n";
272 int rc = write (2, msg, sizeof(msg)-1);
273 if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;}
274 _exit (1);
275 }
276}
277
278
279void
280setup_signals (sighandler_t handler)
281{
282 struct sigaction sa;
283
11c6c509 284 memset(&sa, 0, sizeof(sa));
85007c04
DB
285 sa.sa_handler = handler;
286 sigemptyset (&sa.sa_mask);
287 if (handler != SIG_IGN)
288 {
289 sigaddset (&sa.sa_mask, SIGHUP);
290 sigaddset (&sa.sa_mask, SIGPIPE);
291 sigaddset (&sa.sa_mask, SIGINT);
292 sigaddset (&sa.sa_mask, SIGTERM);
5ed19be2
DB
293 sigaddset (&sa.sa_mask, SIGXFSZ);
294 sigaddset (&sa.sa_mask, SIGXCPU);
85007c04
DB
295 }
296 sa.sa_flags = SA_RESTART;
297
298 sigaction (SIGHUP, &sa, NULL);
299 sigaction (SIGPIPE, &sa, NULL);
300 sigaction (SIGINT, &sa, NULL);
301 sigaction (SIGTERM, &sa, NULL);
5ed19be2
DB
302 sigaction (SIGXFSZ, &sa, NULL);
303 sigaction (SIGXCPU, &sa, NULL);
e2012a7a 304}
6e683641 305
85007c04 306
636e55b8
JS
307static void
308sdt_benchmark_thread(unsigned long i)
3d0a328d 309{
26d48584 310 PROBE(stap, benchmark__thread__start);
3d0a328d 311 while (i--)
bc7f17fb 312 PROBE1(stap, benchmark, i);
f8e839e8 313 PROBE(stap, benchmark__thread__end);
3d0a328d
JS
314}
315
316
317static int
318run_sdt_benchmark(systemtap_session& s)
319{
320 unsigned long loops = s.benchmark_sdt_loops ?: 10000000;
321 unsigned long threads = s.benchmark_sdt_threads ?: 1;
322
a7160c2b
JS
323 if (s.verbose > 0)
324 clog << _F("Beginning SDT benchmark with %lu loops in %lu threads.",
325 loops, threads) << endl;
3d0a328d
JS
326
327 struct tms tms_before, tms_after;
328 struct timeval tv_before, tv_after;
329 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
330 times (& tms_before);
331 gettimeofday (&tv_before, NULL);
332
26d48584 333 PROBE(stap, benchmark__start);
636e55b8
JS
334 {
335 vector<thread> handles;
336 for (unsigned long i = 0; i < threads; ++i)
337 handles.push_back(thread(sdt_benchmark_thread, loops));
338 for (unsigned long i = 0; i < threads; ++i)
339 handles[i].join();
340 }
f8e839e8 341 PROBE(stap, benchmark__end);
bc7f17fb 342
3d0a328d
JS
343 times (& tms_after);
344 gettimeofday (&tv_after, NULL);
a7160c2b
JS
345 if (s.verbose > 0)
346 clog << _F("Completed SDT benchmark in %ldusr/%ldsys/%ldreal ms.",
561d4ebd
FCE
347 (long)(tms_after.tms_utime - tms_before.tms_utime) * 1000 / _sc_clk_tck,
348 (long)(tms_after.tms_stime - tms_before.tms_stime) * 1000 / _sc_clk_tck,
349 (long)((tv_after.tv_sec - tv_before.tv_sec) * 1000 +
a7160c2b
JS
350 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000))
351 << endl;
3d0a328d
JS
352
353 return EXIT_SUCCESS;
354}
355
356
44edbcd6 357// Compilation passes 0 through 4
11a046b7 358int
85007c04
DB
359passes_0_4 (systemtap_session &s)
360{
361 int rc = 0;
daa75206 362
504d2b61
JS
363 // If we don't know the release, there's no hope either locally or on a server.
364 if (s.kernel_release.empty())
365 {
366 if (s.kernel_build_tree.empty())
367 cerr << _("ERROR: kernel release isn't specified") << endl;
368 else
46a1a151
JS
369 cerr << _F("ERROR: kernel release isn't found in \"%s\"",
370 s.kernel_build_tree.c_str()) << endl;
504d2b61
JS
371 return 1;
372 }
373
85007c04
DB
374 // Perform passes 0 through 4 using a compile server?
375 if (! s.specified_servers.empty ())
376 {
0d1534e8 377#if HAVE_NSS
85007c04 378 compile_server_client client (s);
4e78c716 379 return client.passes_0_4 ();
0d1534e8 380#else
4e78c716
DB
381 s.print_warning(_("Without NSS, using a compile-server is not supported by this version of systemtap"));
382
3e1ec884
DB
383 // This cannot be an attempt to use a server after a local compile failed
384 // since --use-server-on-error is locked to 'no' if we don't have
385 // NSS.
386 assert (! s.try_server ());
4e78c716 387 s.print_warning(_("Ignoring --use-server"));
0d1534e8 388#endif
85007c04
DB
389 }
390
391 // PASS 0: setting up
392 s.verbose = s.perpass_verbose[0];
0f5d597d 393 PROBE1(stap, pass0__start, &s);
85007c04 394
85007c04
DB
395 // For PR1477, we used to override $PATH and $LC_ALL and other stuff
396 // here. We seem to use complete pathnames in
397 // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
398 // it interferes with util.cxx:find_executable(), used for $PATH
399 // resolution.
400
401 s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
402
05fb3e0c
WF
403 // Update various paths to include the sysroot, if provided.
404 if (!s.sysroot.empty())
405 {
406 if (s.update_release_sysroot && !s.sysroot.empty())
407 s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
408 debuginfo_path_insert_sysroot(s.sysroot);
409 }
410
85007c04 411 // Now that no further changes to s.kernel_build_tree can occur, let's use it.
d0923e36
NMA
412 if (s.runtime_mode == systemtap_session::kernel_runtime) {
413 if ((rc = s.parse_kernel_config ()) != 0
414 || (rc = s.parse_kernel_exports ()) != 0
415 || (rc = s.parse_kernel_functions ()) != 0)
416 {
417 // Try again with a server
418 s.set_try_server ();
419 return rc;
420 }
421 }
85007c04
DB
422
423 // Create the name of the C source file within the temporary
a4b9c3b3
FCE
424 // directory. Note the _src prefix, explained in
425 // buildrun.cxx:compile_pass()
426 s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c";
85007c04 427
0f5d597d 428 PROBE1(stap, pass0__end, &s);
85007c04
DB
429
430 struct tms tms_before;
431 times (& tms_before);
432 struct timeval tv_before;
433 gettimeofday (&tv_before, NULL);
434
e7c60c35 435 // PASS 1a: PARSING LIBRARY SCRIPTS
0f5d597d 436 PROBE1(stap, pass1a__start, &s);
85007c04 437
d53a4bd1 438 if (! s.pass_1a_complete)
f705da87 439 {
d53a4bd1
DS
440 // We need to handle the library scripts first because this pass
441 // gathers information on .stpm files that might be needed to
442 // parse the user script.
f705da87 443
d53a4bd1
DS
444 // We need to first ascertain the status of the user script, though.
445 struct stat user_file_stat;
446 int user_file_stat_rc = -1;
f705da87 447
d53a4bd1 448 if (s.script_file == "-")
f705da87 449 {
d53a4bd1
DS
450 user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat);
451 }
452 else if (s.script_file != "")
f705da87 453 {
d53a4bd1
DS
454 user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
455 }
456 // otherwise, rc is 0 for a command line script
f705da87 457
d53a4bd1
DS
458 vector<string> version_suffixes;
459 if (s.runtime_mode == systemtap_session::kernel_runtime)
f7a557ae 460 {
d53a4bd1
DS
461 // Construct kernel-versioning search path
462 string kvr = s.kernel_release;
463
464 // add full kernel-version-release (2.6.NN-FOOBAR)
465 version_suffixes.push_back ("/" + kvr);
466
467 // add kernel version (2.6.NN)
468 if (kvr != s.kernel_base_release)
469 {
470 kvr = s.kernel_base_release;
471 version_suffixes.push_back ("/" + kvr);
472 }
473
474 // add kernel family (2.6)
475 string::size_type dot1_index = kvr.find ('.');
476 string::size_type dot2_index = kvr.rfind ('.');
477 while (dot2_index > dot1_index && dot2_index != string::npos)
478 {
479 kvr.erase(dot2_index);
480 version_suffixes.push_back ("/" + kvr);
481 dot2_index = kvr.rfind ('.');
482 }
483 }
484
485 // add empty string as last element
486 version_suffixes.push_back ("");
487
488 // Add arch variants of every path, just before each
489 const string& arch = s.architecture;
490 for (unsigned i=0; i<version_suffixes.size(); i+=2)
491 version_suffixes.insert(version_suffixes.begin() + i,
492 version_suffixes[i] + "/" + arch);
493
494 // Add runtime variants of every path, before everything else
495 string runtime_prefix;
496 if (s.runtime_mode == systemtap_session::kernel_runtime)
497 runtime_prefix = "/linux";
498 else if (s.runtime_mode == systemtap_session::dyninst_runtime)
499 runtime_prefix = "/dyninst";
500 if (!runtime_prefix.empty())
501 for (unsigned i=0; i<version_suffixes.size(); i+=2)
502 version_suffixes.insert(version_suffixes.begin() + i/2,
503 runtime_prefix + version_suffixes[i]);
504
505 // First, parse .stpm files on the include path. We need to have the
506 // resulting macro definitions available for parsing library files,
507 // but since .stpm files can consist only of '@define' constructs,
508 // we can parse each one without reference to the others.
509 set<pair<dev_t, ino_t> > seen_library_macro_files;
510 set<string> seen_library_macro_files_names;
511
512 for (unsigned i=0; i<s.include_path.size(); i++)
85007c04 513 {
d53a4bd1
DS
514 // now iterate upon it
515 for (unsigned k=0; k<version_suffixes.size(); k++)
516 {
517 glob_t globbuf;
518 string dir = s.include_path[i] + version_suffixes[k] + "/*.stpm";
519 int r = glob(dir.c_str (), 0, NULL, & globbuf);
520 if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
521 rc ++;
522 // GLOB_NOMATCH is acceptable
523
524 unsigned prev_s_library_files = s.library_files.size();
525
526 for (unsigned j=0; j<globbuf.gl_pathc; j++)
527 {
528 assert_no_interrupts();
529
530 struct stat tapset_file_stat;
531 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
532 if (stat_rc == 0 && user_file_stat_rc == 0 &&
533 user_file_stat.st_dev == tapset_file_stat.st_dev &&
534 user_file_stat.st_ino == tapset_file_stat.st_ino)
535 {
536 cerr
537 << _F("usage error: macro tapset file '%s' cannot be run directly as a session script.",
538 globbuf.gl_pathv[j]) << endl;
539 rc ++;
540 }
541
542 // PR11949: duplicate-eliminate tapset files
543 if (stat_rc == 0)
544 {
545 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
546 tapset_file_stat.st_ino);
547 if (seen_library_macro_files.find(here) != seen_library_macro_files.end())
548 {
549 if (s.verbose>2)
550 clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl;
551 continue;
552 }
553 seen_library_macro_files.insert (here);
554 }
555
556 // PR12443: duplicate-eliminate harder
557 string full_path = globbuf.gl_pathv[j];
558 string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
559 if (full_path.size() > tapset_base.size())
560 {
561 string tail_part = full_path.substr(tapset_base.size());
562 if (seen_library_macro_files_names.find (tail_part) != seen_library_macro_files_names.end())
563 {
564 if (s.verbose>2)
565 clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl;
566 continue;
567 }
568 seen_library_macro_files_names.insert (tail_part);
569 }
570
571 if (s.verbose>2)
572 clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
573
574 stapfile* f = parse_library_macros (s, globbuf.gl_pathv[j]);
575 if (f == 0)
576 s.print_warning(_F("macro tapset \"%s\" has errors, and will be skipped.", string(globbuf.gl_pathv[j]).c_str()));
577 else
578 s.library_files.push_back (f);
579 }
580
581 unsigned next_s_library_files = s.library_files.size();
582 if (s.verbose>1 && globbuf.gl_pathc > 0)
583 //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
584 clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u",
585 dir.c_str(), globbuf.gl_pathc,
586 (next_s_library_files-prev_s_library_files)) << endl;
587
588 globfree (&globbuf);
589 }
590 }
591
592 // Next, gather and parse the library files.
593 set<pair<dev_t, ino_t> > seen_library_files;
594 set<string> seen_library_files_names;
595
596 for (unsigned i=0; i<s.include_path.size(); i++)
597 {
598 unsigned tapset_flags = pf_guru | pf_squash_errors;
599
600 // The first path is special, as it's the builtin tapset.
601 // Allow all features no matter what s.compatible says.
602 if (i == 0)
603 tapset_flags |= pf_no_compatible;
604
605 // now iterate upon it
606 for (unsigned k=0; k<version_suffixes.size(); k++)
607 {
608 glob_t globbuf;
609 string dir = s.include_path[i] + version_suffixes[k] + "/*.stp";
610 int r = glob(dir.c_str (), 0, NULL, & globbuf);
611 if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
612 rc ++;
613 // GLOB_NOMATCH is acceptable
614
615 unsigned prev_s_library_files = s.library_files.size();
616
617 for (unsigned j=0; j<globbuf.gl_pathc; j++)
618 {
619 assert_no_interrupts();
620
621 struct stat tapset_file_stat;
622 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
623 if (stat_rc == 0 && user_file_stat_rc == 0 &&
624 user_file_stat.st_dev == tapset_file_stat.st_dev &&
625 user_file_stat.st_ino == tapset_file_stat.st_ino)
626 {
627 cerr
628 << _F("usage error: tapset file '%s' cannot be run directly as a session script.",
629 globbuf.gl_pathv[j]) << endl;
630 rc ++;
631 }
632
633 // PR11949: duplicate-eliminate tapset files
634 if (stat_rc == 0)
635 {
636 pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
637 tapset_file_stat.st_ino);
638 if (seen_library_files.find(here) != seen_library_files.end())
639 {
640 if (s.verbose>2)
641 clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl;
642 continue;
643 }
644 seen_library_files.insert (here);
645 }
646
647 // PR12443: duplicate-eliminate harder
648 string full_path = globbuf.gl_pathv[j];
649 string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
650 if (full_path.size() > tapset_base.size())
651 {
652 string tail_part = full_path.substr(tapset_base.size());
653 if (seen_library_files_names.find (tail_part) != seen_library_files_names.end())
654 {
655 if (s.verbose>2)
656 clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl;
657 continue;
658 }
659 seen_library_files_names.insert (tail_part);
660 }
661
662 if (s.verbose>2)
663 clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
664
665 // NB: we don't need to restrict privilege only for
666 // /usr/share/systemtap, i.e., excluding
667 // user-specified $XDG_DATA_DIRS. That's because
668 // stapdev gets root-equivalent privileges anyway;
669 // stapsys and stapusr use a remote compilation with
670 // a trusted environment, where client-side
671 // $XDG_DATA_DIRS are not passed.
672
673 stapfile* f = parse (s, globbuf.gl_pathv[j], tapset_flags);
674 if (f == 0)
675 s.print_warning(_F("tapset \"%s\" has errors, and will be skipped", string(globbuf.gl_pathv[j]).c_str()));
676 else
677 s.library_files.push_back (f);
678 }
679
680 unsigned next_s_library_files = s.library_files.size();
681 if (s.verbose>1 && globbuf.gl_pathc > 0)
682 //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
683 clog << _F("Searched: \"%s\", found: %zu, processed: %u",
684 dir.c_str(), globbuf.gl_pathc,
685 (next_s_library_files-prev_s_library_files)) << endl;
686
687 globfree (& globbuf);
688 }
689 }
690 if (s.num_errors())
691 rc ++;
692
693 // Now that we've made it through pass 1a, remember this so we
694 // don't have to do this again in interactive mode. This doesn't
695 // effect non-interactive mode.
696 s.pass_1a_complete = true;
d53a4bd1 697 }
11a046b7 698
e7c60c35
SM
699 // PASS 1b: PARSING USER SCRIPT
700 PROBE1(stap, pass1b__start, &s);
701
bba368c5
JL
702 // Only try to parse a user script if the user provided one, or if we have to
703 // make one (as is the case for listing mode). Otherwise, s.user_script
704 // remains NULL.
705 if (!s.script_file.empty() ||
706 !s.cmdline_script.empty() ||
707 s.dump_mode == systemtap_session::dump_matched_probes ||
708 s.dump_mode == systemtap_session::dump_matched_probes_vars)
e7c60c35 709 {
f8405ea5 710 unsigned user_flags = s.guru_mode ? pf_guru : 0;
7b5b30a8 711 user_flags |= pf_user_file;
bba368c5
JL
712 if (s.script_file == "-")
713 {
ba48c27a 714 s.user_files.push_back (parse (s, "<input>", cin, user_flags));
bba368c5
JL
715 }
716 else if (s.script_file != "")
717 {
ba48c27a 718 s.user_files.push_back (parse (s, s.script_file, user_flags));
bba368c5
JL
719 }
720 else if (s.cmdline_script != "")
721 {
722 istringstream ii (s.cmdline_script);
ba48c27a 723 s.user_files.push_back(parse (s, "<input>", ii, user_flags));
bba368c5
JL
724 }
725 else // listing mode
726 {
727 istringstream ii ("probe " + s.dump_matched_pattern + " {}");
ba48c27a 728 s.user_files.push_back (parse (s, "<input>", ii, user_flags));
bba368c5 729 }
ba48c27a
AJ
730
731 // parses the additional script(s) (-E script). does so even if in listing
732 // mode, incase there is something special in the additional script(s),
733 // like a macro or alias. give them a unique name to differentiate the
734 // scripts that were inputted.
735 unsigned count = 1;
736 for (vector<string>::iterator script = s.additional_scripts.begin(); script != s.additional_scripts.end(); script++)
737 {
738 string input_name = "<input" + lex_cast(count) + ">";
739 istringstream ii (*script);
740 s.user_files.push_back(parse (s, input_name, ii, user_flags));
741 count ++;
742 }
743
744 for(vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++)
bba368c5 745 {
ba48c27a
AJ
746 if (!(*it))
747 {
748 // Syntax errors already printed.
749 rc ++;
750 }
bba368c5 751 }
e7c60c35 752 }
30b1666e
FL
753 else if (s.cmdline_script.empty() &&
754 s.dump_mode == systemtap_session::dump_none) // -e ''
4bc2b5cd
FL
755 {
756 cerr << _("Input file '<input>' is empty.") << endl;
757 rc++;
758 }
e7c60c35 759
7d66cd75 760 // Dump a list of probe aliases picked up, if requested
bba368c5 761 if (s.dump_mode == systemtap_session::dump_probe_aliases)
7d66cd75
JL
762 {
763 set<string> aliases;
764 vector<stapfile*>::const_iterator file;
765 for (file = s.library_files.begin();
766 file != s.library_files.end(); ++file)
767 {
768 vector<probe_alias*>::const_iterator alias;
769 for (alias = (*file)->aliases.begin();
770 alias != (*file)->aliases.end(); ++alias)
771 {
772 stringstream ss;
773 (*alias)->printsig(ss);
774 string str = ss.str();
775 if (!s.verbose && startswith(str, "_"))
776 continue;
777 aliases.insert(str);
778 }
779 }
780
781 set<string>::iterator alias;
782 for (alias = aliases.begin();
783 alias != aliases.end(); ++alias)
784 {
785 cout << *alias << endl;
786 }
787 }
788 // Dump the parse tree if this is the last pass
789 else if (rc == 0 && s.last_pass == 1)
4c263acb
SM
790 {
791 cout << _("# parse tree dump") << endl;
ba48c27a
AJ
792 for (vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++)
793 (*it)->print (cout);
4c263acb
SM
794 cout << endl;
795 if (s.verbose)
796 for (unsigned i=0; i<s.library_files.size(); i++)
797 {
798 s.library_files[i]->print (cout);
799 cout << endl;
800 }
801 }
802
85007c04
DB
803 struct tms tms_after;
804 times (& tms_after);
805 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
806 struct timeval tv_after;
807 gettimeofday (&tv_after, NULL);
808
678efd81 809#define TIMESPRINT _("in ") << \
85007c04
DB
810 (tms_after.tms_cutime + tms_after.tms_utime \
811 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
812 << (tms_after.tms_cstime + tms_after.tms_stime \
813 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
814 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
815 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
816
817 // syntax errors, if any, are already printed
818 if (s.verbose)
819 {
e7c60c35 820 // XXX also include a count of helper macro files loaded (.stpm)?
678efd81 821 int n = int(s.library_files.size());
f275fa40 822 clog << _("Pass 1: parsed user script and ")
678efd81 823 << _NF("%d library script ", "%d library scripts ", n, n)
85007c04
DB
824 << getmemusage()
825 << TIMESPRINT
826 << endl;
827 }
828
bba368c5 829 if (rc && !s.dump_mode)
1f35f4db 830 cerr << _("Pass 1: parse failed. [man error::pass1]") << endl;
85007c04 831
0f5d597d 832 PROBE1(stap, pass1__end, &s);
85007c04 833
e19ebcf7 834 assert_no_interrupts();
bba368c5
JL
835 if (rc || s.last_pass == 1 ||
836 s.dump_mode == systemtap_session::dump_probe_aliases)
837 return rc;
85007c04
DB
838
839 times (& tms_before);
840 gettimeofday (&tv_before, NULL);
841
842 // PASS 2: ELABORATION
843 s.verbose = s.perpass_verbose[1];
0f5d597d 844 PROBE1(stap, pass2__start, &s);
85007c04
DB
845 rc = semantic_pass (s);
846
b82d77b4 847 // Dump a list of known probe point types, if requested.
bba368c5 848 if (s.dump_mode == systemtap_session::dump_probe_types)
b82d77b4 849 s.pattern_root->dump (s);
eb9ea966 850 // Dump a list of functions we picked up, if requested.
bba368c5 851 else if (s.dump_mode == systemtap_session::dump_functions)
eb9ea966
JL
852 {
853 map<string,functiondecl*>::const_iterator func;
854 for (func = s.functions.begin();
855 func != s.functions.end(); ++func)
856 {
857 functiondecl& curfunc = *func->second;
858 if (curfunc.synthetic)
859 continue;
8f54215e
MC
860 if (!startswith(curfunc.name, "__global_"))
861 continue;
862 if (!s.verbose && startswith(curfunc.name, "__global__"))
eb9ea966
JL
863 continue;
864 curfunc.printsigtags(cout, s.verbose>0 /* all_tags */ );
865 cout << endl;
866 }
867 }
868 // Dump the whole script if requested, or if we stop at 2
bba368c5
JL
869 else if (s.dump_mode == systemtap_session::dump_matched_probes ||
870 s.dump_mode == systemtap_session::dump_matched_probes_vars ||
871 (rc == 0 && s.last_pass == 2))
85007c04
DB
872 printscript(s, cout);
873
874 times (& tms_after);
875 gettimeofday (&tv_after, NULL);
876
678efd81
MC
877 if (s.verbose) {
878 int np = s.probes.size();
879 int nf = s.functions.size();
880 int ne = s.embeds.size();
881 int ng = s.globals.size();
882 clog << _("Pass 2: analyzed script: ")
883 << _NF("%d probe, ", "%d probes, ", np, np)
884 << _NF("%d function, ", "%d functions, ", nf, nf)
885 << _NF("%d embed, ", "%d embeds, ", ne, ne)
886 << _NF("%d global ", "%d globals ", ng, ng)
887 << getmemusage()
888 << TIMESPRINT
889 << endl;
890 }
85007c04 891
dae1c685
FCE
892 missing_rpm_list_print(s, "-debuginfo");
893
bba368c5 894 if (rc && !s.dump_mode && !s.try_server ())
1f35f4db 895 cerr << _("Pass 2: analysis failed. [man error::pass2]") << endl;
85007c04 896
0f5d597d 897 PROBE1(stap, pass2__end, &s);
85007c04 898
e19ebcf7 899 assert_no_interrupts();
bba368c5
JL
900 // NB: none of the dump modes need to go beyond pass-2. If this changes, break
901 // into individual modes here.
902 if (rc || s.last_pass == 2 || s.dump_mode)
903 return rc;
85007c04 904
d13bcfd8 905 rc = prepare_translate_pass (s);
e19ebcf7 906 assert_no_interrupts();
985892de 907 if (rc) return rc;
d13bcfd8 908
85007c04
DB
909 // Generate hash. There isn't any point in generating the hash
910 // if last_pass is 2, since we'll quit before using it.
911 if (s.use_script_cache)
912 {
913 ostringstream o;
914 unsigned saved_verbose;
915
916 {
917 // Make sure we're in verbose mode, so that printscript()
918 // will output function/probe bodies.
919 saved_verbose = s.verbose;
920 s.verbose = 3;
921 printscript(s, o); // Print script to 'o'
922 s.verbose = saved_verbose;
923 }
924
925 // Generate hash
926 find_script_hash (s, o.str());
927
928 // See if we can use cached source/module.
929 if (get_script_from_cache(s))
930 {
7d26ee02
JS
931 // We may still need to build uprobes, if it's not also cached.
932 if (s.need_uprobes)
933 rc = uprobes_pass(s);
934
85007c04
DB
935 // If our last pass isn't 5, we're done (since passes 3 and
936 // 4 just generate what we just pulled out of the cache).
e19ebcf7 937 assert_no_interrupts();
985892de 938 if (rc || s.last_pass < 5) return rc;
85007c04
DB
939
940 // Short-circuit to pass 5.
941 return 0;
942 }
943 }
944
945 // PASS 3: TRANSLATION
946 s.verbose = s.perpass_verbose[2];
947 times (& tms_before);
948 gettimeofday (&tv_before, NULL);
0f5d597d 949 PROBE1(stap, pass3__start, &s);
85007c04
DB
950
951 rc = translate_pass (s);
3e1ec884 952 if (! rc && s.last_pass == 3)
85007c04
DB
953 {
954 ifstream i (s.translated_source.c_str());
955 cout << i.rdbuf();
956 }
957
958 times (& tms_after);
959 gettimeofday (&tv_after, NULL);
960
79bc39ab 961 if (s.verbose)
f275fa40 962 clog << _("Pass 3: translated to C into \"")
79bc39ab
LB
963 << s.translated_source
964 << "\" "
965 << getmemusage()
966 << TIMESPRINT
85007c04
DB
967 << endl;
968
44edbcd6 969 if (rc && ! s.try_server ())
1f35f4db 970 cerr << _("Pass 3: translation failed. [man error::pass3]") << endl;
79bc39ab 971
0f5d597d 972 PROBE1(stap, pass3__end, &s);
85007c04 973
e19ebcf7 974 assert_no_interrupts();
985892de 975 if (rc || s.last_pass == 3) return rc;
85007c04
DB
976
977 // PASS 4: COMPILATION
978 s.verbose = s.perpass_verbose[3];
979 times (& tms_before);
980 gettimeofday (&tv_before, NULL);
0f5d597d 981 PROBE1(stap, pass4__start, &s);
85007c04
DB
982
983 if (s.use_cache)
984 {
985 find_stapconf_hash(s);
986 get_stapconf_from_cache(s);
987 }
988 rc = compile_pass (s);
3e1ec884 989 if (! rc && s.last_pass == 4)
85007c04 990 {
4441e344 991 cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path);
85007c04
DB
992 cout << endl;
993 }
994
995 times (& tms_after);
996 gettimeofday (&tv_after, NULL);
997
f275fa40 998 if (s.verbose) clog << _("Pass 4: compiled C into \"")
4441e344 999 << s.module_filename()
85007c04
DB
1000 << "\" "
1001 << TIMESPRINT
1002 << endl;
1003
44edbcd6 1004 if (rc && ! s.try_server ())
1f35f4db 1005 cerr << _("Pass 4: compilation failed. [man error::pass4]") << endl;
be4b2eed 1006
85007c04
DB
1007 else
1008 {
1009 // Update cache. Cache cleaning is kicked off at the beginning of this function.
1010 if (s.use_script_cache)
1011 add_script_to_cache(s);
ac3af990 1012 if (s.use_cache && !s.runtime_usermode_p())
85007c04
DB
1013 add_stapconf_to_cache(s);
1014
1015 // We may need to save the module in $CWD if the cache was
1016 // inaccessible for some reason.
1017 if (! s.use_script_cache && s.last_pass == 4)
1018 s.save_module = true;
1019
1020 // Copy module to the current directory.
1021 if (s.save_module && !pending_interrupts)
1022 {
4441e344
JS
1023 string module_src_path = s.tmpdir + "/" + s.module_filename();
1024 string module_dest_path = s.module_filename();
85007c04
DB
1025 copy_file(module_src_path, module_dest_path, s.verbose > 1);
1026 }
50f92d4e
SH
1027
1028 // Copy uprobes module to the current directory.
91ea0ce6 1029 if (s.save_uprobes && !s.uprobes_path.empty() && !pending_interrupts)
50f92d4e
SH
1030 {
1031 rc = create_dir("uprobes");
1032 if (! rc)
1033 copy_file(s.uprobes_path, "uprobes/uprobes.ko", s.verbose > 1);
1034 }
85007c04
DB
1035 }
1036
0f5d597d 1037 PROBE1(stap, pass4__end, &s);
85007c04
DB
1038
1039 return rc;
1040}
1041
11a046b7 1042int
ebff2ed0 1043pass_5 (systemtap_session &s, vector<remote*> targets)
85007c04
DB
1044{
1045 // PASS 5: RUN
1046 s.verbose = s.perpass_verbose[4];
1047 struct tms tms_before;
1048 times (& tms_before);
1049 struct timeval tv_before;
1050 gettimeofday (&tv_before, NULL);
1051 // NB: this message is a judgement call. The other passes don't emit
1052 // a "hello, I'm starting" message, but then the others aren't interactive
1053 // and don't take an indefinite amount of time.
0f5d597d 1054 PROBE1(stap, pass5__start, &s);
79bc39ab 1055 if (s.verbose) clog << _("Pass 5: starting run.") << endl;
4f244435 1056 int rc = remote::run(targets);
85007c04
DB
1057 struct tms tms_after;
1058 times (& tms_after);
1059 unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
1060 struct timeval tv_after;
1061 gettimeofday (&tv_after, NULL);
f275fa40 1062 if (s.verbose) clog << _("Pass 5: run completed ")
85007c04
DB
1063 << TIMESPRINT
1064 << endl;
1065
1066 if (rc)
1f35f4db 1067 cerr << _("Pass 5: run failed. [man error::pass5]") << endl;
85007c04
DB
1068 else
1069 // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below.
1070 pending_interrupts = 0;
1071
0f5d597d 1072 PROBE1(stap, pass5__end, &s);
85007c04
DB
1073
1074 return rc;
1075}
1076
1077static void
1078cleanup (systemtap_session &s, int rc)
1079{
1080 // PASS 6: cleaning up
0f5d597d 1081 PROBE1(stap, pass6__start, &s);
85007c04 1082
ebff2ed0
JS
1083 for (systemtap_session::session_map_t::iterator it = s.subsessions.begin();
1084 it != s.subsessions.end(); ++it)
1085 cleanup (*it->second, rc);
1086
85007c04
DB
1087 // update the database information
1088 if (!rc && s.tapset_compile_coverage && !pending_interrupts) {
1089#ifdef HAVE_LIBSQLITE3
1090 update_coverage_db(s);
1091#else
79bc39ab 1092 cerr << _("Coverage database not available without libsqlite3") << endl;
85007c04
DB
1093#endif
1094 }
1095
678b7381 1096 s.report_suppression();
9e1a2390 1097
0f5d597d 1098 PROBE1(stap, pass6__end, &s);
85007c04
DB
1099}
1100
44edbcd6
JS
1101static int
1102passes_0_4_again_with_server (systemtap_session &s)
1103{
1104 // Not a server and not already using a server.
1105 assert (! s.client_options);
1106 assert (s.specified_servers.empty ());
1107
1108 // Specify default server(s).
1109 s.specified_servers.push_back ("");
1110
b96901b7
CM
1111 // Reset the previous temporary directory and start fresh
1112 s.reset_tmp_dir();
44edbcd6
JS
1113
1114 // Try to compile again, using the server
b5f561be 1115 clog << _("Attempting compilation using a compile server")
44edbcd6 1116 << endl;
b96901b7 1117
44edbcd6
JS
1118 int rc = passes_0_4 (s);
1119 return rc;
1120}
1121
85007c04
DB
1122int
1123main (int argc, char * const argv [])
1124{
1125 // Initialize defaults.
b96901b7 1126 try {
891043f0 1127 systemtap_session s;
52c2652f 1128#if ENABLE_NLS
891043f0
CM
1129 setlocale (LC_ALL, "");
1130 bindtextdomain (PACKAGE, LOCALEDIR);
1131 textdomain (PACKAGE);
52c2652f 1132#endif
891043f0
CM
1133
1134 // Set up our handler to catch routine signals, to allow clean
1135 // and reasonably timely exit.
1136 setup_signals(&handle_interrupt);
1137
1138 // PR13520: Parse $SYSTEMTAP_DIR/rc for extra options
1139 string rc_file = s.data_path + "/rc";
1140 ifstream rcf (rc_file.c_str());
1141 string rcline;
1142 wordexp_t words;
1143 memset (& words, 0, sizeof(words));
1144 int rc = 0;
1145 int linecount = 0;
1146 while (getline (rcf, rcline))
1147 {
1148 rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF|
1149 (linecount > 0 ? WRDE_APPEND : 0));
1150 // NB: WRDE_APPEND automagically reallocates words.* as more options are added.
1151 linecount ++;
1152 if (rc) break;
1153 }
4eb12770
FCE
1154 rcf.close();
1155
891043f0
CM
1156 int extended_argc = words.we_wordc + argc;
1157 char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*));
1158 if (rc || !extended_argv)
1159 {
1160 clog << _F("Error processing extra options in %s", rc_file.c_str());
e2d0f787 1161 return EXIT_FAILURE;
891043f0
CM
1162 }
1163 // Copy over the arguments *by reference*, first the ones from the rc file.
1164 char **p = & extended_argv[0];
1165 *p++ = argv[0];
1166 for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i];
1167 for (int j=1; j<argc; j++) *p++ = argv[j];
1168 *p++ = NULL;
1169
1170 // Process the command line.
1171 rc = s.parse_cmdline (extended_argc, extended_argv);
1172 if (rc != 0)
e2d0f787 1173 return rc;
891043f0 1174
9fb50451
MC
1175 // Create the temp dir.
1176 s.create_tmp_dir();
1177
891043f0
CM
1178 if (words.we_wordc > 0 && s.verbose > 1)
1179 clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc);
1180
1181 // Check for options conflicts. Exits if errors are detected.
1182 s.check_options (extended_argc, extended_argv);
1183
1184 // We don't need these strings any more.
1185 wordfree (& words);
1186 free (extended_argv);
1187
1188 // arguments parsed; get down to business
1189 if (s.verbose > 1)
1190 s.version ();
1191
1192 // Need to send the verbose message here, rather than in the session ctor, since
1193 // we didn't know if verbose was set.
1194 if (rc == 0 && s.verbose>1)
1195 clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
1196
3d0a328d
JS
1197 // Run the benchmark and quit right away.
1198 if (s.benchmark_sdt_loops || s.benchmark_sdt_threads)
1199 return run_sdt_benchmark(s);
1200
891043f0
CM
1201 // Prepare connections for each specified remote target.
1202 vector<remote*> targets;
1203 bool fake_remote=false;
1204 if (s.remote_uris.empty())
1205 {
1206 fake_remote=true;
1207 s.remote_uris.push_back("direct:");
1208 }
1209 for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i)
1210 {
1211 // PR13354: pass remote id#/url only in non --remote=HOST cases
1212 remote *target = remote::create(s, s.remote_uris[i],
1213 fake_remote ? -1 : (int)i);
1214 if (target)
1215 targets.push_back(target);
1216 else
1217 rc = 1;
1218 }
3a97e514 1219
891043f0
CM
1220 // Discover and loop over each unique session created by the remote targets.
1221 set<systemtap_session*> sessions;
1222 for (unsigned i = 0; i < targets.size(); ++i)
1223 sessions.insert(targets[i]->get_session());
11a046b7
DS
1224
1225 // FIXME: For now, only attempt local interactive use.
1226 if (s.interactive_mode && fake_remote)
891043f0 1227 {
9ac12b89 1228#ifdef HAVE_LIBREADLINE
11a046b7 1229 rc = interactive_mode (s, targets);
9ac12b89 1230#endif
11a046b7
DS
1231 }
1232 else
1233 {
1234 for (set<systemtap_session*>::iterator it = sessions.begin();
1235 rc == 0 && !pending_interrupts && it != sessions.end(); ++it)
1236 {
1237 systemtap_session& ss = **it;
1238 if (ss.verbose > 1)
1239 clog << _F("Session arch: %s release: %s",
1240 ss.architecture.c_str(), ss.kernel_release.c_str())
1241 << endl;
85007c04 1242
c4fd15b4 1243#if HAVE_NSS
11a046b7
DS
1244 // If requested, query server status. This is independent
1245 // of other tasks.
1246 query_server_status (ss);
85007c04 1247
11a046b7
DS
1248 // If requested, manage trust of servers. This is
1249 // independent of other tasks.
1250 manage_server_trust (ss);
c4fd15b4 1251#endif
ebff2ed0 1252
11a046b7
DS
1253 // Run the passes only if a script has been specified or
1254 // if we're dumping something. The requirement for a
1255 // script has already been checked in
1256 // systemtap_session::check_options.
1257 if (ss.have_script || ss.dump_mode)
1258 {
1259 // Run passes 0-4 for each unique session, either
1260 // locally or using a compile-server.
1261 ss.init_try_server ();
1262 if ((rc = passes_0_4 (ss)))
1263 {
1264 // Compilation failed.
1265 // Try again using a server if appropriate.
1266 if (ss.try_server ())
1267 rc = passes_0_4_again_with_server (ss);
1268 }
1269 if (rc || s.perpass_verbose[0] >= 1)
1270 s.explain_auto_options ();
1271 }
1272 }
1273
1274 // Run pass 5, if requested
1275 if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts)
1276 rc = pass_5 (s, targets);
891043f0 1277 }
3a97e514 1278
891043f0
CM
1279 // Pass 6. Cleanup
1280 for (unsigned i = 0; i < targets.size(); ++i)
1281 delete targets[i];
1282 cleanup (s, rc);
b96901b7 1283
e19ebcf7 1284 assert_no_interrupts();
985892de 1285 return (rc) ? EXIT_FAILURE : EXIT_SUCCESS;
b96901b7 1286 }
8d4072eb 1287 catch (const interrupt_exception& e) {
985892de 1288 // User entered ctrl-c, exit quietly.
e2d0f787
JS
1289 return EXIT_FAILURE;
1290 }
1291 catch (const exit_exception& e) {
1292 // Exiting for any quiet reason.
1293 return e.rc;
985892de 1294 }
29375627
JL
1295 catch (const exception &e) {
1296 // Some other uncaught exception.
985892de 1297 cerr << e.what() << endl;
e2d0f787 1298 return EXIT_FAILURE;
985892de
CM
1299 }
1300 catch (...) {
1301 // Catch all other unknown exceptions.
1302 cerr << _("ERROR: caught unknown exception!") << endl;
e2d0f787 1303 return EXIT_FAILURE;
b96901b7 1304 }
85007c04
DB
1305}
1306
1307/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.346461 seconds and 5 git commands to generate.