]> sourceware.org Git - systemtap.git/blobdiff - main.cxx
testsuite procfs_bpf.exp: tolerate stapbpf early exit
[systemtap.git] / main.cxx
index 4e81097d04c16568ab6d296abded919486988863..ed15b77dcede4cb04158fd256005828090ef862e 100644 (file)
--- a/main.cxx
+++ b/main.cxx
@@ -1,5 +1,5 @@
 // systemtap translator/driver
-// Copyright (C) 2005-2016 Red Hat Inc.
+// Copyright (C) 2005-2018 Red Hat Inc.
 // Copyright (C) 2005 IBM Corp.
 // Copyright (C) 2006 Intel Corporation.
 //
 #include "rpm_finder.h"
 #include "task_finder.h"
 #include "csclient.h"
+#include "client-nss.h"
 #include "remote.h"
 #include "tapsets.h"
 #include "setupdwfl.h"
 #ifdef HAVE_LIBREADLINE
 #include "interactive.h"
 #endif
+#include "bpf.h"
 
 #if ENABLE_NLS
 #include <libintl.h>
@@ -37,6 +39,8 @@
 #include "stap-probe.h"
 
 #include <cstdlib>
+#include <thread>
+#include <algorithm>
 
 extern "C" {
 #include <glob.h>
@@ -49,6 +53,8 @@ extern "C" {
 #include <time.h>
 #include <unistd.h>
 #include <wordexp.h>
+#include <ftw.h>
+#include <fcntl.h>
 }
 
 using namespace std;
@@ -129,7 +135,11 @@ printscript(systemtap_session& s, ostream& o)
       // print probe name and variables if there
       for (map<string, set<derived_probe *> >::iterator it=probe_list.begin(); it!=probe_list.end(); ++it)
         {
-          o << it->first; // probe name or alias
+          // probe name or alias
+          if (s.dump_mode == systemtap_session::dump_matched_probes_vars && isatty(STDOUT_FILENO))
+            o << s.colorize(it->first, "source");
+          else
+            o << it->first;
 
           // Print the locals and arguments for -L mode only
           if (s.dump_mode == systemtap_session::dump_matched_probes_vars)
@@ -268,8 +278,30 @@ void handle_interrupt (int)
   if (pending_interrupts > 2) // XXX: should be configurable? time-based?
     {
       char msg[] = "Too many interrupts received, exiting.\n";
-      int rc = write (2, msg, sizeof(msg)-1);
-      if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;}
+      int fd = 2;
+
+      /* NB: writing to stderr blockingly in a signal handler is dangerous
+       * since it may prevent the stap process from quitting gracefully
+       * on receiving SIGTERM/etc signals when the stderr write buffer
+       * is full. PR23891 */
+      int flags = fcntl(fd, F_GETFL);
+      if (flags == -1)
+        _exit (1);
+
+      if (!(flags & O_NONBLOCK))
+        {
+          if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == 0) {
+            int rc = write (fd, msg, sizeof(msg)-1);
+            if (rc)
+              {
+                /* Do nothing; we don't care if our last gasp went out. */
+                ;
+              }
+          }
+        }  /* if ! O_NONBLOCK */
+
+      /* to avoid leaving any side-effects on the stderr device */
+      (void) fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
       _exit (1);
     }
 }
@@ -303,15 +335,13 @@ setup_signals (sighandler_t handler)
 }
 
 
-static void*
-sdt_benchmark_thread(void* p)
+static void
+sdt_benchmark_thread(unsigned long i)
 {
-  unsigned long i = *(unsigned long*)p;
   PROBE(stap, benchmark__thread__start);
   while (i--)
     PROBE1(stap, benchmark, i);
   PROBE(stap, benchmark__thread__end);
-  return NULL;
 }
 
 
@@ -332,13 +362,13 @@ run_sdt_benchmark(systemtap_session& s)
   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);
-
+    {
+      vector<thread> handles;
+      for (unsigned long i = 0; i < threads; ++i)
+        handles.push_back(thread(sdt_benchmark_thread, loops));
+      for (unsigned long i = 0; i < threads; ++i)
+        handles[i].join();
+    }
   PROBE(stap, benchmark__end);
 
   times (& tms_after);
@@ -354,6 +384,54 @@ run_sdt_benchmark(systemtap_session& s)
   return EXIT_SUCCESS;
 }
 
+static set<string> files;
+static string path_dir;
+
+static int collect_stp(const char* fpath, const struct stat*,
+                       int typeflag, struct FTW* ftwbuf)
+{
+  if (typeflag == FTW_F)
+    {
+      const char* ext = strrchr(fpath, '.');
+      if (ext && (strcmp(".stp", ext) == 0))
+        files.insert(fpath);
+    }
+  else if (typeflag == FTW_D && ftwbuf->level > 0)
+    {
+      // Only recurse for PATH root directory
+      if (strncmp(path_dir.c_str(), fpath, path_dir.size()) != 0 ||
+          (fpath[path_dir.size()] != '/' && fpath[path_dir.size()] != '\0'))
+        return FTW_SKIP_SUBTREE;
+    }
+  return FTW_CONTINUE;
+}
+
+static int collect_stpm(const char* fpath, const struct stat*,
+                        int typeflag, struct FTW* ftwbuf)
+{
+  if (typeflag == FTW_F)
+    {
+      const char* ext = strrchr(fpath, '.');
+      if (ext && (strcmp(".stpm", ext) == 0))
+        files.insert(fpath);
+    }
+  else if (typeflag == FTW_D && ftwbuf->level > 0)
+    {
+      // Only recurse for PATH root directory
+      if (strncmp(path_dir.c_str(), fpath, path_dir.size()) != 0 ||
+          (fpath[path_dir.size()] != '/' && fpath[path_dir.size()] != '\0'))
+        return FTW_SKIP_SUBTREE;
+    }
+  return FTW_CONTINUE;
+}
+
+#if !HAVE_BPF_DECLS
+int
+translate_bpf_pass (systemtap_session &)
+{
+  return 1;
+}
+#endif
 
 // Compilation passes 0 through 4
 int
@@ -375,11 +453,11 @@ passes_0_4 (systemtap_session &s)
   // Perform passes 0 through 4 using a compile server?
   if (! s.specified_servers.empty ())
     {
-#if HAVE_NSS
+#if NEED_BASE_CLIENT_CODE
       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"));
+      s.print_warning(_("Without NSS or HTTP client support, using a compile-server is not supported by this version of systemtap"));
 
       // This cannot be an attempt to use a server after a local compile failed
       // since --use-server-on-error is locked to 'no' if we don't have
@@ -410,16 +488,17 @@ passes_0_4 (systemtap_session &s)
     }
 
   // Now that no further changes to s.kernel_build_tree can occur, let's use it.
-  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)
-      {
-        // Try again with a server
-        s.set_try_server ();
-        return rc;
-      }
-  }
+  if (!s.runtime_usermode_p())
+    {
+      if ((rc = s.parse_kernel_config ()) != 0
+         || (rc = s.parse_kernel_exports ()) != 0
+         || (rc = s.parse_kernel_functions ()) != 0)
+       {
+         // Try again with a server
+         s.set_try_server ();
+         return rc;
+       }
+    }
 
   // Create the name of the C source file within the temporary
   // directory.  Note the _src prefix, explained in
@@ -436,6 +515,9 @@ passes_0_4 (systemtap_session &s)
   // PASS 1a: PARSING LIBRARY SCRIPTS
   PROBE1(stap, pass1a__start, &s);
 
+  // prep this array for tapset $n use too ... although we will reset once again for user scripts
+  s.used_args.resize(s.args.size(), false);
+  
   if (! s.pass_1a_complete)
     {
       // We need to handle the library scripts first because this pass
@@ -452,12 +534,43 @@ passes_0_4 (systemtap_session &s)
        }
       else if (s.script_file != "")
         {
+          if (s.run_example)
+            {
+              files.clear();
+              path_dir = string(PKGDATADIR) + "/examples";
+              (void) nftw(path_dir.c_str(), collect_stp, 1, FTW_ACTIONRETVAL);
+
+              vector<string> examples;
+              for (auto it = files.begin(); it != files.end(); ++it)
+                {
+                  string::size_type last_slash_index = it->find_last_of('/');
+                  string example_name = it->substr(last_slash_index + 1);
+                  if (s.script_file == example_name)
+                    examples.push_back(*it);
+                }
+
+              if (examples.size() > 1)
+                {
+                  cerr << "Multiple examples found: " << endl;
+                  for (auto it = examples.begin(); it != examples.end(); ++it)
+                    cerr << "  " << *it << endl;
+                  return 1;
+                }
+              else if (examples.size() == 0)
+                {
+                  cerr << _F("Example '%s' was not found under '%s'", s.script_file.c_str(), path_dir.c_str()) << endl;
+                  return 1;
+                }
+              else
+                  s.script_file = examples[0];
+            }
+
          user_file_stat_rc = stat (s.script_file.c_str(), & user_file_stat);
        }
       // otherwise, rc is 0 for a command line script
 
       vector<string> version_suffixes;
-      if (s.runtime_mode == systemtap_session::kernel_runtime)
+      if (!s.runtime_usermode_p())
         {
          // Construct kernel-versioning search path
          string kvr = s.kernel_release;
@@ -498,6 +611,8 @@ passes_0_4 (systemtap_session &s)
        runtime_prefix = "/linux";
       else if (s.runtime_mode == systemtap_session::dyninst_runtime)
        runtime_prefix = "/dyninst";
+      else if (s.runtime_mode == systemtap_session::bpf_runtime)
+        runtime_prefix = "/bpf";
       if (!runtime_prefix.empty())
        for (unsigned i=0; i<version_suffixes.size(); i+=2)
            version_suffixes.insert(version_suffixes.begin() + i/2,
@@ -515,28 +630,28 @@ passes_0_4 (systemtap_session &s)
          // 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] + "/*.stpm";
-             int r = glob(dir.c_str (), 0, NULL, & globbuf);
-             if (r == GLOB_NOSPACE || r == GLOB_ABORTED)
-               rc ++;
-             // GLOB_NOMATCH is acceptable
+              int flags = FTW_ACTIONRETVAL;
+             string dir = s.include_path[i] + version_suffixes[k];
+              files.clear();
+              // we need to set this for the nftw() callback
+              path_dir = s.include_path[i] + "/PATH";
+              (void) nftw(dir.c_str(), collect_stpm, 1, flags);
 
              unsigned prev_s_library_files = s.library_files.size();
 
-             for (unsigned j=0; j<globbuf.gl_pathc; j++)
+             for (auto it = files.begin(); it != files.end(); ++it)
                {
                  assert_no_interrupts();
 
                  struct stat tapset_file_stat;
-                 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
+                 int stat_rc = stat (it->c_str(), & 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;
+                               it->c_str()) << endl;
                      rc ++;
                    }
 
@@ -548,14 +663,14 @@ passes_0_4 (systemtap_session &s)
                      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;
+                           clog << _F("Skipping tapset \"%s\", duplicate inode.", it->c_str()) << endl;
                          continue; 
                        }
                      seen_library_macro_files.insert (here);
                    }
 
                  // PR12443: duplicate-eliminate harder
-                 string full_path = globbuf.gl_pathv[j];
+                 string full_path = *it;
                  string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
                  if (full_path.size() > tapset_base.size())
                    {
@@ -563,30 +678,28 @@ passes_0_4 (systemtap_session &s)
                      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;
+                           clog << _F("Skipping tapset \"%s\", duplicate name.", it->c_str()) << endl;
                          continue;
                        }
                      seen_library_macro_files_names.insert (tail_part);
                    }
 
                  if (s.verbose>2)
-                   clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
+                   clog << _F("Processing tapset \"%s\"", it->c_str()) << endl;
 
-                 stapfile* f = parse_library_macros (s, globbuf.gl_pathv[j]);
+                 stapfile* f = parse_library_macros (s, *it);
                  if (f == 0)
-                   s.print_warning(_F("macro tapset \"%s\" has errors, and will be skipped.", string(globbuf.gl_pathv[j]).c_str()));
+                   s.print_warning(_F("macro tapset \"%s\" has errors, and will be skipped.", it->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)
+             if (s.verbose>1 && !files.empty())
                  //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
                clog << _F("Searched for library macro files: \"%s\", found: %zu, processed: %u",
-                          dir.c_str(), globbuf.gl_pathc,
+                          dir.c_str(), files.size(),
                           (next_s_library_files-prev_s_library_files)) << endl;
-
-             globfree (&globbuf);
            }
        }
 
