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