This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

pre-compiled systemtap modules (try 2)


Back at the end of June we had a discussion about pre-compiled modules.
I proposed a command-line interface patch, but we had several
outstanding issues:


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

Note that the patch is smaller than it looks since a large part of
main.cxx was re-indented so that passes 1-4 will get skipped when '-P'
is specified.

(The original patch always saved the compiled module in '.', but Josh
Stone liked being able to specify a directory.  I've changed the patch
to reflect this.)

With this patch, the command-line interface should be ready to handle
saving modules for later use.

If you combine this with the stap '-r' option, you can also compile for
a kernel different than the running kernel.  Note that you must compile
for the same architecture as the running kernel - you can't compile a
x86_64 systemtap module while running a i686 kernel.

Compiling for a different architecture is theoretically possible, but a
problem not really in the systemtap space - finding/building an
appropriate cross-compiler would be the first hurdle to cross.

I'd appreciate any comments on the patch.


2) Differing options between compile (stap) and run time (stpd).  I
believe that most of them should be OK, with the exception of the stap
'-b' relayfs option (which turns into the '-r' stpd option).  If the '-
b' option was specified at compile time and not at run time (or vice
versa), I'm not sure what will happen (since that flag appears to change
behavior both at compile time and run time).

Martin Hunt was going to look into remove '-r' from stpd, but hasn't had
a chance yet that I know of.


3) kernel module support.  If the systemtap script probes a loadable
kernel module, if we save the compiled systemtap module for execution
later, we've no guarantee that the loadable kernel module will be in the
same spot in memory.  To solve this, Ananth Mavinakayanahalli, Prasanna
Panchamukhi, Christoph Hellwig, and Anil Keshavamurthy wrote a set of
patches that changes 'struct kprobe' to take a symbol_name and offset.
See <http://www.ussg.iu.edu/hypermail/linux/kernel/0608.0/2006.html> for
details.  This will allow us to pass in a module name/symbol and have
the address calculation done at run time instead of at compile time for
modules.

I've been internally pushing to get these patches into fc6/rhel5 (but
they aren't quite there yet).

This will require changes in C code generation in systemtap.  I plan on
looking into this next.


Comments appreciated, especially if I've missed any items needed to
support pre-compiled systemtap modules.

-- 
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.25
diff -u -p -r1.25 buildrun.cxx
--- buildrun.cxx	28 Aug 2006 17:59:50 -0000	1.25
+++ buildrun.cxx	12 Sep 2006 21:37:23 -0000
@@ -145,7 +145,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.51
diff -u -p -r1.51 main.cxx
--- main.cxx	28 Aug 2006 17:59:51 -0000	1.51
+++ main.cxx	12 Sep 2006 21:37:23 -0000
@@ -26,6 +26,7 @@ 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 <time.h>
@@ -58,6 +59,8 @@ usage (systemtap_session& s, int exitcod
     << endl
     << "   or: stap [options] -e SCRIPT    Run given script."
     << endl
+    << "   or: stap [options] -P PRE_COMPILED_MODULE  Run pre-compiled module."
+    << endl
     << endl
     << "Options:" << endl
     << "   --         no more options after this" << endl
@@ -94,6 +97,9 @@ 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
+    << "   -P PRE_COMPILED_MODULE" << endl
+    << "              Run pre-compiled module" << endl
     ;
   // -d: dump safety-related external references
 
@@ -119,6 +125,7 @@ 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;
@@ -139,6 +146,8 @@ main (int argc, char * const argv [])
   s.cmd = "";
   s.target_pid = 0;
   s.merge=true;
+  s.pre_compiled_mode = false;
+  s.saved_module_dir = "";
 
   const char* s_p = getenv ("SYSTEMTAP_TAPSET");
   if (s_p != NULL)  
@@ -160,7 +169,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)
@@ -192,6 +201,7 @@ main (int argc, char * const argv [])
 
         case 'I':
           s.include_path.push_back (string (optarg));
+	  added_include_dirs = true;
           break;
 
         case 'e':
@@ -258,6 +268,25 @@ main (int argc, char * const argv [])
 	  s.macros.push_back (string (optarg));
 	  break;
 
+	case 'P':
+	  s.pre_compiled_mode = true;
+	  s.module_name = 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;
@@ -292,13 +321,80 @@ main (int argc, char * const argv [])
     }
 
   // 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 '-P' since the
+      // compilation has already occurred.
+      if (s.macros.size() != 0)
+        {
+	  cerr << "You can't specify the -D and -P options together." << endl;
+	  usage(s, 1);
+	}
+      // There isn't any point in specifying '-I' -with '-P' since the
+      // compilation has already occurred.
+      if (added_include_dirs)
+        {
+	  cerr << "You can't specify the -I and -P options together." << endl;
+	  usage(s, 1);
+	}
+      // There isn't any point in specifying '-g' -with '-P' since the
+      // compilation has already occurred.
+      if (s.guru_mode)
+        {
+	  cerr << "You can't specify the -g and -P options together." << endl;
+	  usage(s, 1);
+	}
+      // There isn't any point in specifying '-u' -with '-P' since the
+      // compilation has already occurred.
+      if (s.unoptimized)
+        {
+	  cerr << "You can't specify the -u and -P options together." << endl;
+	  usage(s, 1);
+	}
+      // There isn't any point in specifying '-k' -with '-P' since there
+      // is no temporary directory.
+      if (s.keep_tmpdir)
+        {
+	  cerr << "You can't specify the -k and -P options together." << endl;
+	  usage(s, 1);
+	}
+      // There isn't any point in specifying '-p' -with '-P' since
+      // we're automatically only doing step 5.
+      if (s.last_pass != 5)
+        {
+	  cerr << "You can't specify the -p and -P options together." << endl;
+	  usage(s, 1);
+	}
+      // There isn't any point in specifying '-S' -with '-P' since there
+      // is no module to save.
+      if (!s.saved_module_dir.empty())
+        {
+	  cerr << "You can't specify the -S and -P options together." << endl;
+	  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";
@@ -315,282 +411,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);
@@ -598,11 +704,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;
 
@@ -614,6 +722,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.8
diff -u -p -r1.8 session.h
--- session.h	28 Aug 2006 17:59:51 -0000	1.8
+++ session.h	12 Sep 2006 21:37:24 -0000
@@ -78,6 +78,8 @@ struct systemtap_session
   bool unoptimized;
   bool merge;
   int buffer_size;
+  bool pre_compiled_mode;
+  std::string saved_module_dir;
 
   // temporary directory for module builds etc.
   // hazardous - it is "rm -rf"'d at exit

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]