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