1 // systemtap translator/driver
2 // Copyright (C) 2005-2010 Red Hat Inc.
3 // Copyright (C) 2005 IBM Corp.
4 // Copyright (C) 2006 Intel Corporation.
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
14 #include "elaborate.h"
15 #include "translate.h"
21 #include "coveragedb.h"
22 #include "rpm_finder.h"
23 #include "task_finder.h"
27 #include "stap-probe.h"
35 #include <sys/utsname.h>
36 #include <sys/times.h>
46 uniq_list(list
<string
>& l
)
49 list
<string
>::iterator i
= l
.begin();
51 if (s
.insert(*i
).second
)
58 printscript(systemtap_session
& s
, ostream
& o
)
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
;
66 // Pre-process the probe alias
67 for (unsigned i
=0; i
<s
.probes
.size(); i
++)
69 if (pending_interrupts
) return;
71 derived_probe
* p
= s
.probes
[i
];
72 // NB: p->basest() is not so interesting;
73 // p->almost_basest() doesn't quite work, so ...
75 p
->collect_derivation_chain (chain
);
76 probe
* second
= (chain
.size()>1) ? chain
[chain
.size()-2] : chain
[0];
79 p
->printsig(cerr
); cerr
<< endl
;
80 cerr
<< "chain[" << chain
.size() << "]:" << endl
;
81 for (unsigned j
=0; j
<chain
.size(); j
++)
83 cerr
<< " [" << j
<< "]: " << endl
;
84 cerr
<< "\tlocations[" << chain
[j
]->locations
.size() << "]:" << endl
;
85 for (unsigned k
=0; k
<chain
[j
]->locations
.size(); k
++)
87 cerr
<< "\t [" << k
<< "]: ";
88 chain
[j
]->locations
[k
]->print(cerr
);
91 const probe_alias
*a
= chain
[j
]->get_alias();
94 cerr
<< "\taliases[" << a
->alias_names
.size() << "]:" << endl
;
95 for (unsigned k
=0; k
<a
->alias_names
.size(); k
++)
97 cerr
<< "\t [" << k
<< "]: ";
98 a
->alias_names
[k
]->print(cerr
);
106 const probe_alias
*a
= second
->get_alias();
109 assert (a
->alias_names
.size() >= 1);
110 a
->alias_names
[0]->print(tmps
); // XXX: [0] is arbitrary; perhaps print all
114 assert (second
->locations
.size() >= 1);
115 second
->locations
[0]->print(tmps
); // XXX: [0] is less arbitrary here, but still ...
117 string pp
= tmps
.str();
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
);
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
)
128 o
<< it
->first
; // probe name or alias
130 // Print the locals and arguments for -L mode only
131 if (s
.listing_mode_vars
)
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
)
140 derived_probe
* p
= *ix
;
141 // collect available locals of the probe
142 for (unsigned j
=0; j
<p
->locals
.size(); j
++)
145 vardecl
* v
= p
->locals
[j
];
147 var_count
[tmps
.str()]++;
148 var_list
.push_back(tmps
.str());
150 // collect arguments of the probe if there
151 list
<string
> arg_set
;
153 for (list
<string
>::iterator ia
=arg_set
.begin(); ia
!=arg_set
.end(); ++ia
) {
155 arg_list
.push_back(*ia
);
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
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
175 if (s
.embeds
.size() > 0)
176 o
<< "# global embedded code" << endl
;
177 for (unsigned i
=0; i
<s
.embeds
.size(); i
++)
179 if (pending_interrupts
) return;
180 embeddedcode
* ec
= s
.embeds
[i
];
185 if (s
.globals
.size() > 0)
186 o
<< "# globals" << endl
;
187 for (unsigned i
=0; i
<s
.globals
.size(); i
++)
189 if (pending_interrupts
) return;
190 vardecl
* v
= s
.globals
[i
];
192 if (s
.verbose
&& v
->init
)
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
++)
204 if (pending_interrupts
) return;
205 functiondecl
* f
= it
->second
;
208 if (f
->locals
.size() > 0)
209 o
<< " # locals" << endl
;
210 for (unsigned j
=0; j
<f
->locals
.size(); j
++)
212 vardecl
* v
= f
->locals
[j
];
224 if (s
.probes
.size() > 0)
225 o
<< "# probes" << endl
;
226 for (unsigned i
=0; i
<s
.probes
.size(); i
++)
228 if (pending_interrupts
) return;
229 derived_probe
* p
= s
.probes
[i
];
232 if (p
->locals
.size() > 0)
233 o
<< " # locals" << endl
;
234 for (unsigned j
=0; j
<p
->locals
.size(); j
++)
236 vardecl
* v
= p
->locals
[j
];
251 int pending_interrupts
;
254 void handle_interrupt (int sig
)
256 kill_stap_spawn(sig
);
257 pending_interrupts
++;
258 if (pending_interrupts
> 1) // XXX: should be configurable? time-based?
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. */ ;}
269 setup_signals (sighandler_t handler
)
273 sa
.sa_handler
= handler
;
274 sigemptyset (&sa
.sa_mask
);
275 if (handler
!= SIG_IGN
)
277 sigaddset (&sa
.sa_mask
, SIGHUP
);
278 sigaddset (&sa
.sa_mask
, SIGPIPE
);
279 sigaddset (&sa
.sa_mask
, SIGINT
);
280 sigaddset (&sa
.sa_mask
, SIGTERM
);
282 sa
.sa_flags
= SA_RESTART
;
284 sigaction (SIGHUP
, &sa
, NULL
);
285 sigaction (SIGPIPE
, &sa
, NULL
);
286 sigaction (SIGINT
, &sa
, NULL
);
287 sigaction (SIGTERM
, &sa
, NULL
);
290 int parse_kernel_config (systemtap_session
&s
)
292 // PR10702: pull config options
293 string kernel_config_file
= s
.kernel_build_tree
+ "/.config";
295 int rc
= stat(kernel_config_file
.c_str(), &st
);
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");
304 ifstream
kcf (kernel_config_file
.c_str());
306 while (getline (kcf
, line
))
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
;
316 clog
<< "Parsed kernel \"" << kernel_config_file
<< "\", number of tuples: " << s
.kernel_config
.size() << endl
;
323 int parse_kernel_exports (systemtap_session
&s
)
325 string kernel_exports_file
= s
.kernel_build_tree
+ "/Module.symvers";
327 int rc
= stat(kernel_exports_file
.c_str(), &st
);
330 clog
<< "Checking \"" << kernel_exports_file
<< "\" failed: " << strerror(errno
) << endl
331 << "Ensure kernel development headers & makefiles are installed." << endl
;
335 ifstream
kef (kernel_exports_file
.c_str());
337 while (getline (kef
, line
))
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]);
347 clog
<< "Parsed kernel \"" << kernel_exports_file
<< "\", number of vmlinux exports: " << s
.kernel_exports
.size() << endl
;
355 create_temp_dir (systemtap_session
&s
)
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");
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());
370 const char* e
= strerror (errno
);
371 cerr
<< "ERROR: cannot create temporary directory (\"" << tmpdirt
<< "\"): " << e
<< endl
;
375 s
.tmpdir
= tmpdir_name
;
378 clog
<< "Created temporary directory \"" << s
.tmpdir
<< "\"" << endl
;
382 remove_temp_dir (systemtap_session
&s
)
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
;
392 // Ignore signals while we're deleting the temporary directory.
393 setup_signals (SIG_IGN
);
395 // Remove the temporary directory.
396 string cleanupcmd
= "rm -rf ";
397 cleanupcmd
+= s
.tmpdir
;
399 (void) stap_system (s
.verbose
, cleanupcmd
);
405 passes_0_4 (systemtap_session
&s
)
409 // Create a temporary directory to build within.
410 // Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end.
413 // Perform passes 0 through 4 using a compile server?
414 if (! s
.specified_servers
.empty ())
417 compile_server_client
client (s
);
418 return client
.passes_0_4 ();
420 cerr
<< "WARNING: Without NSS, using a compile-server is not supported by this version of systemtap" << endl
;
424 // PASS 0: setting up
425 s
.verbose
= s
.perpass_verbose
[0];
426 PROBE1(stap
, pass0__start
, &s
);
429 // For PR1477, we used to override $PATH and $LC_ALL and other stuff
430 // here. We seem to use complete pathnames in
431 // buildrun.cxx/tapsets.cxx now, so this is not necessary. Further,
432 // it interferes with util.cxx:find_executable(), used for $PATH
435 s
.kernel_base_release
.assign(s
.kernel_release
, 0, s
.kernel_release
.find('-'));
437 // arguments parsed; get down to business
441 clog
<< "Session arch: " << s
.architecture
442 << " release: " << s
.kernel_release
446 // Now that no further changes to s.kernel_build_tree can occur, let's use it.
447 if (parse_kernel_config (s
) != 0)
450 if (parse_kernel_exports (s
) != 0)
454 // Create the name of the C source file within the temporary
456 s
.translated_source
= string(s
.tmpdir
) + "/" + s
.module_name
+ ".c";
458 // Set up our handler to catch routine signals, to allow clean
459 // and reasonably timely exit.
460 setup_signals(&handle_interrupt
);
462 PROBE1(stap
, pass0__end
, &s
);
464 struct tms tms_before
;
465 times (& tms_before
);
466 struct timeval tv_before
;
467 gettimeofday (&tv_before
, NULL
);
469 // PASS 1a: PARSING USER SCRIPT
470 PROBE1(stap
, pass1a__start
, &s
);
472 struct stat user_file_stat
;
473 int user_file_stat_rc
= -1;
475 if (s
.script_file
== "-")
477 s
.user_file
= parse (s
, cin
, s
.guru_mode
);
478 user_file_stat_rc
= fstat (STDIN_FILENO
, & user_file_stat
);
480 else if (s
.script_file
!= "")
482 s
.user_file
= parse (s
, s
.script_file
, s
.guru_mode
);
483 user_file_stat_rc
= stat (s
.script_file
.c_str(), & user_file_stat
);
487 istringstream
ii (s
.cmdline_script
);
488 s
.user_file
= parse (s
, ii
, s
.guru_mode
);
490 if (s
.user_file
== 0)
491 // syntax errors already printed
494 // Construct arch / kernel-versioning search path
495 vector
<string
> version_suffixes
;
496 string kvr
= s
.kernel_release
;
497 const string
& arch
= s
.architecture
;
498 // add full kernel-version-release (2.6.NN-FOOBAR) + arch
499 version_suffixes
.push_back ("/" + kvr
+ "/" + arch
);
500 version_suffixes
.push_back ("/" + kvr
);
501 // add kernel version (2.6.NN) + arch
502 if (kvr
!= s
.kernel_base_release
) {
503 kvr
= s
.kernel_base_release
;
504 version_suffixes
.push_back ("/" + kvr
+ "/" + arch
);
505 version_suffixes
.push_back ("/" + kvr
);
507 // add kernel family (2.6) + arch
508 string::size_type dot1_index
= kvr
.find ('.');
509 string::size_type dot2_index
= kvr
.rfind ('.');
510 while (dot2_index
> dot1_index
&& dot2_index
!= string::npos
) {
511 kvr
.erase(dot2_index
);
512 version_suffixes
.push_back ("/" + kvr
+ "/" + arch
);
513 version_suffixes
.push_back ("/" + kvr
);
514 dot2_index
= kvr
.rfind ('.');
516 // add architecture search path
517 version_suffixes
.push_back("/" + arch
);
518 // add empty string as last element
519 version_suffixes
.push_back ("");
521 // PASS 1b: PARSING LIBRARY SCRIPTS
522 PROBE1(stap
, pass1b__start
, &s
);
524 set
<pair
<dev_t
, ino_t
> > seen_library_files
;
526 for (unsigned i
=0; i
<s
.include_path
.size(); i
++)
528 // now iterate upon it
529 for (unsigned k
=0; k
<version_suffixes
.size(); k
++)
532 string dir
= s
.include_path
[i
] + version_suffixes
[k
] + "/*.stp";
533 int r
= glob(dir
.c_str (), 0, NULL
, & globbuf
);
534 if (r
== GLOB_NOSPACE
|| r
== GLOB_ABORTED
)
536 // GLOB_NOMATCH is acceptable
538 unsigned prev_s_library_files
= s
.library_files
.size();
540 for (unsigned j
=0; j
<globbuf
.gl_pathc
; j
++)
542 if (pending_interrupts
)
545 struct stat tapset_file_stat
;
546 int stat_rc
= stat (globbuf
.gl_pathv
[j
], & tapset_file_stat
);
547 if (stat_rc
== 0 && user_file_stat_rc
== 0 &&
548 user_file_stat
.st_dev
== tapset_file_stat
.st_dev
&&
549 user_file_stat
.st_ino
== tapset_file_stat
.st_ino
)
551 cerr
<< "usage error: tapset file '" << globbuf
.gl_pathv
[j
]
552 << "' cannot be run directly as a session script." << endl
;
556 // PR11949: duplicate-eliminate tapset files
559 pair
<dev_t
,ino_t
> here
= make_pair(tapset_file_stat
.st_dev
,
560 tapset_file_stat
.st_ino
);
561 if (seen_library_files
.find(here
) != seen_library_files
.end())
563 seen_library_files
.insert (here
);
566 // XXX: privilege only for /usr/share/systemtap?
567 stapfile
* f
= parse (s
, globbuf
.gl_pathv
[j
], true);
568 if (f
== 0 && !s
.suppress_warnings
)
569 s
.print_warning("tapset '" + string(globbuf
.gl_pathv
[j
])
570 + "' has errors, and will be skipped.");
572 s
.library_files
.push_back (f
);
575 unsigned next_s_library_files
= s
.library_files
.size();
576 if (s
.verbose
>1 && globbuf
.gl_pathc
> 0)
577 clog
<< "Searched \"" << dir
<< "\","
578 << " found " << globbuf
.gl_pathc
579 << " processed " << (next_s_library_files
-prev_s_library_files
) << endl
;
581 globfree (& globbuf
);
587 if (rc
== 0 && s
.last_pass
== 1)
589 cout
<< "# parse tree dump" << endl
;
590 s
.user_file
->print (cout
);
593 for (unsigned i
=0; i
<s
.library_files
.size(); i
++)
595 s
.library_files
[i
]->print (cout
);
600 struct tms tms_after
;
602 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
603 struct timeval tv_after
;
604 gettimeofday (&tv_after
, NULL
);
606 #define TIMESPRINT "in " << \
607 (tms_after.tms_cutime + tms_after.tms_utime \
608 - tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
609 << (tms_after.tms_cstime + tms_after.tms_stime \
610 - tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
611 << ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
612 ((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
614 // syntax errors, if any, are already printed
617 clog
<< "Pass 1: parsed user script and "
618 << s
.library_files
.size()
619 << " library script(s) "
625 if (rc
&& !s
.listing_mode
)
626 cerr
<< "Pass 1: parse failed. "
627 << "Try again with another '--vp 1' option."
630 PROBE1(stap
, pass1__end
, &s
);
632 if (rc
|| s
.last_pass
== 1 || pending_interrupts
) return rc
;
634 times (& tms_before
);
635 gettimeofday (&tv_before
, NULL
);
637 // PASS 2: ELABORATION
638 s
.verbose
= s
.perpass_verbose
[1];
639 PROBE1(stap
, pass2__start
, &s
);
640 rc
= semantic_pass (s
);
642 if (s
.listing_mode
|| (rc
== 0 && s
.last_pass
== 2))
643 printscript(s
, cout
);
646 gettimeofday (&tv_after
, NULL
);
648 if (s
.verbose
) clog
<< "Pass 2: analyzed script: "
649 << s
.probes
.size() << " probe(s), "
650 << s
.functions
.size() << " function(s), "
651 << s
.embeds
.size() << " embed(s), "
652 << s
.globals
.size() << " global(s) "
657 if (rc
&& !s
.listing_mode
)
658 cerr
<< "Pass 2: analysis failed. "
659 << "Try again with another '--vp 01' option."
662 /* Print out list of missing files. XXX should be "if (rc)" ? */
663 missing_rpm_list_print(s
,"-debuginfo");
665 PROBE1(stap
, pass2__end
, &s
);
667 if (rc
|| s
.listing_mode
|| s
.last_pass
== 2 || pending_interrupts
) return rc
;
669 rc
= prepare_translate_pass (s
);
670 if (rc
|| pending_interrupts
) return rc
;
672 // Generate hash. There isn't any point in generating the hash
673 // if last_pass is 2, since we'll quit before using it.
674 if (s
.use_script_cache
)
677 unsigned saved_verbose
;
680 // Make sure we're in verbose mode, so that printscript()
681 // will output function/probe bodies.
682 saved_verbose
= s
.verbose
;
684 printscript(s
, o
); // Print script to 'o'
685 s
.verbose
= saved_verbose
;
689 find_script_hash (s
, o
.str());
691 // See if we can use cached source/module.
692 if (get_script_from_cache(s
))
694 // If our last pass isn't 5, we're done (since passes 3 and
695 // 4 just generate what we just pulled out of the cache).
696 if (s
.last_pass
< 5 || pending_interrupts
) return rc
;
698 // Short-circuit to pass 5.
703 // PASS 3: TRANSLATION
704 s
.verbose
= s
.perpass_verbose
[2];
705 times (& tms_before
);
706 gettimeofday (&tv_before
, NULL
);
707 PROBE1(stap
, pass3__start
, &s
);
709 rc
= translate_pass (s
);
711 if (rc
== 0 && s
.last_pass
== 3)
713 ifstream
i (s
.translated_source
.c_str());
718 gettimeofday (&tv_after
, NULL
);
720 if (s
.verbose
) clog
<< "Pass 3: translated to C into \""
721 << s
.translated_source
728 cerr
<< "Pass 3: translation failed. "
729 << "Try again with another '--vp 001' option."
732 PROBE1(stap
, pass3__end
, &s
);
734 if (rc
|| s
.last_pass
== 3 || pending_interrupts
) return rc
;
736 // PASS 4: COMPILATION
737 s
.verbose
= s
.perpass_verbose
[3];
738 times (& tms_before
);
739 gettimeofday (&tv_before
, NULL
);
740 PROBE1(stap
, pass4__start
, &s
);
744 find_stapconf_hash(s
);
745 get_stapconf_from_cache(s
);
747 rc
= compile_pass (s
);
749 if (rc
== 0 && s
.last_pass
== 4)
751 cout
<< ((s
.hash_path
== "") ? (s
.module_name
+ string(".ko")) : s
.hash_path
);
756 gettimeofday (&tv_after
, NULL
);
758 if (s
.verbose
) clog
<< "Pass 4: compiled C into \""
759 << s
.module_name
<< ".ko"
765 cerr
<< "Pass 4: compilation failed. "
766 << "Try again with another '--vp 0001' option."
770 // Update cache. Cache cleaning is kicked off at the beginning of this function.
771 if (s
.use_script_cache
)
772 add_script_to_cache(s
);
774 add_stapconf_to_cache(s
);
776 // We may need to save the module in $CWD if the cache was
777 // inaccessible for some reason.
778 if (! s
.use_script_cache
&& s
.last_pass
== 4)
779 s
.save_module
= true;
781 // Copy module to the current directory.
782 if (s
.save_module
&& !pending_interrupts
)
784 string module_src_path
= s
.tmpdir
+ "/" + s
.module_name
+ ".ko";
785 string module_dest_path
= s
.module_name
+ ".ko";
786 copy_file(module_src_path
, module_dest_path
, s
.verbose
> 1);
790 PROBE1(stap
, pass4__end
, &s
);
796 pass_5 (systemtap_session
&s
, vector
<remote
*> targets
)
799 s
.verbose
= s
.perpass_verbose
[4];
800 struct tms tms_before
;
801 times (& tms_before
);
802 struct timeval tv_before
;
803 gettimeofday (&tv_before
, NULL
);
804 // NB: this message is a judgement call. The other passes don't emit
805 // a "hello, I'm starting" message, but then the others aren't interactive
806 // and don't take an indefinite amount of time.
807 PROBE1(stap
, pass5__start
, &s
);
808 if (s
.verbose
) clog
<< "Pass 5: starting run." << endl
;
809 int rc
= 0; // XXX with multiple targets, need to deal with partial failure
810 for (unsigned i
= 0; i
< targets
.size() && !pending_interrupts
; ++i
)
811 rc
|= targets
[i
]->start();
812 for (unsigned i
= 0; i
< targets
.size(); ++i
)
813 rc
|= targets
[i
]->finish();
814 struct tms tms_after
;
816 unsigned _sc_clk_tck
= sysconf (_SC_CLK_TCK
);
817 struct timeval tv_after
;
818 gettimeofday (&tv_after
, NULL
);
819 if (s
.verbose
) clog
<< "Pass 5: run completed "
824 cerr
<< "Pass 5: run failed. "
825 << "Try again with another '--vp 00001' option."
828 // Interrupting pass-5 to quit is normal, so we want an EXIT_SUCCESS below.
829 pending_interrupts
= 0;
831 PROBE1(stap
, pass5__end
, &s
);
837 cleanup (systemtap_session
&s
, int rc
)
839 // PASS 6: cleaning up
840 PROBE1(stap
, pass6__start
, &s
);
842 for (systemtap_session::session_map_t::iterator it
= s
.subsessions
.begin();
843 it
!= s
.subsessions
.end(); ++it
)
844 cleanup (*it
->second
, rc
);
846 // update the database information
847 if (!rc
&& s
.tapset_compile_coverage
&& !pending_interrupts
) {
848 #ifdef HAVE_LIBSQLITE3
849 update_coverage_db(s
);
851 cerr
<< "Coverage database not available without libsqlite3" << endl
;
855 // Clean up temporary directory. Obviously, be careful with this.
858 PROBE1(stap
, pass6__end
, &s
);
862 main (int argc
, char * const argv
[])
864 // Initialize defaults.
867 // Process the command line.
868 int rc
= s
.parse_cmdline (argc
, argv
);
872 // Check for options conflicts. Exits if errors are detected.
873 s
.check_options (argc
, argv
);
875 // If requested, query server status. This is independent of other tasks.
876 query_server_status (s
);
878 // If requested, manage trust of servers. This is independent of other tasks.
879 manage_server_trust (s
);
881 // Run the passes only if a script has been specified. The requirement for
882 // a script has already been checked in systemtap_session::check_options.
885 vector
<remote
*> targets
;
886 if (s
.remote_uris
.empty())
888 remote
* target
= remote::create(s
, "direct");
890 targets
.push_back(target
);
895 for (unsigned i
= 0; i
< s
.remote_uris
.size(); ++i
)
897 remote
*target
= remote::create(s
, s
.remote_uris
[i
]);
899 targets
.push_back(target
);
907 // Run passes 0-4 for each unique session,
908 // either locally or using a compile-server.
911 set
<systemtap_session
*> sessions
;
912 for (unsigned i
= 0; i
< targets
.size(); ++i
)
913 sessions
.insert(targets
[i
]->get_session());
914 for (set
<systemtap_session
*>::iterator it
= sessions
.begin();
915 it
!= sessions
.end(); ++it
)
916 if ((rc
= passes_0_4 (**it
)))
920 // Run pass 5, if requested
921 if (rc
== 0 && s
.last_pass
>= 5 && ! pending_interrupts
)
922 rc
= pass_5 (s
, targets
);
924 for (unsigned i
= 0; i
< targets
.size(); ++i
)
931 return (rc
||pending_interrupts
) ? EXIT_FAILURE
: EXIT_SUCCESS
;
934 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */