]> sourceware.org Git - systemtap.git/blobdiff - session.cxx
buildrun.cxx: adapt to kernel 5.4+
[systemtap.git] / session.cxx
index e7af997d9110c1174b92a9669cca5d10badb94c6..a69dca20be0e00c34e00e2a5bbda4984536f2a7c 100644 (file)
@@ -1,5 +1,5 @@
 // session functions
-// Copyright (C) 2010-2016 Red Hat Inc.
+// Copyright (C) 2010-2019 Red Hat Inc.
 //
 // This file is part of systemtap, and is free software.  You can
 // redistribute it and/or modify it under the terms of the GNU General
@@ -70,7 +70,7 @@ systemtap_session::systemtap_session ():
   base_hash(0),
   pattern_root(new match_node),
   dfa_counter (0),
-  dfa_maxstate (0),
+  dfa_maxmap (0),
   dfa_maxtag (0),
   need_tagged_dfa (false),
   be_derived_probes(0),
@@ -101,6 +101,7 @@ systemtap_session::systemtap_session ():
   suppressed_errors(0),
   warningerr_count(0),
   target_namespaces_pid(0),
+  suppress_costly_diagnostics(0),
   last_token (0)
 {
   struct utsname buf;
@@ -139,6 +140,7 @@ systemtap_session::systemtap_session ():
   tmpdir_opt_set = false;
   monitor = false;
   monitor_interval = 1;
+  read_stdin = false;
   save_module = false;
   save_uprobes = false;
   modname_given = false;
@@ -175,12 +177,16 @@ systemtap_session::systemtap_session ():
   update_release_sysroot = false;
   suppress_time_limits = false;
   target_namespaces_pid = 0;
+  suppress_costly_diagnostics = 0;
   color_mode = color_auto;
   color_errors = isatty(STDERR_FILENO) // conditions for coloring when
     && strcmp(getenv("TERM") ?: "notdumb", "dumb"); // on auto
   interactive_mode = false;
+  run_example = false;
+  no_global_var_display = false;
   pass_1a_complete = false;
   timeout = 0;
+  use_bpf_raw_tracepoint = false;
 
   // PR12443: put compiled-in / -I paths in front, to be preferred during 
   // tapset duplicate-file elimination
@@ -261,7 +267,7 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   pattern_root(new match_node),
   user_files (other.user_files),
   dfa_counter(0),
-  dfa_maxstate (0),
+  dfa_maxmap(0),
   dfa_maxtag (0),
   need_tagged_dfa(other.need_tagged_dfa),
   be_derived_probes(0),
@@ -292,6 +298,7 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   suppressed_errors(0),
   warningerr_count(0),
   target_namespaces_pid(0),
+  suppress_costly_diagnostics(0),
   last_token (0)
 {
   release = kernel_release = kern;
@@ -364,6 +371,8 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   color_errors = other.color_errors;
   color_mode = other.color_mode;
   interactive_mode = other.interactive_mode;
+  run_example = other.run_example;
+  no_global_var_display = other.no_global_var_display;
   pass_1a_complete = other.pass_1a_complete;
   timeout = other.timeout;
 
@@ -382,6 +391,7 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   script_file = other.script_file;
   cmdline_script = other.cmdline_script;
   additional_scripts = other.additional_scripts;
+  stdin_script.str() = other.stdin_script.str();
   c_macros = other.c_macros;
   args = other.args;
   kbuildflags = other.kbuildflags;
@@ -396,6 +406,9 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   server_args = other.server_args;
   mok_fingerprints = other.mok_fingerprints;
 
+  // HTTP client/server
+  http_servers = other.http_servers;
+
   unwindsym_modules = other.unwindsym_modules;
   auto_privilege_level_msg = other.auto_privilege_level_msg;
   auto_server_msgs = other.auto_server_msgs;
@@ -413,9 +426,22 @@ systemtap_session::~systemtap_session ()
 const string
 systemtap_session::module_filename() const
 {
-  if (runtime_usermode_p())
-    return module_name + ".so";
-  return module_name + ".ko";
+  const char *suffix;
+  switch (runtime_mode)
+    {
+    case kernel_runtime:
+      suffix = ".ko";
+      break;
+    case dyninst_runtime:
+      suffix = ".so";
+      break;
+    case bpf_runtime:
+      suffix = ".bo";
+      break;
+    default:
+      abort();
+    }
+  return module_name + suffix;
 }
 
 #if HAVE_NSS
@@ -449,12 +475,12 @@ systemtap_session::version_string ()
 {
   string elfutils_version1;
 #ifdef _ELFUTILS_VERSION
-  elfutils_version1 = "0." + lex_cast(_ELFUTILS_VERSION);
+  elfutils_version1 = "0." + lex_cast(_ELFUTILS_VERSION); /* BUILD */
 #endif
-  string elfutils_version2 = dwfl_version(NULL);
+  string elfutils_version2 = dwfl_version(NULL); /* RUN */
 
   if (elfutils_version1 != elfutils_version2)
-    elfutils_version2 += string("/") + elfutils_version1;
+    elfutils_version2 += string("/") + elfutils_version1;   /* RUN/BUILD */
 
   return string (VERSION) + "/" + elfutils_version2 + ", " + STAP_EXTENDED_VERSION;
 }
@@ -462,12 +488,11 @@ systemtap_session::version_string ()
 void
 systemtap_session::version ()
 {
-  // PRERELEASE
   cout << _F("Systemtap translator/driver (version %s)\n"
-             "Copyright (C) 2005-2016 Red Hat, Inc. and others\n"
+             "Copyright (C) 2005-2019 Red Hat, Inc. and others\n"   // PRERELEASE
              "This is free software; see the source for copying conditions.\n",
              version_string().c_str());
-  cout << _F("tested kernel versions: %s ... %s\n", "2.6.18", "4.10-rc0");
+  cout << _F("tested kernel versions: %s ... %s\n", "2.6.18", "5.4-rc6");   // PRERELEASE
   
   cout << _("enabled features:")
 #ifdef HAVE_AVAHI
@@ -479,6 +504,9 @@ systemtap_session::version ()
 #ifdef HAVE_DYNINST
        << " DYNINST"
 #endif
+#ifdef HAVE_BPF_DECLS
+       << " BPF"
+#endif
 #ifdef HAVE_JAVA
        << " JAVA"
 #endif
@@ -626,6 +654,10 @@ systemtap_session::usage (int exitcode)
     "   --dyninst\n"
     "              shorthand for --runtime=dyninst\n"
 #endif /* HAVE_DYNINST */
+#ifdef HAVE_BPF_DECLS
+    "   --bpf\n"
+    "              shorthand for --runtime=bpf\n"
+#endif /* HAVE_BPF_DECLS */
     "   --prologue-searching[=WHEN]\n"
     "              prologue-searching for function probes\n"
     "   --privilege=PRIVILEGE_LEVEL\n"
@@ -653,6 +685,10 @@ systemtap_session::usage (int exitcode)
     "              ssl,signer,all-users,revoke,no-prompt\n"
     "   --use-server-on-error[=yes/no]\n"
     "              retry compilation using a compile server upon compilation error\n"
+#endif
+#ifdef HAVE_HTTP_SUPPORT
+    "   --use-http-server=SERVER-SPEC\n"
+    "              specify systemtap http compile server\n"
 #endif
     "   --remote=HOSTNAME\n"
     "              run pass 5 on the specified ssh host.\n"
@@ -677,11 +713,11 @@ systemtap_session::usage (int exitcode)
     "              disable -DSTP_OVERLOAD, -DMAXACTION, and -DMAXTRYACTION limits\n"
     "   --save-uprobes\n"
     "              save uprobes.ko to current directory if it is built from source\n"
-    "   --target-namesapce=PID\n"
+    "   --target-namespace=PID\n"
     "              sets the target namespaces pid to PID\n"
 #if HAVE_MONITOR_LIBS
     "   --monitor=INTERVAL\n"
-    "              enables monitor interfaces\n"
+    "              enables runtime interactive monitoring\n"
 #endif
     , compatible.c_str()) << endl
   ;
@@ -701,6 +737,9 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
   client_options_disallowed_for_unprivileged = "";
   std::set<std::string> additional_unwindsym_modules;
   struct rlimit our_rlimit;
+  bool sysroot_option_seen = false;
+  string kernel_release_value;
+
   while (true)
     {
       char * num_endptr;
@@ -863,9 +902,10 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
         case 'r':
           assert(optarg);
           if (client_options) // NB: no paths!
-            assert_regexp_match("-r parameter from client", optarg, "^[a-z0-9_.-]+$");
+           // Note that '-' must come last in a regex bracket expression.
+            assert_regexp_match("-r parameter from client", optarg, "^[a-z0-9_.+-]+$");
          server_args.push_back (string ("-") + (char)grc + optarg);
-          setup_kernel_release(optarg);
+         kernel_release_value = optarg;
           break;
 
         case 'a':
@@ -954,8 +994,8 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          break;
 
        case 'S':
-          assert_regexp_match ("-S parameter", optarg, "^[0-9]+(,[0-9]+)?$");
           assert(optarg);
+          assert_regexp_match ("-S parameter", optarg, "^[0-9]+(,[0-9]+)?$");
          server_args.push_back (string ("-") + (char)grc + optarg);
          size_option = string (optarg);
          break;
@@ -1060,6 +1100,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
            // privilege level. The server also expects and depends on this behaviour when
            // examining the client-side options passed to it.
            privilege_t newPrivilege;
+           assert(optarg);
            if (strcmp (optarg, "stapdev") == 0)
              newPrivilege = pr_stapdev;
            else if (strcmp (optarg, "stapsys") == 0)
@@ -1190,10 +1231,25 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
            server_trust_spec = "ssl";
          break;
 
+
+#ifdef HAVE_HTTP_SUPPORT
+       case LONG_OPT_USE_HTTP_SERVER:
+         if (client_options) {
+           cerr << _F("ERROR: %s is invalid with %s", "--use-http-server", "--client-options") << endl;
+           return 1;
+         }
+         http_servers.push_back (optarg);
+         break;
+#endif
+
        case LONG_OPT_HELP:
          usage (0);
          break;
 
+       case LONG_OPT_RUN_EXAMPLE:
+         run_example = true;
+         break;
+
          // The caching options should not be available to server clients
        case LONG_OPT_DISABLE_CACHE:
          if (client_options) {
@@ -1220,6 +1276,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          throw exit_exception(EXIT_SUCCESS);
 
        case LONG_OPT_COMPATIBLE:
+          assert(optarg);
          server_args.push_back ("--compatible=" + string(optarg));
           if (strverscmp(optarg, VERSION) > 0) {
             cerr << _F("ERROR: systemtap version %s cannot be compatible with future version %s", VERSION, optarg)
@@ -1316,11 +1373,13 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
            cerr << _F("ERROR: %s is invalid with %s", "--modinfo", "--client-options") << endl;
            return 1;
          }
+          assert(optarg);
          assert_regexp_match("--modinfo parameter", optarg, "^[a-z_][a-z0-9_]*=.+$");
          modinfos.push_back (string(optarg));
          break;
 
        case LONG_OPT_RLIMIT_AS:
+          assert(optarg);
          if(getrlimit(RLIMIT_AS, & our_rlimit))
            cerr << _F("Unable to obtain resource limits for rlimit-as : %s", strerror (errno)) << endl;
          if (strlen(optarg) == 0) {
@@ -1345,6 +1404,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          break;
 
        case LONG_OPT_RLIMIT_CPU:
+          assert(optarg);
          if(getrlimit(RLIMIT_CPU, & our_rlimit))
            cerr << _F("Unable to obtain resource limits for rlimit-cpu : %s", strerror (errno)) << endl;
          if (strlen(optarg) == 0) {
@@ -1365,6 +1425,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          break;
 
        case LONG_OPT_RLIMIT_NPROC:
+          assert(optarg);
          if(getrlimit(RLIMIT_NPROC, & our_rlimit))
            cerr << _F("Unable to obtain resource limits for rlimit-nproc : %s", strerror (errno)) << endl;
          if (strlen(optarg) == 0) {
@@ -1385,6 +1446,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          break;
 
        case LONG_OPT_RLIMIT_STACK:
+          assert(optarg);
          if(getrlimit(RLIMIT_STACK, & our_rlimit))
            cerr << _F("Unable to obtain resource limits for rlimit-stack : %s", strerror (errno)) << endl;
          if (strlen(optarg) == 0) {
@@ -1409,6 +1471,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          break;
 
        case LONG_OPT_RLIMIT_FSIZE:
+          assert(optarg);
          if(getrlimit(RLIMIT_FSIZE, & our_rlimit))
            cerr << _F("Unable to obtain resource limits for rlimit-fsize : %s", strerror (errno)) << endl;
          if (strlen(optarg) == 0) {
@@ -1432,11 +1495,13 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
          if (client_options) {
              cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl;
              return 1;
-         } else if (!sysroot.empty()) {
+         } else if (sysroot_option_seen) {
              cerr << "ERROR: multiple --sysroot options not supported" << endl;
              return 1;
          } else {
-             char *spath = canonicalize_file_name (optarg);
+             char *spath;
+             assert(optarg);
+             spath = canonicalize_file_name (optarg);
              if (spath == NULL) {
                  cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
                  return 1;
@@ -1444,11 +1509,17 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
 
              sysroot = string(spath);
              free (spath);
-             if (sysroot[sysroot.size() - 1] != '/')
-                 sysroot.append("/");
 
-             break;
+             // We do path creation like this:
+             //   sysroot + "/lib/modules"
+             // So, we don't want the sysroot path to end with a '/',
+             // otherwise we'll end up with '/foo//lib/modules'.
+             if (!sysroot.empty() && *(sysroot.end() - 1) == '/') {
+                 sysroot.erase(sysroot.end() - 1);
+             }
          }
+         sysroot_option_seen = true;
+         break;
 
        case LONG_OPT_SYSENV:
          if (client_options) {
@@ -1458,7 +1529,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
              string sysenv_str = optarg;
              string value;
              size_t pos;
-             if (sysroot.empty()) {
+             if (! sysroot_option_seen) {
                  cerr << "ERROR: --sysenv must follow --sysroot" << endl;
                  return 1;
              }
@@ -1499,6 +1570,11 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
             return 1;
           break;
 
+       case LONG_OPT_RUNTIME_BPF:
+          if (!parse_cmdline_runtime ("bpf"))
+            return 1;
+          break;
+
         case LONG_OPT_BENCHMARK_SDT:
           // XXX This option is secret, not supported, subject to change at our whim
           benchmark_sdt_threads = thread::hardware_concurrency();
@@ -1574,6 +1650,10 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
             }
           break;
 
+       case LONG_OPT_NO_GLOBAL_VAR_DISPLAY:
+         no_global_var_display = true;
+         break;
+
        case '?':
          // Invalid/unrecognized option given or argument required, but
          // not given. In both cases getopt_long() will have printed the
@@ -1603,6 +1683,15 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
        }
     }
 
+  if (! kernel_release_value.empty())
+  {
+      setup_kernel_release(kernel_release_value);
+  }
+  else if (! sysroot.empty())
+  {
+      kernel_build_tree = sysroot + "/lib/modules/" + kernel_release  + "/build";
+  }
+
   return 0;
 }
 
@@ -1611,6 +1700,23 @@ systemtap_session::parse_cmdline_runtime (const string& opt_runtime)
 {
   if (opt_runtime == string("kernel"))
     runtime_mode = kernel_runtime;
+  else if (opt_runtime == string("bpf"))
+    {
+#ifndef HAVE_BPF_DECLS
+      cerr << _("ERROR: --runtime=bpf unavailable; this build lacks BPF feature") << endl;
+      version();
+      return false;
+#else
+      runtime_mode = bpf_runtime;
+
+      // TODO: From early BPF development. Remove after making sure the
+      // cache doesn't break anything. Currently removal is blocked
+      // by PR22330 (module name encoded in trace_printk() calls,
+      // using up a lot of stack space for the cacheable script
+      // names).
+      use_cache = use_script_cache = false;
+#endif
+    }
   else if (opt_runtime == string("dyninst"))
     {
 #ifndef HAVE_DYNINST
@@ -1887,6 +1993,11 @@ systemtap_session::parse_kernel_config ()
         clog << _F("Checking \"%s\" failed with error: %s",
                    kernel_config_file.c_str(), strerror(errno)) << endl;
        find_devel_rpms(*this, kernel_build_tree.c_str());
+        // Enable warnings, so that the rpm-installation help is sent
+        // out.  The above message is going to go to stderr anyway
+        // in the case of stap -L without a necessary -devel available.
+        // Might as well make the text more helpful.
+        this->suppress_warnings = false;
        missing_rpm_list_print(*this, "-devel");
        return rc;
     }
@@ -1965,7 +2076,7 @@ systemtap_session::parse_kernel_functions ()
        clog << _F("Kernel symbol table %s unavailable, (%s)",
                   system_map_path.c_str(), strerror(errno)) << endl;
 
-      system_map_path = "/boot/System.map-" + kernel_release;
+      system_map_path = sysroot + "/boot/System.map-" + kernel_release;
       system_map.clear();
       system_map.open(system_map_path.c_str(), ifstream::in);
       if (! system_map.is_open())
@@ -1983,7 +2094,7 @@ systemtap_session::parse_kernel_functions ()
       string address, type, name;
       system_map >> address >> type >> name;
 
-      if (verbose > 3)
+      if (verbose > 5)
         clog << "'" << address << "' '" << type << "' '" << name
              << "'" << endl;
 
@@ -2104,7 +2215,7 @@ void systemtap_session::insert_loaded_modules()
 }
 
 void
-systemtap_session::setup_kernel_release (const char* kstr) 
+systemtap_session::setup_kernel_release (const string& kstr) 
 {
   // Sometimes we may get dupes here... e.g. a server may have a full
   // -r /path/to/kernel followed by a client's -r kernel.
@@ -2135,7 +2246,7 @@ systemtap_session::setup_kernel_release (const char* kstr)
   else
     {
       update_release_sysroot = true;
-      kernel_release = string (kstr);
+      kernel_release = kstr;
       if (!kernel_release.empty())
         kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
 
@@ -2192,6 +2303,25 @@ systemtap_session::register_library_aliases()
     }
 }
 
+// The name of the primary stap file, if any -- usually user_files[0]->name:
+string
+systemtap_session::script_name()
+{
+  if (user_files.empty())
+    return "<unknown>";
+  return user_files[0]->name;
+}
+
+
+// The basename of the primary stap file, if any:
+string
+systemtap_session::script_basename()
+{
+  if (user_files.empty())
+    return "<unknown>";
+  return user_files[0]->name.substr(user_files[0]->name.rfind('/')+1); // basename
+}
+
 
 // Print this given token, but abbreviate it if the last one had the
 // same file name.
@@ -2634,6 +2764,10 @@ systemtap_session::parse_stap_color(const std::string& type)
  *
  * On certain kernels (RHEL7), we also have to check
  * /sys/kernel/security/securelevel.
+ *
+ * On certain kernels (Fedora28+), efi-lockdown may be in effect, but
+ * we lack a way of telling.  RHBZ1638874.  So check an environment
+ * variable "SYSTEMTAP_SIGN" instead for now.
  */
 bool
 systemtap_session::modules_must_be_signed()
@@ -2642,6 +2776,9 @@ systemtap_session::modules_must_be_signed()
   ifstream securelevel("/sys/kernel/security/securelevel");
   char status = 'N';
 
+  if (getenv("SYSTEMTAP_SIGN"))
+    return true;
+
   statm >> status;
   if (status == 'Y')
     return true;
@@ -2649,6 +2786,7 @@ systemtap_session::modules_must_be_signed()
   securelevel >> status;
   if (status == '1')
     return true;
+
   return false;
 }
 
@@ -2749,6 +2887,12 @@ systemtap_session::is_user_file (const string &name)
 bool
 systemtap_session::is_primary_probe (derived_probe *dp)
 {
+
+  // If the probe is synthetically generated, then it's not primary.
+  
+  if (dp->synthetic)
+    return false;
+
   // We check if this probe is from the primary user file by going back to its
   // original probe and checking if that probe was found in the primary user
   // file.
This page took 0.036763 seconds and 5 git commands to generate.