This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: pre-compiled systemtap modules (try 2)
Eugeniy Meshcheryakov wrote:
13 ??????? 2006 ? 13:12 -0500 David Smith ???????(-??):
On Tue, 2006-09-12 at 22:06 -0400, Martin Hunt wrote:
On Tue, 2006-09-12 at 16:39 -0500, David Smith wrote:
1) Command-line interface. To make this easy for a user to do, we need
to modify the stap command to save a kernel module and run an existing
one. I've attached an updated patch that modifies the systemtap front
end to take 2 new options:
-S DIR Save the compiled module in DIR
-P PRE_COMPILED_MODULE
Run pre-compiled module
Instead of "-P", why not have stap just realize it's been given a module
and it automatically does the right thing?
Hmm. You do have a point here, because with the patch it is possible to
do something like stupid like "stap -P foo.ko bar.stp".
Can't systemtap just check if there is ELF signature at the begining of
the file?
Here's an updated version of the patch that does just that. So, the
'-P' option has been removed.
Note however that it doesn't try to differentiate between a kernel
module and a regular elf executable.
--
David Smith
dsmith@redhat.com
Red Hat, Inc.
http://www.redhat.com
256.217.0141 (direct)
256.837.0057 (fax)
Index: buildrun.cxx
===================================================================
RCS file: /cvs/systemtap/src/buildrun.cxx,v
retrieving revision 1.26
diff -u -p -r1.26 buildrun.cxx
--- buildrun.cxx 13 Sep 2006 22:46:45 -0000 1.26
+++ buildrun.cxx 14 Sep 2006 15:48:12 -0000
@@ -144,7 +144,10 @@ run_pass (systemtap_session& s)
if (s.buffer_size)
stpd_cmd += "-b " + stringify(s.buffer_size) + " ";
- stpd_cmd += s.tmpdir + "/" + s.module_name + ".ko";
+ if (s.pre_compiled_mode)
+ stpd_cmd += s.module_name;
+ else
+ stpd_cmd += s.tmpdir + "/" + s.module_name + ".ko";
if (s.verbose>1) clog << "Running " << stpd_cmd << endl;
Index: main.cxx
===================================================================
RCS file: /cvs/systemtap/src/main.cxx,v
retrieving revision 1.52
diff -u -p -r1.52 main.cxx
--- main.cxx 12 Sep 2006 22:05:48 -0000 1.52
+++ main.cxx 14 Sep 2006 15:48:12 -0000
@@ -26,8 +26,11 @@ extern "C" {
#include <glob.h>
#include <unistd.h>
#include <sys/utsname.h>
+#include <sys/stat.h>
#include <sys/times.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <fcntl.h>
#include <time.h>
#include <elfutils/libdwfl.h>
}
@@ -52,7 +55,7 @@ usage (systemtap_session& s, int exitcod
version ();
clog
<< endl
- << "Usage: stap [options] FILE Run script in file."
+ << "Usage: stap [options] FILE Run script or pre-compiled module."
<< endl
<< " or: stap [options] - Run script on stdin."
<< endl
@@ -94,6 +97,7 @@ usage (systemtap_session& s, int exitcod
<< endl
<< " -x PID sets target() to PID" << endl
<< " -t benchmarking timing information generated" << endl
+ << " -S DIR Save the compiled module in DIR" << endl
;
// -d: dump safety-related external references
@@ -113,12 +117,59 @@ stringify(T t)
}
+// Is a file an elf file?
+bool
+elf_file (systemtap_session& s, const string& file)
+{
+ bool rc = false;
+
+ // Before we start tell the ELF library which version we are using.
+ elf_version (EV_CURRENT);
+
+ // Open the file.
+ int fd = open (file.c_str(), O_RDONLY);
+ if (fd == -1)
+ {
+ clog << "Cannot open file " << file << ": " << strerror(errno) << endl;
+ usage (s, 1);
+ }
+
+ // Create an 'Elf' descriptor.
+ Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ if (elf == NULL)
+ {
+ clog << "Cannot generate Elf descriptor: " << elf_errmsg (-1) << endl;
+ usage (s, 1);
+ }
+ else
+ {
+ Elf_Kind kind = elf_kind (elf);
+
+ // Is it an elf file?
+ if (kind == ELF_K_ELF)
+ rc = true;
+
+ // Now we can close the descriptor.
+ if (elf_end (elf) != 0)
+ {
+ clog << "Error while closing Elf descriptor: " << elf_errmsg (-1)
+ << endl;
+ usage (s, 1);
+ }
+ }
+
+ close (fd);
+ return rc;
+}
+
+
int
main (int argc, char * const argv [])
{
string cmdline_script; // -e PROGRAM
string script_file; // FILE
bool have_script = false;
+ bool added_include_dirs = false;
// Initialize defaults
systemtap_session s;
@@ -140,6 +191,8 @@ main (int argc, char * const argv [])
s.target_pid = 0;
s.merge=true;
s.perfmon=0;
+ s.pre_compiled_mode = false;
+ s.saved_module_dir = "";
const char* s_p = getenv ("SYSTEMTAP_TAPSET");
if (s_p != NULL)
@@ -161,7 +214,7 @@ main (int argc, char * const argv [])
while (true)
{
- int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgc:x:D:bs:u");
+ int grc = getopt (argc, argv, "hVMvtp:I:e:o:R:r:m:kgc:x:D:bs:uP:S:");
if (grc < 0)
break;
switch (grc)
@@ -193,6 +246,7 @@ main (int argc, char * const argv [])
case 'I':
s.include_path.push_back (string (optarg));
+ added_include_dirs = true;
break;
case 'e':
@@ -259,6 +313,20 @@ main (int argc, char * const argv [])
s.macros.push_back (string (optarg));
break;
+ case 'S':
+ s.saved_module_dir = string (optarg);
+ {
+ struct stat st;
+ int rc = stat(s.saved_module_dir.c_str(), &st);
+ if (rc != 0)
+ {
+ clog << "Saved module directory " << s.saved_module_dir
+ << " check failed: " << strerror(errno) << endl;
+ usage (s, 1);
+ }
+ }
+ break;
+
case 'h':
usage (s, 0);
break;
@@ -283,23 +351,99 @@ main (int argc, char * const argv [])
for (int i = optind; i < argc; i++)
{
- if (! have_script)
+ if (! have_script && ! s.pre_compiled_mode)
{
- script_file = string (argv[i]);
- have_script = true;
- }
+ string file(argv[i]);
+ if (file != "-" && elf_file (s, file))
+ {
+ s.module_name = file;
+ s.pre_compiled_mode = true;
+ }
+ else
+ {
+ script_file = file;
+ have_script = true;
+ }
+ }
else
s.args.push_back (string (argv[i]));
}
// need a user file
- if (! have_script)
+ if (! have_script && ! s.pre_compiled_mode)
{
- cerr << "A script must be specified." << endl;
+ cerr << "A script or pre-compiled module must be specified." << endl;
usage(s, 1);
}
+ if (s.pre_compiled_mode)
+ {
+ // There isn't any point in specifying '-D' with a pre-compiled
+ // module since the compilation has already occurred.
+ if (s.macros.size() != 0)
+ {
+ cerr << "You can't specify the -D option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ // There isn't any point in specifying '-I' with a pre-compiled
+ // module since the compilation has already occurred.
+ if (added_include_dirs)
+ {
+ cerr << "You can't specify the -I option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ // There isn't any point in specifying '-g' with a pre-compiled
+ // module since the compilation has already occurred.
+ if (s.guru_mode)
+ {
+ cerr << "You can't specify the -g option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ // There isn't any point in specifying '-u' with a pre-compiled
+ // module since the compilation has already occurred.
+ if (s.unoptimized)
+ {
+ cerr << "You can't specify the -u option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ // There isn't any point in specifying '-k' with a pre-compiled
+ // module since there is no temporary directory.
+ if (s.keep_tmpdir)
+ {
+ cerr << "You can't specify the -k option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ // There isn't any point in specifying '-p' with a pre-compiled
+ // module since we're automatically only doing step 5.
+ if (s.last_pass != 5)
+ {
+ cerr << "You can't specify the -p option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ // There isn't any point in specifying '-S' with a pre-compiled
+ // module since there is no module to save.
+ if (!s.saved_module_dir.empty())
+ {
+ cerr << "You can't specify the -S option with a pre-compiled module.\n";
+ usage(s, 1);
+ }
+ }
+
+ if (!s.saved_module_dir.empty())
+ {
+ // With '-S', you must run at least pass 4 (the compilation
+ // phase) since there wouldn't be anything to save if we stopped
+ // before pass 4.
+ if (s.last_pass < 4)
+ {
+ cerr << "When using the -S option, you must specify at least"
+ << " pass 4 with the -p option." << endl;
+ usage(s, 1);
+ }
+ }
+
int rc = 0;
+ int pass4_rc = 0;
// override PATH and LC_ALL
const char *path = "/bin:/sbin:/usr/bin:/usr/sbin";
@@ -316,282 +460,292 @@ main (int argc, char * const argv [])
// Create a temporary directory to build within.
// Be careful with this, as "s.tmpdir" is "rm -rf"'d at the end.
- {
- const char* tmpdir_env = getenv("TMPDIR");
- if (! tmpdir_env)
- tmpdir_env = "/tmp";
+ if (! s.pre_compiled_mode)
+ {
+ const char* tmpdir_env = getenv("TMPDIR");
+ if (! tmpdir_env)
+ tmpdir_env = "/tmp";
- string stapdir = "/stapXXXXXX";
- string tmpdirt = tmpdir_env + stapdir;
- const char* tmpdir = mkdtemp((char *)tmpdirt.c_str());
- if (! tmpdir)
- {
- const char* e = strerror (errno);
- cerr << "ERROR: cannot create temporary directory (\"" << tmpdirt << "\"): " << e << endl;
- exit (1); // die
- }
- else
- s.tmpdir = tmpdir;
+ string stapdir = "/stapXXXXXX";
+ string tmpdirt = tmpdir_env + stapdir;
+ const char* tmpdir = mkdtemp((char *)tmpdirt.c_str());
+ if (! tmpdir)
+ {
+ const char* e = strerror (errno);
+ cerr << "ERROR: cannot create temporary directory (\"" << tmpdirt << "\"): " << e << endl;
+ exit (1); // die
+ }
+ else
+ s.tmpdir = tmpdir;
- if (s.verbose>1)
- clog << "Created temporary directory \"" << s.tmpdir << "\"" << endl;
- }
+ if (s.verbose>1)
+ clog << "Created temporary directory \"" << s.tmpdir << "\"" << endl;
+ }
struct tms tms_before;
times (& tms_before);
struct timeval tv_before;
gettimeofday (&tv_before, NULL);
- // PASS 1a: PARSING USER SCRIPT
- // XXX: pass args vector, so parser (or lexer?) can substitute
- // $1..$NN with actual arguments
- if (script_file == "-")
- s.user_file = parser::parse (s, cin, s.guru_mode);
- else if (script_file != "")
- s.user_file = parser::parse (s, script_file, s.guru_mode);
- else
- {
- istringstream ii (cmdline_script);
- s.user_file = parser::parse (s, ii, s.guru_mode);
- }
- if (s.user_file == 0)
- // syntax errors already printed
- rc ++;
-
- // Construct arch / kernel-versioning search path
- vector<string> version_suffixes;
- string kvr = s.kernel_release;
- const string& arch = s.architecture;
- // add full kernel-version-release (2.6.NN-FOOBAR) + arch
- version_suffixes.push_back ("/" + kvr + "/" + arch);
- version_suffixes.push_back ("/" + kvr);
- // add kernel version (2.6.NN) + arch
- string::size_type dash_index = kvr.find ('-');
- if (dash_index > 0 && dash_index != string::npos) {
- kvr.erase(dash_index);
- version_suffixes.push_back ("/" + kvr + "/" + arch);
- version_suffixes.push_back ("/" + kvr);
- }
- // add kernel family (2.6) + arch
- 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 + "/" + arch);
- version_suffixes.push_back ("/" + kvr);
- dot2_index = kvr.rfind ('.');
- }
- // add architecture search path
- version_suffixes.push_back("/" + arch);
- // add empty string as last element
- version_suffixes.push_back ("");
-
- // PASS 1b: PARSING LIBRARY SCRIPTS
- for (unsigned i=0; i<s.include_path.size(); i++)
+ unsigned _sc_clk_tck = sysconf (_SC_CLK_TCK);
+ struct tms tms_after;
+ struct timeval tv_after;
+ if (! s.pre_compiled_mode)
{
- // now iterate upon it
- for (unsigned k=0; k<version_suffixes.size(); k++)
+ // PASS 1a: PARSING USER SCRIPT
+ // XXX: pass args vector, so parser (or lexer?) can substitute
+ // $1..$NN with actual arguments
+ if (script_file == "-")
+ s.user_file = parser::parse (s, cin, s.guru_mode);
+ else if (script_file != "")
+ s.user_file = parser::parse (s, script_file, s.guru_mode);
+ else
{
- 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 ++;
- // GLOB_NOMATCH is acceptable
-
- if (s.verbose>1)
- clog << "Searched '" << dir << "', "
- << "match count " << globbuf.gl_pathc << endl;
-
- for (unsigned j=0; j<globbuf.gl_pathc; j++)
- {
- // privilege only for /usr/share/systemtap?
- stapfile* f = parser::parse (s, globbuf.gl_pathv[j], true);
- if (f == 0)
- rc ++;
- else
- s.library_files.push_back (f);
- }
-
- globfree (& globbuf);
+ istringstream ii (cmdline_script);
+ s.user_file = parser::parse (s, ii, s.guru_mode);
}
- }
-
- if (rc == 0 && s.last_pass == 1)
- {
- cout << "# parse tree dump" << endl;
- s.user_file->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);
+ if (s.user_file == 0)
+ // syntax errors already printed
+ rc ++;
+
+ // Construct arch / kernel-versioning search path
+ vector<string> version_suffixes;
+ string kvr = s.kernel_release;
+ const string& arch = s.architecture;
+ // add full kernel-version-release (2.6.NN-FOOBAR) + arch
+ version_suffixes.push_back ("/" + kvr + "/" + arch);
+ version_suffixes.push_back ("/" + kvr);
+ // add kernel version (2.6.NN) + arch
+ string::size_type dash_index = kvr.find ('-');
+ if (dash_index > 0 && dash_index != string::npos)
+ {
+ kvr.erase(dash_index);
+ version_suffixes.push_back ("/" + kvr + "/" + arch);
+ version_suffixes.push_back ("/" + kvr);
+ }
+ // add kernel family (2.6) + arch
+ 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 + "/" + arch);
+ version_suffixes.push_back ("/" + kvr);
+ dot2_index = kvr.rfind ('.');
+ }
+ // add architecture search path
+ version_suffixes.push_back("/" + arch);
+ // add empty string as last element
+ version_suffixes.push_back ("");
-#define TIMESPRINT \
- (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."
+ // PASS 1b: PARSING LIBRARY SCRIPTS
+ for (unsigned i=0; i<s.include_path.size(); i++)
+ {
+ // now iterate upon it
+ 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 ++;
+ // GLOB_NOMATCH is acceptable
+
+ if (s.verbose>1)
+ clog << "Searched '" << dir << "', "
+ << "match count " << globbuf.gl_pathc << endl;
+
+ for (unsigned j=0; j<globbuf.gl_pathc; j++)
+ {
+ // privilege only for /usr/share/systemtap?
+ stapfile* f = parser::parse (s, globbuf.gl_pathv[j], true);
+ if (f == 0)
+ rc ++;
+ else
+ s.library_files.push_back (f);
+ }
- // syntax errors, if any, are already printed
- if (s.verbose)
- {
- clog << "Pass 1: parsed user script and "
- << s.library_files.size()
- << " library script(s) in "
- << TIMESPRINT
- << endl;
- }
+ globfree (& globbuf);
+ }
+ }
- if (rc)
- cerr << "Pass 1: parse failed. "
- << "Try again with more '-v' (verbose) options."
- << endl;
+ if (rc == 0 && s.last_pass == 1)
+ {
+ cout << "# parse tree dump" << endl;
+ s.user_file->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;
+ }
+ }
- if (rc || s.last_pass == 1) goto cleanup;
+ times (& tms_after);
+ gettimeofday (&tv_after, NULL);
- times (& tms_before);
- gettimeofday (&tv_before, NULL);
+#define TIMESPRINT \
+ (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."
- // PASS 2: ELABORATION
- rc = semantic_pass (s);
+ // syntax errors, if any, are already printed
+ if (s.verbose)
+ {
+ clog << "Pass 1: parsed user script and "
+ << s.library_files.size()
+ << " library script(s) in "
+ << TIMESPRINT
+ << endl;
+ }
- if (rc == 0 && s.last_pass == 2)
- {
- if (s.globals.size() > 0)
- cout << "# globals" << endl;
- for (unsigned i=0; i<s.globals.size(); i++)
- {
- vardecl* v = s.globals[i];
- v->printsig (cout);
- cout << endl;
- }
-
- if (s.functions.size() > 0)
- cout << "# functions" << endl;
- for (unsigned i=0; i<s.functions.size(); i++)
- {
- functiondecl* f = s.functions[i];
- f->printsig (cout);
- cout << endl;
- if (f->locals.size() > 0)
- cout << " # locals" << endl;
- for (unsigned j=0; j<f->locals.size(); j++)
- {
- vardecl* v = f->locals[j];
- cout << " ";
- v->printsig (cout);
- cout << endl;
- }
- if (s.verbose)
- {
- f->body->print (cout);
- cout << endl;
- }
- }
+ if (rc)
+ cerr << "Pass 1: parse failed. "
+ << "Try again with more '-v' (verbose) options."
+ << endl;
- if (s.probes.size() > 0)
- cout << "# probes" << endl;
- for (unsigned i=0; i<s.probes.size(); i++)
- {
- derived_probe* p = s.probes[i];
- p->printsig (cout);
- cout << endl;
- if (p->locals.size() > 0)
- cout << " # locals" << endl;
- for (unsigned j=0; j<p->locals.size(); j++)
- {
- vardecl* v = p->locals[j];
- cout << " ";
- v->printsig (cout);
- cout << endl;
- }
- if (s.verbose)
- {
- p->body->print (cout);
- cout << endl;
- }
- }
- }
+ if (rc || s.last_pass == 1) goto cleanup;
- times (& tms_after);
- gettimeofday (&tv_after, NULL);
+ times (& tms_before);
+ gettimeofday (&tv_before, NULL);
- if (s.verbose) clog << "Pass 2: analyzed script: "
- << s.probes.size() << " probe(s), "
- << s.functions.size() << " function(s), "
- << s.globals.size() << " global(s) in "
- << TIMESPRINT
- << endl;
+ // PASS 2: ELABORATION
+ rc = semantic_pass (s);
- if (rc)
- cerr << "Pass 2: analysis failed. "
- << "Try again with more '-v' (verbose) options."
- << endl;
+ if (rc == 0 && s.last_pass == 2)
+ {
+ if (s.globals.size() > 0)
+ cout << "# globals" << endl;
+ for (unsigned i=0; i<s.globals.size(); i++)
+ {
+ vardecl* v = s.globals[i];
+ v->printsig (cout);
+ cout << endl;
+ }
- if (rc || s.last_pass == 2) goto cleanup;
+ if (s.functions.size() > 0)
+ cout << "# functions" << endl;
+ for (unsigned i=0; i<s.functions.size(); i++)
+ {
+ functiondecl* f = s.functions[i];
+ f->printsig (cout);
+ cout << endl;
+ if (f->locals.size() > 0)
+ cout << " # locals" << endl;
+ for (unsigned j=0; j<f->locals.size(); j++)
+ {
+ vardecl* v = f->locals[j];
+ cout << " ";
+ v->printsig (cout);
+ cout << endl;
+ }
+ if (s.verbose)
+ {
+ f->body->print (cout);
+ cout << endl;
+ }
+ }
- // PASS 3: TRANSLATION
+ if (s.probes.size() > 0)
+ cout << "# probes" << endl;
+ for (unsigned i=0; i<s.probes.size(); i++)
+ {
+ derived_probe* p = s.probes[i];
+ p->printsig (cout);
+ cout << endl;
+ if (p->locals.size() > 0)
+ cout << " # locals" << endl;
+ for (unsigned j=0; j<p->locals.size(); j++)
+ {
+ vardecl* v = p->locals[j];
+ cout << " ";
+ v->printsig (cout);
+ cout << endl;
+ }
+ if (s.verbose)
+ {
+ p->body->print (cout);
+ cout << endl;
+ }
+ }
+ }
- times (& tms_before);
- gettimeofday (&tv_before, NULL);
+ times (& tms_after);
+ gettimeofday (&tv_after, NULL);
- s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
- rc = translate_pass (s);
+ if (s.verbose)
+ clog << "Pass 2: analyzed script: "
+ << s.probes.size() << " probe(s), "
+ << s.functions.size() << " function(s), "
+ << s.globals.size() << " global(s) in "
+ << TIMESPRINT
+ << endl;
- if (rc == 0 && s.last_pass == 3)
- {
- ifstream i (s.translated_source.c_str());
- cout << i.rdbuf();
- }
+ if (rc)
+ cerr << "Pass 2: analysis failed. "
+ << "Try again with more '-v' (verbose) options."
+ << endl;
- times (& tms_after);
- gettimeofday (&tv_after, NULL);
+ if (rc || s.last_pass == 2) goto cleanup;
- if (s.verbose) clog << "Pass 3: translated to C into \""
- << s.translated_source
- << "\" in "
- << TIMESPRINT
- << endl;
+ // PASS 3: TRANSLATION
- if (rc)
- cerr << "Pass 3: translation failed. "
- << "Try again with more '-v' (verbose) options."
- << endl;
+ times (& tms_before);
+ gettimeofday (&tv_before, NULL);
- if (rc || s.last_pass == 3) goto cleanup;
+ s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
+ rc = translate_pass (s);
- // PASS 4: COMPILATION
- times (& tms_before);
- gettimeofday (&tv_before, NULL);
- rc = compile_pass (s);
- times (& tms_after);
- gettimeofday (&tv_after, NULL);
+ if (rc == 0 && s.last_pass == 3)
+ {
+ ifstream i (s.translated_source.c_str());
+ cout << i.rdbuf();
+ }
- if (s.verbose) clog << "Pass 4: compiled C into \""
- << s.module_name << ".ko"
- << "\" in "
- << TIMESPRINT
- << endl;
+ times (& tms_after);
+ gettimeofday (&tv_after, NULL);
- if (rc)
- cerr << "Pass 4: compilation failed. "
- << "Try again with more '-v' (verbose) options."
- << endl;
+ if (s.verbose)
+ clog << "Pass 3: translated to C into \""
+ << s.translated_source
+ << "\" in "
+ << TIMESPRINT
+ << endl;
+
+ if (rc)
+ cerr << "Pass 3: translation failed. "
+ << "Try again with more '-v' (verbose) options."
+ << endl;
+
+ if (rc || s.last_pass == 3) goto cleanup;
+
+ // PASS 4: COMPILATION
+ times (& tms_before);
+ gettimeofday (&tv_before, NULL);
+ rc = compile_pass (s);
+ times (& tms_after);
+ gettimeofday (&tv_after, NULL);
- // XXX: what to do if rc==0 && last_pass == 4? dump .ko file to stdout?
- if (rc || s.last_pass == 4) goto cleanup;
+ if (s.verbose)
+ clog << "Pass 4: compiled C into \""
+ << s.module_name << ".ko"
+ << "\" in "
+ << TIMESPRINT
+ << endl;
+
+ if (rc)
+ cerr << "Pass 4: compilation failed. "
+ << "Try again with more '-v' (verbose) options."
+ << endl;
+
+ // XXX: what to do if rc==0 && last_pass == 4? dump .ko file to stdout?
+ pass4_rc = rc;
+ if (rc || s.last_pass == 4) goto cleanup;
+ }
// PASS 5: RUN
times (& tms_before);
@@ -599,11 +753,13 @@ main (int argc, char * const argv [])
// NB: this message is a judgement call. The other passes don't emit
// a "hello, I'm starting" message, but then the others aren't interactive
// and don't take an indefinite amount of time.
- if (s.verbose) clog << "Pass 5: starting run." << endl;
+ if (s.verbose)
+ clog << "Pass 5: starting run." << endl;
rc = run_pass (s);
times (& tms_after);
gettimeofday (&tv_after, NULL);
- if (s.verbose) clog << "Pass 5: run completed in "
+ if (s.verbose)
+ clog << "Pass 5: run completed in "
<< TIMESPRINT
<< endl;
@@ -615,6 +771,22 @@ main (int argc, char * const argv [])
// if (rc) goto cleanup;
cleanup:
+ // If the user requested that we save the module and pass 4 worked,
+ // save module.
+ if (!s.saved_module_dir.empty() && !pass4_rc && s.last_pass >= 4)
+ {
+ string copycmd = "cp ";
+ copycmd += s.tmpdir + "/" + s.module_name + ".ko " + s.saved_module_dir;
+ if (s.verbose>1)
+ clog << "Running " << copycmd << endl;
+ int status = system (copycmd.c_str());
+ if (status != 0)
+ clog << "Module save failed, status: " << status << endl;
+ else
+ clog << "Module saved as " << s.saved_module_dir << "/"
+ << s.module_name << ".ko" << endl;
+ }
+
// Clean up temporary directory. Obviously, be careful with this.
if (s.tmpdir == "")
; // do nothing
Index: session.h
===================================================================
RCS file: /cvs/systemtap/src/session.h,v
retrieving revision 1.9
diff -u -p -r1.9 session.h
--- session.h 12 Sep 2006 22:05:48 -0000 1.9
+++ session.h 14 Sep 2006 15:48:12 -0000
@@ -79,6 +79,8 @@ struct systemtap_session
bool merge;
int buffer_size;
unsigned perfmon;
+ bool pre_compiled_mode;
+ std::string saved_module_dir;
// temporary directory for module builds etc.
// hazardous - it is "rm -rf"'d at exit