@@ -596,38 +709,41 @@ passes_0_4 (systemtap_session &s)
 
       for (unsigned i=0; i<s.include_path.size(); i++)
         {
-         unsigned tapset_flags = pf_guru | pf_squash_errors;
-
-         // The first path is special, as it's the builtin tapset.
-         // Allow all features no matter what s.compatible says.
-         if (i == 0)
-           tapset_flags |= pf_no_compatible;
-
          // 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
+              int flags = FTW_ACTIONRETVAL;
+             string dir = s.include_path[i] + version_suffixes[k];
+              files.clear();
+              // we need to set this for the nftw() callback
+              path_dir = s.include_path[i] + "/PATH";
+              (void) nftw(dir.c_str(), collect_stp, 1, flags);
 
              unsigned prev_s_library_files = s.library_files.size();
 
-             for (unsigned j=0; j<globbuf.gl_pathc; j++)
+              for (auto it = files.begin(); it != files.end(); ++it)
                {
-                 assert_no_interrupts();
+                  unsigned tapset_flags = pf_guru | pf_squash_errors;
+
+                  // The first path is special, as it's the builtin tapset.
+                  // Allow all features no matter what s.compatible says.
+                  if (i == 0)
+                    tapset_flags |= pf_no_compatible;
+
+                  if (it->find("/PATH/") != string::npos)
+                    tapset_flags |= pf_auto_path;
+
+                  assert_no_interrupts();
 
                  struct stat tapset_file_stat;
-                 int stat_rc = stat (globbuf.gl_pathv[j], & tapset_file_stat);
+                 int stat_rc = stat (it->c_str(), & 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;
+                               it->c_str()) << endl;
                      rc ++;
                    }
 
@@ -639,14 +755,14 @@ passes_0_4 (systemtap_session &s)
                      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;
+                           clog << _F("Skipping tapset \"%s\", duplicate inode.", it->c_str()) << endl;
                          continue; 
                        }
                      seen_library_files.insert (here);
                    }
 
                  // PR12443: duplicate-eliminate harder
-                 string full_path = globbuf.gl_pathv[j];
+                 string full_path = *it;
                  string tapset_base = s.include_path[i]; // not dir; it has arch suffixes too
                  if (full_path.size() > tapset_base.size())
                    {
@@ -654,14 +770,14 @@ passes_0_4 (systemtap_session &s)
                      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;
+                           clog << _F("Skipping tapset \"%s\", duplicate name.", it->c_str()) << endl;
                          continue;
                        }
                      seen_library_files_names.insert (tail_part);
                    }
 
                  if (s.verbose>2)
-                   clog << _F("Processing tapset \"%s\"", globbuf.gl_pathv[j]) << endl;
+                   clog << _F("Processing tapset \"%s\"", it->c_str()) << endl;
 
                  // NB: we don't need to restrict privilege only for
                  // /usr/share/systemtap, i.e., excluding
@@ -671,23 +787,25 @@ passes_0_4 (systemtap_session &s)
                  // a trusted environment, where client-side
                  // $XDG_DATA_DIRS are not passed.
 
-                 stapfile* f = parse (s, globbuf.gl_pathv[j], tapset_flags);
+                 stapfile* f = parse (s, *it, tapset_flags);
                  if (f == 0)
-                   s.print_warning(_F("tapset \"%s\" has errors, and will be skipped", string(globbuf.gl_pathv[j]).c_str()));
+                   s.print_warning(_F("tapset \"%s\" has errors, and will be skipped", it->c_str()));
                  else
-                   s.library_files.push_back (f);
+                    {
+                      assert (f->privileged);
+                      s.library_files.push_back (f);
+                    }
                }
 
              unsigned next_s_library_files = s.library_files.size();
-             if (s.verbose>1 && globbuf.gl_pathc > 0)
+             if (s.verbose>1 && !files.empty())
                  //TRANSLATORS: Searching through directories, 'processed' means 'examined so far'
                clog << _F("Searched: \"%s\", found: %zu, processed: %u",
-                          dir.c_str(), globbuf.gl_pathc,
+                          dir.c_str(), files.size(),
                           (next_s_library_files-prev_s_library_files)) << endl;
-
-             globfree (& globbuf);
            }
        }
+
       if (s.num_errors())
        rc ++;
 
@@ -700,6 +818,10 @@ passes_0_4 (systemtap_session &s)
   // PASS 1b: PARSING USER SCRIPT
   PROBE1(stap, pass1b__start, &s);
 
