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]

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

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