main.cxx - systemtap
Global variables defined
Functions defined
Macros defined
Source code
#include "config.h"
#include "staptree.h"
#include "parse.h"
#include "elaborate.h"
#include "translate.h"
#include "buildrun.h"
#include "session.h"
#include "hash.h"
#include "cache.h"
#include "util.h"
#include "coveragedb.h"
#include "rpm_finder.h"
#include "task_finder.h"
#include "csclient.h"
#include "remote.h"
#include "tapsets.h"
#include "setupdwfl.h"
#if ENABLE_NLS
#include <libintl.h>
#include <locale.h>
#endif
#include "stap-probe.h"
#include <cstdlib>
extern "C" {
#include <glob.h>
#include <unistd.h>
#include <signal.h>
#include <sys/utsname.h>
#include <sys/times.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <wordexp.h>
}
using namespace std;
static void
uniq_list(list<string>& l)
{
set<string> s;
list<string>::iterator i = l.begin();
while (i != l.end())
if (s.insert(*i).second)
++i;
else
i = l.erase(i);
}
static void
printscript(systemtap_session& s, ostream& o)
{
if (s.dump_mode == systemtap_session::dump_matched_probes ||
s.dump_mode == systemtap_session::dump_matched_probes_vars)
{
map<string,set<derived_probe *> > probe_list;
for (unsigned i=0; i<s.probes.size(); i++)
{
assert_no_interrupts();
derived_probe* p = s.probes[i];
vector<probe*> chain;
p->collect_derivation_chain (chain);
if (s.verbose > 2) {
p->printsig(cerr); cerr << endl;
cerr << "chain[" << chain.size() << "]:" << endl;
for (unsigned j=0; j<chain.size(); j++)
{
cerr << " [" << j << "]: " << endl;
cerr << "\tlocations[" << chain[j]->locations.size() << "]:" << endl;
for (unsigned k=0; k<chain[j]->locations.size(); k++)
{
cerr << "\t [" << k << "]: ";
chain[j]->locations[k]->print(cerr);
cerr << endl;
}
const probe_alias *a = chain[j]->get_alias();
if (a)
{
cerr << "\taliases[" << a->alias_names.size() << "]:" << endl;
for (unsigned k=0; k<a->alias_names.size(); k++)
{
cerr << "\t [" << k << "]: ";
a->alias_names[k]->print(cerr);
cerr << endl;
}
}
}
}
const string& pp = lex_cast(*p->script_location());
if (!s.is_primary_probe(p))
continue;
probe_list[pp].insert(p);
}
for (map<string, set<derived_probe *> >::iterator it=probe_list.begin(); it!=probe_list.end(); ++it)
{
o << it->first;
if (s.dump_mode == systemtap_session::dump_matched_probes_vars)
{
map<string,unsigned> var_count; map<string,unsigned> arg_count;
list<string> var_list;
list<string> arg_list;
for (set<derived_probe *>::iterator ix=it->second.begin(); ix!=it->second.end(); ++ix)
{
derived_probe* p = *ix;
for (unsigned j=0; j<p->locals.size(); j++)
{
stringstream tmps;
vardecl* v = p->locals[j];
v->printsig (tmps);
var_count[tmps.str()]++;
var_list.push_back(tmps.str());
}
list<string> arg_set;
p->getargs(arg_set);
for (list<string>::iterator ia=arg_set.begin(); ia!=arg_set.end(); ++ia) {
arg_count[*ia]++;
arg_list.push_back(*ia);
}
}
uniq_list(arg_list);
uniq_list(var_list);
for (list<string>::iterator ir=var_list.begin(); ir!=var_list.end(); ++ir)
if (var_count.find(*ir)->second == it->second.size()) o << " " << *ir;
for (list<string>::iterator ir=arg_list.begin(); ir!=arg_list.end(); ++ir)
if (arg_count.find(*ir)->second == it->second.size()) o << " " << *ir;
}
o << endl;
}
}
else
{
if (s.embeds.size() > 0)
o << _("# global embedded code") << endl;
for (unsigned i=0; i<s.embeds.size(); i++)
{
assert_no_interrupts();
embeddedcode* ec = s.embeds[i];
ec->print (o);
o << endl;
}
if (s.globals.size() > 0)
o << _("# globals") << endl;
for (unsigned i=0; i<s.globals.size(); i++)
{
assert_no_interrupts();
vardecl* v = s.globals[i];
v->printsig (o);
if (s.verbose && v->init)
{
o << " = ";
v->init->print(o);
}
o << endl;
}
if (s.functions.size() > 0)
o << _("# functions") << endl;
for (map<string,functiondecl*>::iterator it = s.functions.begin(); it != s.functions.end(); it++)
{
assert_no_interrupts();
functiondecl* f = it->second;
f->printsig (o);
o << endl;
if (f->locals.size() > 0)
o << _(" # locals") << endl;
for (unsigned j=0; j<f->locals.size(); j++)
{
vardecl* v = f->locals[j];
o << " ";
v->printsig (o);
o << endl;
}
if (s.verbose)
{
f->body->print (o);
o << endl;
}
}
if (s.probes.size() > 0)
o << _("# probes") << endl;
for (unsigned i=0; i<s.probes.size(); i++)
{
assert_no_interrupts();
derived_probe* p = s.probes[i];
p->printsig (o);
o << endl;
if (p->locals.size() > 0)
o << _(" # locals") << endl;
for (unsigned j=0; j<p->locals.size(); j++)
{
vardecl* v = p->locals[j];
o << " ";
v->printsig (o);
o << endl;
}
if (s.verbose)
{
p->body->print (o);
o << endl;
}
}
}
}
int pending_interrupts;
extern "C"
void handle_interrupt (int sig)
{
kill_stap_spawn(SIGTERM);
pending_interrupts ++;
if (pending_interrupts > 2) XXX {
char msg[] = "Too many interrupts received, exiting.\n";
int rc = write (2, msg, sizeof(msg)-1);
if (rc) { ;}
_exit (1);
}
}
void
setup_signals (sighandler_t handler)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigemptyset (&sa.sa_mask);
if (handler != SIG_IGN)
{
sigaddset (&sa.sa_mask, SIGHUP);
sigaddset (&sa.sa_mask, SIGPIPE);
sigaddset (&sa.sa_mask, SIGINT);
sigaddset (&sa.sa_mask, SIGTERM);
sigaddset (&sa.sa_mask, SIGXFSZ);
sigaddset (&sa.sa_mask, SIGXCPU);
}
sa.sa_flags = SA_RESTART;
sigaction (SIGHUP, &sa, NULL);
sigaction (SIGPIPE, &sa, NULL);
sigaction (SIGINT, &sa, NULL);
sigaction (SIGTERM, &sa, NULL);
sigaction (SIGXFSZ, &sa, NULL);
sigaction (SIGXCPU, &sa, NULL);
}
static void*
sdt_benchmark_thread(void* p)
{
unsigned long i = *(unsigned long*)p;
PROBE(stap, benchmark__thread__start);
while (i--)
PROBE1(stap, benchmark, i);
PROBE(stap, benchmark__thread__end);
return NULL;
}
static int
run_sdt_benchmark(systemtap_session& s)
{
unsigned long loops = s.benchmark_sdt_loops ?: 10000000;
unsigned long threads = s.benchmark_sdt_threads ?: 1;
if (s.verbose > 0)
clog << _F("Beginning SDT benchmark with %lu loops in %lu threads.",
loops, threads) << endl;
struct tms tms_before, tms_after;
struct timeval tv_before, tv_after;
unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
times (& tms_before);
gettimeofday (&tv_before, NULL);
PROBE(stap, benchmark__start);
pthread_t pthreads[threads];
for (unsigned long i = 0; i < threads; ++i)
pthread_create(&pthreads[i], NULL, sdt_benchmark_thread, &loops);
for (unsigned long i = 0; i < threads; ++i)
pthread_join(pthreads[i], NULL);
PROBE(stap, benchmark__end);
times (& tms_after);
gettimeofday (&tv_after, NULL);
if (s.verbose > 0)
clog << _F("Completed SDT benchmark in %ldusr/%ldsys/%ldreal ms.",
(long)(tms_after.tms_utime - tms_before.tms_utime) * 1000 / _sc_clk_tck,
(long)(tms_after.tms_stime - tms_before.tms_stime) * 1000 / _sc_clk_tck,
(long)((tv_after.tv_sec - tv_before.tv_sec) * 1000 +
((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000))
<< endl;
return EXIT_SUCCESS;
}
static int
passes_0_4 (systemtap_session &s)
{
int rc = 0;
if (s.kernel_release.empty())
{
if (s.kernel_build_tree.empty())
cerr << _("ERROR: kernel release isn't specified") << endl;
else
cerr << _F("ERROR: kernel release isn't found in \"%s\"",
s.kernel_build_tree.c_str()) << endl;
return 1;
}
if (! s.specified_servers.empty ())
{
#if HAVE_NSS
compile_server_client client (s);
return client.passes_0_4 ();
#else
s.print_warning(_("Without NSS, using a compile-server is not supported by this version of systemtap"));
assert (! s.try_server ());
s.print_warning(_("Ignoring --use-server"));
#endif
}
s.verbose = s.perpass_verbose[0];
PROBE1(stap, pass0__start, &s);
s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
if (!s.sysroot.empty())
{
if (s.update_release_sysroot && !s.sysroot.empty())
s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
debuginfo_path_insert_sysroot(s.sysroot);
}
if (s.runtime_mode == systemtap_session::kernel_runtime) {
if ((rc = s.parse_kernel_config ()) != 0
|| (rc = s.parse_kernel_exports ()) != 0
|| (rc = s.parse_kernel_functions ()) != 0)
{
s.set_try_server ();
return rc;
}
}
s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c";
PROBE1(stap, pass0__end, &s);
struct tms tms_before;
times (& tms_before);
struct timeval tv_before;
gettimeofday (&tv_before, NULL);
PROBE1(stap, pass1a__start, &s);
struct stat user_file_stat;
int user_file_stat_rc = -1;
if (s.script_file == "-")
{
user_file_stat_rc = fstat (STDIN_FILENO, & user_file_stat);
}
else if (s.script_file != "")
{
user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
}
vector<string> version_suffixes;
if (s.runtime_mode == systemtap_session::kernel_runtime)
{
string kvr = s.kernel_release;
version_suffixes.push_back ("/" + kvr);
if (kvr != s.kernel_base_release)
{
kvr = s.kernel_base_release;
version_suffixes.push_back ("/" + kvr);
}
string::size_type dot1_index = kvr.find ('.');
string::size_type dot2_index = kvr.rfind ('.');
while (dot2_index > dot1_index && dot2_index != string::npos)
{
kvr.erase(dot2_index);
version_suffixes.push_back ("/" + kvr);
dot2_index = kvr.rfind ('.');
}
}
version_suffixes.push_back ("");
const string& arch = s.architecture;
for (unsigned i=0; i<version_suffixes.size(); i+=2)
version_suffixes.insert(version_suffixes.begin() + i,
version_suffixes[i] + "/" + arch);
string runtime_prefix;
if (s.runtime_mode == systemtap_session::kernel_runtime)
runtime_prefix = "/linux";
else if (s.runtime_mode == systemtap_session::dyninst_runtime)
runtime_prefix = "/dyninst";
if (!runtime_prefix.empty())
for (unsigned i=0; i<version_suffixes.size(); i+=2)
version_suffixes.insert(version_suffixes.begin() + i/2,
runtime_prefix + version_suffixes[i]);
set<pair<dev_t, ino_t> > seen_library_macro_files;
set<string> seen_library_macro_files_names;
for (unsigned i=0; i<s.include_path.size(); i++)
{
for (unsigned k=0; k<version_suffixes.size(); k++)
{
glob_t globbuf;
string dir = s.include_path[i] + version_suffixes[k] + "/*.stpm";
int r = glob(dir.c_str (), 0, NULL, & globbuf);
if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
rc ++;
unsigned prev_s_library_files = s.library_files.size();
for (unsigned j=0; j<globbuf.gl_pathc; j++)
{
assert_no_interrupts();
struct stat tapset_file_stat;
int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
if (stat_rc == 0 && user_file_stat_rc == 0 &&
user_file_stat.st_dev == tapset_file_stat.st_dev &&
user_file_stat.st_ino == tapset_file_stat.st_ino)
{
cerr
<< _F("usage error: macro tapset file '%s' cannot be run directly as a session script.",
globbuf.gl_pathv[j]) << endl;
rc ++;
}
if (stat_rc == 0)
{
pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
tapset_file_stat.st_ino);
if (seen_library_macro_files.find(here) != seen_library_macro_files.end()) {
if (s.verbose>2)
clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl;
continue;
}
seen_library_macro_files.insert (here);
}
string full_path = globbuf.gl_pathv[j];
string tapset_base = s.include_path[i]; if (full_path.size() > tapset_base.size()) {
string tail_part = full_path.substr(tapset_base.size());
if (seen_library_macro_files_names.find (tail_part) != seen_library_macro_files_names.end()) {
if (s.verbose>2)
clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl;
continue;
}
seen_library_macro_files_names.insert (tail_part);
}
if (s.verbose>2)
clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
stapfile* f = parse_library_macros (s, globbuf.gl_pathv[j]);
if (f == 0)
s.print_warning(_F("macro tapset \"%s\" has errors, and will be skipped.", string(globbuf.gl_pathv[j]).c_str()));
else
s.library_files.push_back (f);
}
unsigned next_s_library_files = s.library_files.size();
if (s.verbose>1 && globbuf.gl_pathc > 0)
clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u",
dir.c_str(), globbuf.gl_pathc,
(next_s_library_files-prev_s_library_files)) << endl;
globfree (&globbuf);
}
}
set<pair<dev_t, ino_t> > seen_library_files;
set<string> seen_library_files_names;
for (unsigned i=0; i<s.include_path.size(); i++)
{
unsigned tapset_flags = pf_guru | pf_squash_errors;
if (i == 0)
tapset_flags |= pf_no_compatible;
for (unsigned k=0; k<version_suffixes.size(); k++)
{
glob_t globbuf;
string dir = s.include_path[i] + version_suffixes[k] + "/*.stp";
int r = glob(dir.c_str (), 0, NULL, & globbuf);
if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
rc ++;
unsigned prev_s_library_files = s.library_files.size();
for (unsigned j=0; j<globbuf.gl_pathc; j++)
{
assert_no_interrupts();
struct stat tapset_file_stat;
int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
if (stat_rc == 0 && user_file_stat_rc == 0 &&
user_file_stat.st_dev == tapset_file_stat.st_dev &&
user_file_stat.st_ino == tapset_file_stat.st_ino)
{
cerr
<< _F("usage error: tapset file '%s' cannot be run directly as a session script.",
globbuf.gl_pathv[j]) << endl;
rc ++;
}
if (stat_rc == 0)
{
pair<dev_t,ino_t> here = make_pair(tapset_file_stat.st_dev,
tapset_file_stat.st_ino);
if (seen_library_files.find(here) != seen_library_files.end()) {
if (s.verbose>2)
clog << _F("Skipping tapset \"%s\", duplicate inode.", globbuf.gl_pathv[j]) << endl;
continue;
}
seen_library_files.insert (here);
}
string full_path = globbuf.gl_pathv[j];
string tapset_base = s.include_path[i]; if (full_path.size() > tapset_base.size()) {
string tail_part = full_path.substr(tapset_base.size());
if (seen_library_files_names.find (tail_part) != seen_library_files_names.end()) {
if (s.verbose>2)
clog << _F("Skipping tapset \"%s\", duplicate name.", globbuf.gl_pathv[j]) << endl;
continue;
}
seen_library_files_names.insert (tail_part);
}
if (s.verbose>2)
clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
stapfile* f = parse (s, globbuf.gl_pathv[j], tapset_flags);
if (f == 0)
s.print_warning(_F("tapset \"%s\" has errors, and will be skipped", string(globbuf.gl_pathv[j]).c_str()));
else
s.library_files.push_back (f);
}
unsigned next_s_library_files = s.library_files.size();
if (s.verbose>1 && globbuf.gl_pathc > 0)
clog << _F("Searched: \"%s\", found: %zu, processed: %u",
dir.c_str(), globbuf.gl_pathc,
(next_s_library_files-prev_s_library_files)) << endl;
globfree (& globbuf);
}
}
if (s.num_errors())
rc ++;
PROBE1(stap, pass1b__start, &s);
if (!s.script_file.empty() ||
!s.cmdline_script.empty() ||
s.dump_mode == systemtap_session::dump_matched_probes ||
s.dump_mode == systemtap_session::dump_matched_probes_vars)
{
unsigned user_flags = s.guru_mode ? pf_guru : 0;
if (s.script_file == "-")
{
s.user_files.push_back (parse (s, "<input>", cin, user_flags));
}
else if (s.script_file != "")
{
s.user_files.push_back (parse (s, s.script_file, user_flags));
}
else if (s.cmdline_script != "")
{
istringstream ii (s.cmdline_script);
s.user_files.push_back(parse (s, "<input>", ii, user_flags));
}
else {
istringstream ii ("probe " + s.dump_matched_pattern + " {}");
s.user_files.push_back (parse (s, "<input>", ii, user_flags));
}
unsigned count = 1;
for (vector<string>::iterator script = s.additional_scripts.begin(); script != s.additional_scripts.end(); script++)
{
string input_name = "<input" + lex_cast(count) + ">";
istringstream ii (*script);
s.user_files.push_back(parse (s, input_name, ii, user_flags));
count ++;
}
for(vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++)
{
if (!(*it))
{
rc ++;
}
}
}
if (s.dump_mode == systemtap_session::dump_probe_aliases)
{
set<string> aliases;
vector<stapfile*>::const_iterator file;
for (file = s.library_files.begin();
file != s.library_files.end(); ++file)
{
vector<probe_alias*>::const_iterator alias;
for (alias = (*file)->aliases.begin();
alias != (*file)->aliases.end(); ++alias)
{
stringstream ss;
(*alias)->printsig(ss);
string str = ss.str();
if (!s.verbose && startswith(str, "_"))
continue;
aliases.insert(str);
}
}
set<string>::iterator alias;
for (alias = aliases.begin();
alias != aliases.end(); ++alias)
{
cout << *alias << endl;
}
}
else if (rc == 0 && s.last_pass == 1)
{
cout << _("# parse tree dump") << endl;
for (vector<stapfile*>::iterator it = s.user_files.begin(); it != s.user_files.end(); it++)
(*it)->print (cout);
cout << endl;
if (s.verbose)
for (unsigned i=0; i<s.library_files.size(); i++)
{
s.library_files[i]->print (cout);
cout << endl;
}
}
struct tms tms_after;
times (& tms_after);
unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
struct timeval tv_after;
gettimeofday (&tv_after, NULL);
#define TIMESPRINT "in " << \
(tms_after.tms_cutime + tms_after.tms_utime \
- tms_before.tms_cutime - tms_before.tms_utime) * 1000 / (_sc_clk_tck) << "usr/" \
<< (tms_after.tms_cstime + tms_after.tms_stime \
- tms_before.tms_cstime - tms_before.tms_stime) * 1000 / (_sc_clk_tck) << "sys/" \
<< ((tv_after.tv_sec - tv_before.tv_sec) * 1000 + \
((long)tv_after.tv_usec - (long)tv_before.tv_usec) / 1000) << "real ms."
if (s.verbose)
{
XXX clog << "Pass 1: parsed user script and "
<< s.library_files.size()
<< " library script(s) "
<< getmemusage()
<< TIMESPRINT
<< endl;
}
if (rc && !s.dump_mode)
cerr << _("Pass 1: parse failed. [man error::pass1]") << endl;
PROBE1(stap, pass1__end, &s);
assert_no_interrupts();
if (rc || s.last_pass == 1 ||
s.dump_mode == systemtap_session::dump_probe_aliases)
return rc;
times (& tms_before);
gettimeofday (&tv_before, NULL);
s.verbose = s.perpass_verbose[1];
PROBE1(stap, pass2__start, &s);
rc = semantic_pass (s);
if (s.dump_mode == systemtap_session::dump_probe_types)
s.pattern_root->dump (s);
else if (s.dump_mode == systemtap_session::dump_functions)
{
map<string,functiondecl*>::const_iterator func;
for (func = s.functions.begin();
func != s.functions.end(); ++func)
{
functiondecl& curfunc = *func->second;
if (curfunc.synthetic)
continue;
if (!s.verbose && startswith(curfunc.name, "_"))
continue;
curfunc.printsigtags(cout, s.verbose>0 );
cout << endl;
}
}
else if (s.dump_mode == systemtap_session::dump_matched_probes ||
s.dump_mode == systemtap_session::dump_matched_probes_vars ||
(rc == 0 && s.last_pass == 2))
printscript(s, cout);
times (& tms_after);
gettimeofday (&tv_after, NULL);
if (s.verbose) clog << "Pass 2: analyzed script: "
<< s.probes.size() << " probe(s), "
<< s.functions.size() << " function(s), "
<< s.embeds.size() << " embed(s), "
<< s.globals.size() << " global(s) "
<< getmemusage()
<< TIMESPRINT
<< endl;
if (rc && !s.dump_mode && !s.try_server ())
cerr << _("Pass 2: analysis failed. [man error::pass2]") << endl;
PROBE1(stap, pass2__end, &s);
assert_no_interrupts();
if (rc || s.last_pass == 2 || s.dump_mode)
return rc;
rc = prepare_translate_pass (s);
assert_no_interrupts();
if (rc) return rc;
if (s.use_script_cache)
{
ostringstream o;
unsigned saved_verbose;
{
saved_verbose = s.verbose;
s.verbose = 3;
printscript(s, o); s.verbose = saved_verbose;
}
find_script_hash (s, o.str());
if (get_script_from_cache(s))
{
if (s.need_uprobes)
rc = uprobes_pass(s);
assert_no_interrupts();
if (rc || s.last_pass < 5) return rc;
return 0;
}
}
s.verbose = s.perpass_verbose[2];
times (& tms_before);
gettimeofday (&tv_before, NULL);
PROBE1(stap, pass3__start, &s);
rc = translate_pass (s);
if (! rc && s.last_pass == 3)
{
ifstream i (s.translated_source.c_str());
cout << i.rdbuf();
}
times (& tms_after);
gettimeofday (&tv_after, NULL);
if (s.verbose)
clog << "Pass 3: translated to C into \""
<< s.translated_source
<< "\" "
<< getmemusage()
<< TIMESPRINT
<< endl;
if (rc && ! s.try_server ())
cerr << _("Pass 3: translation failed. [man error::pass3]") << endl;
PROBE1(stap, pass3__end, &s);
assert_no_interrupts();
if (rc || s.last_pass == 3) return rc;
s.verbose = s.perpass_verbose[3];
times (& tms_before);
gettimeofday (&tv_before, NULL);
PROBE1(stap, pass4__start, &s);
if (s.use_cache)
{
find_stapconf_hash(s);
get_stapconf_from_cache(s);
}
rc = compile_pass (s);
if (! rc && s.last_pass == 4)
{
cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path);
cout << endl;
}
times (& tms_after);
gettimeofday (&tv_after, NULL);
if (s.verbose) clog << "Pass 4: compiled C into \""
<< s.module_filename()
<< "\" "
<< TIMESPRINT
<< endl;
if (rc && ! s.try_server ())
cerr << _("Pass 4: compilation failed. [man error::pass4]") << endl;
else
{
if (s.use_script_cache)
add_script_to_cache(s);
if (s.use_cache && !s.runtime_usermode_p())
add_stapconf_to_cache(s);
if (! s.use_script_cache && s.last_pass == 4)
s.save_module = true;
if (s.save_module && !pending_interrupts)
{
string module_src_path = s.tmpdir + "/" + s.module_filename();
string module_dest_path = s.module_filename();
copy_file(module_src_path, module_dest_path, s.verbose > 1);
}
if (s.save_uprobes && !s.uprobes_path.empty() && !pending_interrupts)
{
rc = create_dir("uprobes");
if (! rc)
copy_file(s.uprobes_path, "uprobes/uprobes.ko", s.verbose > 1);
}
}
PROBE1(stap, pass4__end, &s);
return rc;
}
static int
pass_5 (systemtap_session &s, vector<remote*> targets)
{
s.verbose = s.perpass_verbose[4];
struct tms tms_before;
times (& tms_before);
struct timeval tv_before;
gettimeofday (&tv_before, NULL);
PROBE1(stap, pass5__start, &s);
if (s.verbose) clog << _("Pass 5: starting run.") << endl;
int rc = remote::run(targets);
struct tms tms_after;
times (& tms_after);
unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
struct timeval tv_after;
gettimeofday (&tv_after, NULL);
if (s.verbose) clog << "Pass 5: run completed "
<< TIMESPRINT
<< endl;
if (rc)
cerr << _("Pass 5: run failed. [man error::pass5]") << endl;
else
pending_interrupts = 0;
PROBE1(stap, pass5__end, &s);
return rc;
}
static void
cleanup (systemtap_session &s, int rc)
{
PROBE1(stap, pass6__start, &s);
for (systemtap_session::session_map_t::iterator it = s.subsessions.begin();
it != s.subsessions.end(); ++it)
cleanup (*it->second, rc);
if (!rc && s.tapset_compile_coverage && !pending_interrupts) {
#ifdef HAVE_LIBSQLITE3
update_coverage_db(s);
#else
cerr << _("Coverage database not available without libsqlite3") << endl;
#endif
}
s.report_suppression();
PROBE1(stap, pass6__end, &s);
}
static int
passes_0_4_again_with_server (systemtap_session &s)
{
assert (! s.client_options);
assert (s.specified_servers.empty ());
s.specified_servers.push_back ("");
s.reset_tmp_dir();
clog << _("Attempting compilation using a compile server")
<< endl;
int rc = passes_0_4 (s);
return rc;
}
int
main (int argc, char * const argv [])
{
try {
systemtap_session s;
#if ENABLE_NLS
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
#endif
setup_signals(&handle_interrupt);
string rc_file = s.data_path + "/rc";
ifstream rcf (rc_file.c_str());
string rcline;
wordexp_t words;
memset (& words, 0, sizeof(words));
int rc = 0;
int linecount = 0;
while (getline (rcf, rcline))
{
rc = wordexp (rcline.c_str(), & words, WRDE_NOCMD|WRDE_UNDEF|
(linecount > 0 ? WRDE_APPEND : 0));
linecount ++;
if (rc) break;
}
int extended_argc = words.we_wordc + argc;
char **extended_argv = (char**) calloc (extended_argc + 1, sizeof(char*));
if (rc || !extended_argv)
{
clog << _F("Error processing extra options in %s", rc_file.c_str());
return EXIT_FAILURE;
}
char **p = & extended_argv[0];
*p++ = argv[0];
for (unsigned i=0; i<words.we_wordc; i++) *p++ = words.we_wordv[i];
for (int j=1; j<argc; j++) *p++ = argv[j];
*p++ = NULL;
rc = s.parse_cmdline (extended_argc, extended_argv);
if (rc != 0)
return rc;
if (words.we_wordc > 0 && s.verbose > 1)
clog << _F("Extra options in %s: %d\n", rc_file.c_str(), (int)words.we_wordc);
s.check_options (extended_argc, extended_argv);
wordfree (& words);
free (extended_argv);
if (s.verbose > 1)
s.version ();
if (rc == 0 && s.verbose>1)
clog << _F("Created temporary directory \"%s\"", s.tmpdir.c_str()) << endl;
if (s.benchmark_sdt_loops || s.benchmark_sdt_threads)
return run_sdt_benchmark(s);
vector<remote*> targets;
bool fake_remote=false;
if (s.remote_uris.empty())
{
fake_remote=true;
s.remote_uris.push_back("direct:");
}
for (unsigned i = 0; rc == 0 && i < s.remote_uris.size(); ++i)
{
remote *target = remote::create(s, s.remote_uris[i],
fake_remote ? -1 : (int)i);
if (target)
targets.push_back(target);
else
rc = 1;
}
set<systemtap_session*> sessions;
for (unsigned i = 0; i < targets.size(); ++i)
sessions.insert(targets[i]->get_session());
for (set<systemtap_session*>::iterator it = sessions.begin();
rc == 0 && !pending_interrupts && it != sessions.end(); ++it)
{
systemtap_session& ss = **it;
if (ss.verbose > 1)
clog << _F("Session arch: %s release: %s",
ss.architecture.c_str(), ss.kernel_release.c_str()) << endl;
#if HAVE_NSS
query_server_status (ss);
manage_server_trust (ss);
#endif
if (ss.have_script || ss.dump_mode)
{
ss.init_try_server ();
if ((rc = passes_0_4 (ss)))
{
if (ss.try_server ())
rc = passes_0_4_again_with_server (ss);
}
if (rc || s.perpass_verbose[0] >= 1)
s.explain_auto_options ();
}
}
if (rc == 0 && s.have_script && s.last_pass >= 5 && ! pending_interrupts)
rc = pass_5 (s, targets);
for (unsigned i = 0; i < targets.size(); ++i)
delete targets[i];
cleanup (s, rc);
assert_no_interrupts();
return (rc) ? EXIT_FAILURE : EXIT_SUCCESS;
}
catch (const interrupt_exception& e) {
return EXIT_FAILURE;
}
catch (const exit_exception& e) {
return e.rc;
}
catch (const exception &e) {
cerr << e.what() << endl;
return EXIT_FAILURE;
}
catch (...) {
cerr << _("ERROR: caught unknown exception!") << endl;
return EXIT_FAILURE;
}
}