+  // reset for user scripts -- it's their use of $* we care about
+  // except that tapsets like argv.stp can consume $parms
+  fill(s.used_args.begin(), s.used_args.end(), false);
+
   // Only try to parse a user script if the user provided one, or if we have to
   // make one (as is the case for listing mode). Otherwise, s.user_script
   // remains NULL.
@@ -712,7 +834,10 @@ passes_0_4 (systemtap_session &s)
       user_flags |= pf_user_file;
       if (s.script_file == "-")
         {
-          s.user_files.push_back (parse (s, "<input>", cin, user_flags));
+         if (s.stdin_script.str().empty())
+           s.stdin_script << cin.rdbuf();          
+          s.user_files.push_back (parse (s, "<input>", s.stdin_script,
+                                        user_flags));
         }
       else if (s.script_file != "")
         {
@@ -845,6 +970,23 @@ passes_0_4 (systemtap_session &s)
   PROBE1(stap, pass2__start, &s);
   rc = semantic_pass (s);
 
+  // http handled probes need probe information from pass 2
+  if (! s.http_servers.empty ())
+    {
+#if NEED_BASE_CLIENT_CODE
+      compile_server_client client (s);
+      return client.passes_0_4 ();
+#else
+      s.print_warning(_("Without NSS or HTTP client support, using a compile-server is not supported by this version of systemtap"));
+
+      // This cannot be an attempt to use a server after a local compile failed
+      // since --use-server-on-error is locked to 'no' if we don't have
+      // NSS.
+      assert (! s.try_server ());
+      s.print_warning(_("Ignoring --use-server"));
+#endif
+    }
+
   // Dump a list of known probe point types, if requested.
   if (s.dump_mode == systemtap_session::dump_probe_types)
     s.pattern_root->dump (s);
@@ -869,7 +1011,8 @@ passes_0_4 (systemtap_session &s)
   // Dump the whole script if requested, or if we stop at 2
   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))
+           (rc == 0 && s.last_pass == 2) ||
+           (rc != 0 && s.verbose > 2))
     printscript(s, cout);
 
   times (& tms_after);
@@ -892,6 +1035,23 @@ passes_0_4 (systemtap_session &s)
 
   missing_rpm_list_print(s, "-debuginfo");
 
+  // Check for unused command line parameters.  But - if the argv
+  // tapset was selected for inclusion, then the user-script need not
+  // use $* directly, so we want to suppress the warning in this case.
+  // This is hacky, but we don't have a formal way of tracking tokens
+  // that came from command line arguments so as to do set-subtraction
+  // at this point.
+  //
+  bool argc_found=false, argv_found=false;
+  for (unsigned i = 0; i<s.globals.size(); i++) {
+    if (s.globals[i]->unmangled_name == "argc") argc_found = true;
+    if (s.globals[i]->unmangled_name == "argv") argv_found = true;
+  }
+  if (!argc_found && !argv_found)
+    for (unsigned i = 0; i<s.used_args.size(); i++)
+      if (! s.used_args[i])
+        s.print_warning (_F("unused command line option $%u/@%u", i+1, i+1));
+  
   if (rc && !s.dump_mode && !s.try_server ())
     cerr << _("Pass 2: analysis failed.  [man error::pass2]") << endl;
 
@@ -944,36 +1104,57 @@ passes_0_4 (systemtap_session &s)
     }
 
   // PASS 3: TRANSLATION
+  // (BPF does translation and compilation at once in pass 4.)
   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)
+  if (s.runtime_mode == systemtap_session::bpf_runtime)
     {
-      ifstream i (s.translated_source.c_str());
-      cout << i.rdbuf();
+      times (& tms_after);
+      gettimeofday (&tv_after, NULL);
+      PROBE1(stap, pass3__end, &s);
+
+      if (s.verbose)
+       clog << _("Pass 3: pass skipped for stapbpf runtime ")
+            << TIMESPRINT
+            << endl;
+
+      assert_no_interrupts();
+      if (s.last_pass == 3)
+       return rc;
     }
+  else
+    {
+      rc = translate_pass (s);
 
-  times (& tms_after);
-  gettimeofday (&tv_after, NULL);
+      if (! rc && s.last_pass == 3)
+       {
+         ifstream i (s.translated_source.c_str());
+         cout << i.rdbuf();
+       }
 
-  if (s.verbose) 
-    clog << _("Pass 3: translated to C into \"")
-         << s.translated_source
-         << "\" "
-         << getmemusage()
-         << TIMESPRINT
-         << endl;
+      times (& tms_after);
+      gettimeofday (&tv_after, NULL);
 
-  if (rc && ! s.try_server ())
-    cerr << _("Pass 3: translation failed.  [man error::pass3]") << endl;
+      if (s.verbose)
+       clog << _("Pass 3: translated to C into \"")
+            << s.translated_source
+            << "\" "
+            << getmemusage()
+            << TIMESPRINT
+            << endl;
 
-  PROBE1(stap, pass3__end, &s);
+      if (rc && ! s.try_server ())
+       cerr << _("Pass 3: translation failed.  [man error::pass3]") << endl;
 
-  assert_no_interrupts();
-  if (rc || s.last_pass == 3) return rc;
+      PROBE1(stap, pass3__end, &s);
+
+      assert_no_interrupts();
+      if (rc || s.last_pass == 3)
+       return rc;
+    }
 
   // PASS 4: COMPILATION
   s.verbose = s.perpass_verbose[3];
@@ -981,13 +1162,19 @@ passes_0_4 (systemtap_session &s)
   gettimeofday (&tv_before, NULL);
   PROBE1(stap, pass4__start, &s);
 
-  if (s.use_cache)
+  if (s.runtime_mode == systemtap_session::bpf_runtime)
+    rc = translate_bpf_pass (s);
+  else
     {
-      find_stapconf_hash(s);
-      get_stapconf_from_cache(s);
+      if (s.use_cache)
+       {
+         find_stapconf_hash(s);
+         get_stapconf_from_cache(s);
+       }
+      rc = compile_pass (s);
     }
-  rc = compile_pass (s);
-  if (! rc && s.last_pass == 4)
+
+  if (! rc && s.last_pass <= 4)
     {
       cout << ((s.hash_path == "") ? s.module_filename() : s.hash_path);
       cout << endl;
@@ -996,18 +1183,21 @@ passes_0_4 (systemtap_session &s)
   times (& tms_after);
   gettimeofday (&tv_after, NULL);
 
-  if (s.verbose) clog << _("Pass 4: compiled C into \"")
-                      << s.module_filename()
-                      << "\" "
-                      << TIMESPRINT
-                      << endl;
+  if (s.verbose)
+    {
+      if (s.runtime_mode == systemtap_session::bpf_runtime)
+       clog << _("Pass 4: compiled BPF into \"");
+      else
+       clog << _("Pass 4: compiled C into \"");
+      clog << s.module_filename() << "\" " << TIMESPRINT << endl;
+    }
 
   if (rc && ! s.try_server ())
     cerr << _("Pass 4: compilation failed.  [man error::pass4]") << endl;
-
   else
     {
-      // Update cache. Cache cleaning is kicked off at the beginning of this function.
+      // Update cache. Cache cleaning is kicked off at the
+      // beginning of this function.
       if (s.use_script_cache)
         add_script_to_cache(s);
       if (s.use_cache && !s.runtime_usermode_p())
@@ -1015,7 +1205,7 @@ passes_0_4 (systemtap_session &s)
 
       // We may need to save the module in $CWD if the cache was
       // inaccessible for some reason.
-      if (! s.use_script_cache && s.last_pass == 4)
+      if (! s.use_script_cache && s.last_pass <= 4)
         s.save_module = true;
 
       // Copy module to the current directory.
@@ -1239,16 +1429,19 @@ main (int argc, char * const argv [])
             if (ss.verbose > 1)
              clog << _F("Session arch: %s release: %s",
                         ss.architecture.c_str(), ss.kernel_release.c_str())
+                  << endl
+                   << _F("Build tree: \"%s\"",
+                        ss.kernel_build_tree.c_str())
                   << endl;
 
 #if HAVE_NSS
            // If requested, query server status. This is independent
            // of other tasks.
-           query_server_status (ss);
+           nss_client_query_server_status (ss);
 
            // If requested, manage trust of servers. This is
            // independent of other tasks.
-           manage_server_trust (ss);
+           nss_client_manage_server_trust (ss);
 #endif
 
            // Run the passes only if a script has been specified or
This page took 0.044367 seconds and 5 git commands to generate.