public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Add --sysroot option
@ 2012-01-09 14:51 Wade Farnsworth
  2012-01-20 15:49 ` Wade Farnsworth
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-01-09 14:51 UTC (permalink / raw)
  To: systemtap

This adds a --sysroot option to facilitate different file locations for
user-space processes and libraries at compile-time versus run-time when
generating stap kernel modules for a remote system.

For example if we compile the probe:

process("/bin/foo").begin {}

while passing "--sysroot=/bar/baz" to stap, symbols will be taken from
/bar/baz/bin/foo, but the resulting .ko will still refer to /bin/foo.
This allows the probe to be used on a different machine than the one it
is compiled on, so long as the compiling machine replicates the
necessary files in the sysroot directory.  This is a fairly typical use case
for embedded Linux.

Known limitations:
1. Probes must contain the absolute file path to the process or library.
   If a relative path is used, it will be assumed to be located in the
   top level of the sysroot.
2. Similarly probes on scripts containing "#!/usr/bin/env bash" or similar
   will also assume that the interpreter is located in the sysroot
   top level.
The reason for these limitations is that we do not have access to the
target machine's environment compile-time, so some assumptions must
necessarily be made.

Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com>
---
 session.cxx       |   16 ++++++++++++++++
 session.h         |    1 +
 tapset-itrace.cxx |    5 ++++-
 tapset-utrace.cxx |    5 ++++-
 tapsets.cxx       |   53 +++++++++++++++++++++++++++++++++++++++++------------
 5 files changed, 66 insertions(+), 14 deletions(-)

diff --git a/session.cxx b/session.cxx
index f4ce8a6..1c1adbf 100644
--- a/session.cxx
+++ b/session.cxx
@@ -84,6 +84,7 @@ systemtap_session::systemtap_session ():
   kernel_release = string (buf.release);
   release = kernel_release;
   kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
+  sysroot = string();
   architecture = machine = normalize_machine(buf.machine);
 
   for (unsigned i=0; i<5; i++) perpass_verbose[i]=0;
@@ -534,6 +535,8 @@ systemtap_session::usage (int exitcode)
     "              yes,no,ask,<timeout value>\n"
     "   --dump-probe-types\n"
     "              show a list of available probe types.\n"
+    "   --sysroot=DIR\n"
+    "              specify sysroot directory where executables are located"
     , compatible.c_str()) << endl
   ;
 
@@ -587,6 +590,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
 #define LONG_OPT_PRIVILEGE 28
 #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29
 #define LONG_OPT_MODINFO 30
+#define LONG_OPT_SYSROOT 31
       // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page
       static struct option long_options[] = {
         { "kelf", 0, &long_opt, LONG_OPT_KELF },
@@ -625,6 +629,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
         { "privilege", 1, &long_opt, LONG_OPT_PRIVILEGE },
         { "suppress-handler-errors", 0, &long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS },
         { "modinfo", 1, &long_opt, LONG_OPT_MODINFO },
+        { "sysroot", 1, &long_opt, LONG_OPT_SYSROOT },
         { NULL, 0, NULL, 0 }
       };
       int grc = getopt_long (argc, argv, "hVvtp:I:e:o:R:r:a:m:kgPc:x:D:bs:uqwl:d:L:FS:B:WG:",
@@ -1151,6 +1156,17 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
               modinfos.push_back (string(optarg));
               break;
 
+            case LONG_OPT_SYSROOT:
+              {
+                  const char *spath = canonicalize_file_name (optarg);
+                  if (spath == NULL) {
+                      cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
+                      return 1;
+                  }
+                  sysroot = string(spath) + "/";
+                  break;
+              }
+
             default:
               // NOTREACHED unless one added a getopt option but not a corresponding switch/case:
               cerr << _F("Unhandled long argument id %d", long_opt) << endl;
diff --git a/session.h b/session.h
index 64a22a5..f1a301b 100644
--- a/session.h
+++ b/session.h
@@ -140,6 +140,7 @@ public:
   std::string kernel_base_release;
   std::string kernel_build_tree;
   std::string kernel_source_tree;
+  std::string sysroot;
   std::map<std::string,std::string> kernel_config;
   std::set<std::string> kernel_exports;
   std::string machine;
diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
index 1a9bf67..77811d5 100644
--- a/tapset-itrace.cxx
+++ b/tapset-itrace.cxx
@@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder
     // If we have a path, we need to validate it.
     if (has_path)
       {
-        path = find_executable (path);
+        size_t pos;
+        path = find_executable (sess.sysroot + path);
         sess.unwindsym_modules.insert (path);
+        if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+          path.replace(pos, sess.sysroot.length(), "/");
       }
 
     finished_results.push_back(new itrace_derived_probe(sess, base, location,
diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
index 64ba900..11cf292 100644
--- a/tapset-utrace.cxx
+++ b/tapset-utrace.cxx
@@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder
       }
     else if (has_path)
       {
-        path = find_executable (path);
+        size_t pos;
+        path = find_executable (sess.sysroot + path);
         sess.unwindsym_modules.insert (path);
+	if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+	  path.replace(pos, sess.sysroot.length(), "/");
       }
     else if (has_pid)
       {
diff --git a/tapsets.cxx b/tapsets.cxx
index 177f565..50464dc 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -584,13 +584,13 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params):
       has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
 
       if (has_process)
-        module_val = find_executable (module_val);
+        module_val = find_executable (sess.sysroot + module_val);
       if (has_library)
         {
           if (! contains_glob_chars (library_name))
             {
               path = module_val;
-              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
+              module_val = find_executable (sess.sysroot + library_name, "LD_LIBRARY_PATH");
             }
           else
             path = library_name;
@@ -1139,7 +1139,7 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 {
   string reloc_section; // base section for relocation purposes
   Dwarf_Addr reloc_addr; // relocated
-  const string& module = dw.module_name; // "kernel" or other
+  string& module = dw.module_name; // "kernel" or other
   string funcname = dw_funcname;
 
   assert (! has_absolute); // already handled in dwarf_builder::build()
@@ -1190,6 +1190,14 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 
       if (has_process)
         {
+	  if (!sess.sysroot.empty())
+            {
+              size_t pos;
+              if ((pos = module.find(sess.sysroot)) != string::npos)
+                module.replace(pos, sess.sysroot.length(), "/");
+              if ((pos = path.find(sess.sysroot)) != string::npos)
+                path.replace(pos, sess.sysroot.length(), "/");
+            }
           results.push_back (new uprobe_derived_probe(funcname, filename, line,
                                                       module, reloc_section, addr, reloc_addr,
                                                       *this, scope_die));
@@ -6548,13 +6556,14 @@ dwarf_builder::build(systemtap_session & sess,
     }
   else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS))
       {
+      module_name = sess.sysroot + module_name;
       if(has_null_param(filled_parameters, TOK_PROCESS))
         {
           wordexp_t words;
           int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF);
           if(rc || words.we_wordc <= 0)
             throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND"));
-          module_name = words.we_wordv[0];
+          module_name = sess.sysroot + words.we_wordv[0];
           filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map
           // in the case of TOK_MARK we need to modify locations as well
           if(location->components[0]->functor==TOK_PROCESS &&
@@ -6607,9 +6616,15 @@ dwarf_builder::build(systemtap_session & sess,
                   if (sess.verbose > 1)
                     clog << _F("Expanded process(\"%s\") to process(\"%s\")",
                                module_name.c_str(), eglobbed.c_str()) << endl;
+                  if (!sess.sysroot.empty())
+                    {
+                      size_t pos;
+                      if ((pos = eglobbed.find(sess.sysroot)) != string::npos)
+                        eglobbed.replace(pos, sess.sysroot.length(), "/");
+                    }
 
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (eglobbed));
+                                                    new literal_string (eglobbed));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6681,12 +6696,12 @@ dwarf_builder::build(systemtap_session & sess,
                     if (p3 != string::npos)
                     {
                        string env_path = path.substr(p3);
-                       user_path = find_executable (env_path);
+                       user_path = find_executable (sess.sysroot + env_path);
                     }
                 }
                 else
                 {
-                   user_path = find_executable (path);
+                  user_path = find_executable (sess.sysroot + path);
                 }
 
                 struct stat st;
@@ -6707,8 +6722,12 @@ dwarf_builder::build(systemtap_session & sess,
 
                   // synthesize a new probe_point, with the expanded string
                   probe_point *pp = new probe_point (*location);
+                  string user_path_tgt = user_path;
+                  size_t pos;
+                  if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+                    user_path_tgt.replace(pos, sess.sysroot.length(), "/");
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (user_path.c_str()));
+                                                                            new literal_string (user_path_tgt.c_str()));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6727,7 +6746,7 @@ dwarf_builder::build(systemtap_session & sess,
 
       if(get_param (parameters, TOK_LIBRARY, user_lib)
 	  && user_lib.length() && ! contains_glob_chars (user_lib))
-	module_name = find_executable (user_lib, "LD_LIBRARY_PATH");
+	module_name = find_executable (sess.sysroot + user_lib, "LD_LIBRARY_PATH");
       else
 	module_name = user_path; // canonicalize it
 
@@ -8195,7 +8214,7 @@ struct kprobe_builder: public derived_probe_builder
 
 
 void
-kprobe_builder::build(systemtap_session &,
+kprobe_builder::build(systemtap_session & sess,
 		      probe * base,
 		      probe_point * location,
 		      literal_map_t const & parameters,
@@ -8218,9 +8237,19 @@ kprobe_builder::build(systemtap_session &,
   has_library = get_param (parameters, TOK_LIBRARY, library);
 
   if (has_path)
-    path = find_executable (path);
+    {
+      size_t pos;
+      path = find_executable (sess.sysroot + path);
+      if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+        path.replace(pos, sess.sysroot.length(), "/");
+    }
   if (has_library)
-    library = find_executable (library, "LD_LIBRARY_PATH");
+    {
+      size_t pos;
+      library = find_executable (sess.sysroot + library, "LD_LIBRARY_PATH");
+      if (!sess.sysroot.empty() && ((pos = library.find(sess.sysroot)) != string::npos))
+        library.replace(pos, sess.sysroot.length(), "/");
+    }
 
   if (has_function_str)
     {
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Add --sysroot option
  2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth
@ 2012-01-20 15:49 ` Wade Farnsworth
  2012-01-20 18:11 ` Josh Stone
  2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth
  2 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-01-20 15:49 UTC (permalink / raw)
  To: systemtap

Wade Farnsworth wrote:
> This adds a --sysroot option to facilitate different file locations for
> user-space processes and libraries at compile-time versus run-time when
> generating stap kernel modules for a remote system.
>
> For example if we compile the probe:
>
> process("/bin/foo").begin {}
>
> while passing "--sysroot=/bar/baz" to stap, symbols will be taken from
> /bar/baz/bin/foo, but the resulting .ko will still refer to /bin/foo.
> This allows the probe to be used on a different machine than the one it
> is compiled on, so long as the compiling machine replicates the
> necessary files in the sysroot directory.  This is a fairly typical use case
> for embedded Linux.
>
> Known limitations:
> 1. Probes must contain the absolute file path to the process or library.
>     If a relative path is used, it will be assumed to be located in the
>     top level of the sysroot.
> 2. Similarly probes on scripts containing "#!/usr/bin/env bash" or similar
>     will also assume that the interpreter is located in the sysroot
>     top level.
> The reason for these limitations is that we do not have access to the
> target machine's environment compile-time, so some assumptions must
> necessarily be made.
>
> Signed-off-by: Wade Farnsworth<wade_farnsworth@mentor.com>

Any comments on this patch?  In particular, I'm wondering if I'm on the 
right track here.  Any advice would be appreciated.  Thanks!

-Wade

> ---
>   session.cxx       |   16 ++++++++++++++++
>   session.h         |    1 +
>   tapset-itrace.cxx |    5 ++++-
>   tapset-utrace.cxx |    5 ++++-
>   tapsets.cxx       |   53 +++++++++++++++++++++++++++++++++++++++++------------
>   5 files changed, 66 insertions(+), 14 deletions(-)
>
> diff --git a/session.cxx b/session.cxx
> index f4ce8a6..1c1adbf 100644
> --- a/session.cxx
> +++ b/session.cxx
> @@ -84,6 +84,7 @@ systemtap_session::systemtap_session ():
>     kernel_release = string (buf.release);
>     release = kernel_release;
>     kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
> +  sysroot = string();
>     architecture = machine = normalize_machine(buf.machine);
>
>     for (unsigned i=0; i<5; i++) perpass_verbose[i]=0;
> @@ -534,6 +535,8 @@ systemtap_session::usage (int exitcode)
>       "              yes,no,ask,<timeout value>\n"
>       "   --dump-probe-types\n"
>       "              show a list of available probe types.\n"
> +    "   --sysroot=DIR\n"
> +    "              specify sysroot directory where executables are located"
>       , compatible.c_str())<<  endl
>     ;
>
> @@ -587,6 +590,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
>   #define LONG_OPT_PRIVILEGE 28
>   #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29
>   #define LONG_OPT_MODINFO 30
> +#define LONG_OPT_SYSROOT 31
>         // NB: also see find_hash(), usage(), switch stmt below, stap.1 man page
>         static struct option long_options[] = {
>           { "kelf", 0,&long_opt, LONG_OPT_KELF },
> @@ -625,6 +629,7 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
>           { "privilege", 1,&long_opt, LONG_OPT_PRIVILEGE },
>           { "suppress-handler-errors", 0,&long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS },
>           { "modinfo", 1,&long_opt, LONG_OPT_MODINFO },
> +        { "sysroot", 1,&long_opt, LONG_OPT_SYSROOT },
>           { NULL, 0, NULL, 0 }
>         };
>         int grc = getopt_long (argc, argv, "hVvtp:I:e:o:R:r:a:m:kgPc:x:D:bs:uqwl:d:L:FS:B:WG:",
> @@ -1151,6 +1156,17 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
>                 modinfos.push_back (string(optarg));
>                 break;
>
> +            case LONG_OPT_SYSROOT:
> +              {
> +                  const char *spath = canonicalize_file_name (optarg);
> +                  if (spath == NULL) {
> +                      cerr<<  _F("ERROR: %s is an invalid directory for --sysroot", optarg)<<  endl;
> +                      return 1;
> +                  }
> +                  sysroot = string(spath) + "/";
> +                  break;
> +              }
> +
>               default:
>                 // NOTREACHED unless one added a getopt option but not a corresponding switch/case:
>                 cerr<<  _F("Unhandled long argument id %d", long_opt)<<  endl;
> diff --git a/session.h b/session.h
> index 64a22a5..f1a301b 100644
> --- a/session.h
> +++ b/session.h
> @@ -140,6 +140,7 @@ public:
>     std::string kernel_base_release;
>     std::string kernel_build_tree;
>     std::string kernel_source_tree;
> +  std::string sysroot;
>     std::map<std::string,std::string>  kernel_config;
>     std::set<std::string>  kernel_exports;
>     std::string machine;
> diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
> index 1a9bf67..77811d5 100644
> --- a/tapset-itrace.cxx
> +++ b/tapset-itrace.cxx
> @@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder
>       // If we have a path, we need to validate it.
>       if (has_path)
>         {
> -        path = find_executable (path);
> +        size_t pos;
> +        path = find_executable (sess.sysroot + path);
>           sess.unwindsym_modules.insert (path);
> +        if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +          path.replace(pos, sess.sysroot.length(), "/");
>         }
>
>       finished_results.push_back(new itrace_derived_probe(sess, base, location,
> diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
> index 64ba900..11cf292 100644
> --- a/tapset-utrace.cxx
> +++ b/tapset-utrace.cxx
> @@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder
>         }
>       else if (has_path)
>         {
> -        path = find_executable (path);
> +        size_t pos;
> +        path = find_executable (sess.sysroot + path);
>           sess.unwindsym_modules.insert (path);
> +	if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +	  path.replace(pos, sess.sysroot.length(), "/");
>         }
>       else if (has_pid)
>         {
> diff --git a/tapsets.cxx b/tapsets.cxx
> index 177f565..50464dc 100644
> --- a/tapsets.cxx
> +++ b/tapsets.cxx
> @@ -584,13 +584,13 @@ base_query::base_query(dwflpp&  dw, literal_map_t const&  params):
>         has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
>
>         if (has_process)
> -        module_val = find_executable (module_val);
> +        module_val = find_executable (sess.sysroot + module_val);
>         if (has_library)
>           {
>             if (! contains_glob_chars (library_name))
>               {
>                 path = module_val;
> -              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
> +              module_val = find_executable (sess.sysroot + library_name, "LD_LIBRARY_PATH");
>               }
>             else
>               path = library_name;
> @@ -1139,7 +1139,7 @@ dwarf_query::add_probe_point(const string&  dw_funcname,
>   {
>     string reloc_section; // base section for relocation purposes
>     Dwarf_Addr reloc_addr; // relocated
> -  const string&  module = dw.module_name; // "kernel" or other
> +  string&  module = dw.module_name; // "kernel" or other
>     string funcname = dw_funcname;
>
>     assert (! has_absolute); // already handled in dwarf_builder::build()
> @@ -1190,6 +1190,14 @@ dwarf_query::add_probe_point(const string&  dw_funcname,
>
>         if (has_process)
>           {
> +	  if (!sess.sysroot.empty())
> +            {
> +              size_t pos;
> +              if ((pos = module.find(sess.sysroot)) != string::npos)
> +                module.replace(pos, sess.sysroot.length(), "/");
> +              if ((pos = path.find(sess.sysroot)) != string::npos)
> +                path.replace(pos, sess.sysroot.length(), "/");
> +            }
>             results.push_back (new uprobe_derived_probe(funcname, filename, line,
>                                                         module, reloc_section, addr, reloc_addr,
>                                                         *this, scope_die));
> @@ -6548,13 +6556,14 @@ dwarf_builder::build(systemtap_session&  sess,
>       }
>     else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS))
>         {
> +      module_name = sess.sysroot + module_name;
>         if(has_null_param(filled_parameters, TOK_PROCESS))
>           {
>             wordexp_t words;
>             int rc = wordexp(sess.cmd.c_str(),&words, WRDE_NOCMD|WRDE_UNDEF);
>             if(rc || words.we_wordc<= 0)
>               throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND"));
> -          module_name = words.we_wordv[0];
> +          module_name = sess.sysroot + words.we_wordv[0];
>             filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map
>             // in the case of TOK_MARK we need to modify locations as well
>             if(location->components[0]->functor==TOK_PROCESS&&
> @@ -6607,9 +6616,15 @@ dwarf_builder::build(systemtap_session&  sess,
>                     if (sess.verbose>  1)
>                       clog<<  _F("Expanded process(\"%s\") to process(\"%s\")",
>                                  module_name.c_str(), eglobbed.c_str())<<  endl;
> +                  if (!sess.sysroot.empty())
> +                    {
> +                      size_t pos;
> +                      if ((pos = eglobbed.find(sess.sysroot)) != string::npos)
> +                        eglobbed.replace(pos, sess.sysroot.length(), "/");
> +                    }
>
>                     probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
> -                                                                            new literal_string (eglobbed));
> +                                                    new literal_string (eglobbed));
>                     ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
>                     pp->components[0] = ppc;
>
> @@ -6681,12 +6696,12 @@ dwarf_builder::build(systemtap_session&  sess,
>                       if (p3 != string::npos)
>                       {
>                          string env_path = path.substr(p3);
> -                       user_path = find_executable (env_path);
> +                       user_path = find_executable (sess.sysroot + env_path);
>                       }
>                   }
>                   else
>                   {
> -                   user_path = find_executable (path);
> +                  user_path = find_executable (sess.sysroot + path);
>                   }
>
>                   struct stat st;
> @@ -6707,8 +6722,12 @@ dwarf_builder::build(systemtap_session&  sess,
>
>                     // synthesize a new probe_point, with the expanded string
>                     probe_point *pp = new probe_point (*location);
> +                  string user_path_tgt = user_path;
> +                  size_t pos;
> +                  if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +                    user_path_tgt.replace(pos, sess.sysroot.length(), "/");
>                     probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
> -                                                                            new literal_string (user_path.c_str()));
> +                                                                            new literal_string (user_path_tgt.c_str()));
>                     ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
>                     pp->components[0] = ppc;
>
> @@ -6727,7 +6746,7 @@ dwarf_builder::build(systemtap_session&  sess,
>
>         if(get_param (parameters, TOK_LIBRARY, user_lib)
>   	&&  user_lib.length()&&  ! contains_glob_chars (user_lib))
> -	module_name = find_executable (user_lib, "LD_LIBRARY_PATH");
> +	module_name = find_executable (sess.sysroot + user_lib, "LD_LIBRARY_PATH");
>         else
>   	module_name = user_path; // canonicalize it
>
> @@ -8195,7 +8214,7 @@ struct kprobe_builder: public derived_probe_builder
>
>
>   void
> -kprobe_builder::build(systemtap_session&,
> +kprobe_builder::build(systemtap_session&  sess,
>   		      probe * base,
>   		      probe_point * location,
>   		      literal_map_t const&  parameters,
> @@ -8218,9 +8237,19 @@ kprobe_builder::build(systemtap_session&,
>     has_library = get_param (parameters, TOK_LIBRARY, library);
>
>     if (has_path)
> -    path = find_executable (path);
> +    {
> +      size_t pos;
> +      path = find_executable (sess.sysroot + path);
> +      if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +        path.replace(pos, sess.sysroot.length(), "/");
> +    }
>     if (has_library)
> -    library = find_executable (library, "LD_LIBRARY_PATH");
> +    {
> +      size_t pos;
> +      library = find_executable (sess.sysroot + library, "LD_LIBRARY_PATH");
> +      if (!sess.sysroot.empty()&&  ((pos = library.find(sess.sysroot)) != string::npos))
> +        library.replace(pos, sess.sysroot.length(), "/");
> +    }
>
>     if (has_function_str)
>       {

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Add --sysroot option
  2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth
  2012-01-20 15:49 ` Wade Farnsworth
@ 2012-01-20 18:11 ` Josh Stone
  2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth
  2 siblings, 0 replies; 15+ messages in thread
From: Josh Stone @ 2012-01-20 18:11 UTC (permalink / raw)
  To: Wade Farnsworth; +Cc: systemtap

On 01/09/2012 06:51 AM, Wade Farnsworth wrote:
> This adds a --sysroot option to facilitate different file locations for
> user-space processes and libraries at compile-time versus run-time when
> generating stap kernel modules for a remote system.

This enhancement is PR12331, so please prefix as such in your patch's
subject.  If you like, you may also claim assignment on the bug itself.
  http://sourceware.org/bugzilla/show_bug.cgi?id=12331

> 
> For example if we compile the probe:
> 
> process("/bin/foo").begin {}
> 
> while passing "--sysroot=/bar/baz" to stap, symbols will be taken from
> /bar/baz/bin/foo, but the resulting .ko will still refer to /bin/foo.
> This allows the probe to be used on a different machine than the one it
> is compiled on, so long as the compiling machine replicates the
> necessary files in the sysroot directory.  This is a fairly typical use case
> for embedded Linux.
> 
> Known limitations:
> 1. Probes must contain the absolute file path to the process or library.
>    If a relative path is used, it will be assumed to be located in the
>    top level of the sysroot.
> 2. Similarly probes on scripts containing "#!/usr/bin/env bash" or similar
>    will also assume that the interpreter is located in the sysroot
>    top level.
> The reason for these limitations is that we do not have access to the
> target machine's environment compile-time, so some assumptions must
> necessarily be made.

It is a bit sticky that we don't know the target environment PATH or
LD_LIBRARY_PATH.  However, I think even assuming the same as this host
is better than nothing, so one can at least benefit from the usual
/bin:/usr/bin:... sort of paths.  If need be, we can add another option
for this, something like --sysenv=PATH=/bin:/system/bin:etc.

So at least the basic part of this can be achieved by making
find_executable() smarter about sysroot.  In calls like this:

> diff --git a/tapsets.cxx b/tapsets.cxx
> index 177f565..50464dc 100644
> --- a/tapsets.cxx
> +++ b/tapsets.cxx
> @@ -584,13 +584,13 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params):
>        has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
>  
>        if (has_process)
> -        module_val = find_executable (module_val);
> +        module_val = find_executable (sess.sysroot + module_val);
>        if (has_library)
>          {
>            if (! contains_glob_chars (library_name))
>              {
>                path = module_val;
> -              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
> +              module_val = find_executable (sess.sysroot + library_name, "LD_LIBRARY_PATH");
>              }
>            else
>              path = library_name;

Notice that find_executable() takes an environment variable to to use
for path searching (and defaults to "PATH").  I think the sysroot needs
to be taken as a separate parameter in these calls, so it can be
searched appropriately.

The current behavior of find_executable() is if the name already has a
'/', return as-is, else search the path.  The new behavior needs to also
prefix everything, so for names with '/' return sysroot/name, else
search sysroot/PATH1/name, sysroot/PATH2/name, etc. and return whatever
matches.

This can still be escaped by relative paths that traverse upwards, e.g.
"../../../usr/bin/foo".  User shoots self in foot, news at 11.  But this
may matter for the client-server mode if a server has chosen to build
from some sysroot.  Perhaps ".." paths should be disallowed when sysroot
is in use?  I'm not really sure how well we can really protect this, but
better to at least try.

Also, I think clients should not be allowed to pass sysroot at all,
given that they don't really know how the server is laid out in the
first place.  See how the client_options flag is used in restricting
other options, and please do the same for --sysroot.

Your patch focuses on process/library paths, but I think there are a few
other cases that will need sysroot treatment too.  For one, I would
expect that some of the dwarf processing will need munging, especially
for the case with split debuginfo from the main binary.  Another is for
locating the kernel binaries and build tree -- if -r is given as a path,
that's probably fine, but for plain versions we should probably look in
sysroot/lib/modules/RELEASE/...

Thanks for tackling this feature, and sorry for the delayed review.

Josh

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv
  2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth
  2012-01-20 15:49 ` Wade Farnsworth
  2012-01-20 18:11 ` Josh Stone
@ 2012-02-09 18:26 ` Wade Farnsworth
  2012-02-17 14:39   ` Wade Farnsworth
                     ` (2 more replies)
  2 siblings, 3 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-02-09 18:26 UTC (permalink / raw)
  To: systemtap, jistone

This adds new command-line options to facilitate different file locations at
compile-time versus run-time when generating stap kernel modules for a remote
system:

1. --sysroot=DIR
   Specifies a separate filesystem for the remote system on the local
   system.  The following stap functionalities will make use of this:

   a. When compiling process and library probes with a remote filesystem path
      (e.g. process("/bin/foo") with --sysroot=/bar/baz).  In this case symbols
      will be taken from the local filesystem (/bar/baz/bin/foo), but the
      resulting .ko will still contain paths on the remote filesystem
      (/bin/foo).

   b. When passing a kernel release with -r (not a full path), the kernel
      build directory will be expected in the sysroot.

   c. When DWARF debug info is contained in a separate file from the
      executable, the sysroot is used to find the debug info files.

   d. All calls to find_executable() search the path passed in the
      argument env_path relative to the sysroot.  For example if
      PATH=/bin/foo, and --sysroot=/bar/baz is provided, then
      find_executable() called with env_path == "PATH" will search
      /bar/baz/bin/foo.

   e. stap attempts to detect if a path in a probe would be outside of the
      sysroot and errors appropriately.  This situation may occur, for
      example, if the path contains several ".." directories.

2. --sysenv=VAR=VALUE
   Specifies a different environment variable for the remote system as opposed
   to the local one, and that the value on the remote system should be used.
   Currently only valid env_path arguments to find_executable() are handled
   (i.e. PATH, LD_LIBRARY_PATH).  If --sysroot is provided and --sysenv
   is omitted, then the local environment relative to the sysroot will
   be used.

These options are disabled for systemtap clients.

Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com>
---

Josh, I believe I have implemented all of your comments on the previous version
of this patch.  Any further suggestions are welcome!

-v2: Implemented several improvements per Josh Stone's comment.

 cmdline.cxx       |    2 +
 cmdline.h         |    2 +
 dwflpp.cxx        |    4 +-
 hash.cxx          |    3 +-
 session.cxx       |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 session.h         |    3 ++
 setupdwfl.cxx     |   39 ++++++++++++++++++++++++++----
 setupdwfl.h       |    3 +-
 tapset-itrace.cxx |    5 +++-
 tapset-utrace.cxx |    5 +++-
 tapsets.cxx       |   64 ++++++++++++++++++++++++++++++++++++++------------
 translate.cxx     |    6 ++--
 util.cxx          |   28 +++++++++++++++++----
 util.h            |    3 ++
 14 files changed, 197 insertions(+), 37 deletions(-)

diff --git a/cmdline.cxx b/cmdline.cxx
index 88e02f9..881a5c3 100644
--- a/cmdline.cxx
+++ b/cmdline.cxx
@@ -50,5 +50,7 @@ struct option stap_long_options[] = {
   { "privilege", 1, &stap_long_opt, LONG_OPT_PRIVILEGE },
   { "suppress-handler-errors", 0, &stap_long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS },
   { "modinfo", 1, &stap_long_opt, LONG_OPT_MODINFO },
+  { "sysroot", 1, &stap_long_opt, LONG_OPT_SYSROOT },
+  { "sysenv", 1, &stap_long_opt, LONG_OPT_SYSENV },
   { NULL, 0, NULL, 0 }
 };
diff --git a/cmdline.h b/cmdline.h
index 3229a7b..680f290 100644
--- a/cmdline.h
+++ b/cmdline.h
@@ -44,6 +44,8 @@ extern "C" {
 #define LONG_OPT_PRIVILEGE 28
 #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29
 #define LONG_OPT_MODINFO 30
+#define LONG_OPT_SYSROOT 31
+#define LONG_OPT_SYSENV 32
 
 // NB: when adding new options, consider very carefully whether they
 // should be restricted from stap clients (after --client-options)!
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 4d78187..17fd5c6 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session & s, bool debuginfo_n
     {
       if (debuginfo_needed) {
         // Suggest a likely kernel dir to find debuginfo rpm for
-        string dir = string("/lib/modules/" + sess.kernel_release );
+        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
         find_debug_rpms(sess, dir.c_str());
       }
       throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
@@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed)
     {
       if (debuginfo_needed) {
         // Suggest a likely kernel dir to find debuginfo rpm for
-        string dir = string("/lib/modules/" + sess.kernel_release );
+        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
         find_debug_rpms(sess, dir.c_str());
       }
       throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
diff --git a/hash.cxx b/hash.cxx
index c435a03..69334f5 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -133,6 +133,7 @@ void create_hash_log(const string &type_str, const string &parms, const string &
 static const hash&
 get_base_hash (systemtap_session& s)
 {
+  map<string, char*> dummy;
   if (s.base_hash)
     return *s.base_hash;
 
@@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s)
   // Hash compiler path, size, and mtime.  We're just going to assume
   // we'll be using gcc. XXX: getting kbuild to spit out out would be
   // better, especially since this is fooled by ccache.
-  h.add_path("Compiler ", find_executable("gcc"));
+  h.add_path("Compiler ", find_executable("gcc", "", dummy));
 
   // Hash the systemtap size and mtime.  We could use VERSION/DATE,
   // but when developing systemtap that doesn't work well (since you
diff --git a/session.cxx b/session.cxx
index 24c329a..2c5be33 100644
--- a/session.cxx
+++ b/session.cxx
@@ -20,6 +20,7 @@
 #include "util.h"
 #include "cmdline.h"
 #include "git_version.h"
+#include "setupdwfl.h"
 
 #include <cerrno>
 #include <cstdlib>
@@ -86,6 +87,8 @@ systemtap_session::systemtap_session ():
   kernel_release = string (buf.release);
   release = kernel_release;
   kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
+  sysroot = "";
+  update_release_sysroot = false;
   architecture = machine = normalize_machine(buf.machine);
 
   for (unsigned i=0; i<5; i++) perpass_verbose[i]=0;
@@ -533,6 +536,13 @@ systemtap_session::usage (int exitcode)
     "              yes,no,ask,<timeout value>\n"
     "   --dump-probe-types\n"
     "              show a list of available probe types.\n"
+    "   --sysroot=DIR\n"
+    "              specify sysroot directory where executables are located.\n"
+    "   --sysenv=VAR=VALUE\n"
+    "              provide an alternate value for an environment variable\n"
+    "              where the value on a remote system differs.  Path\n"
+    "              variables (e.g. PATH, LD_LIBRARY_PATH) are assumed to be\n"
+    "              relatve to the sysroot.\n"
     , compatible.c_str()) << endl
   ;
 
@@ -1097,6 +1107,56 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
               modinfos.push_back (string(optarg));
               break;
 
+            case LONG_OPT_SYSROOT:
+              if (client_options) {
+                  cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl;
+                  return 1;
+              } else {
+                  const char *spath = canonicalize_file_name (optarg);
+                  if (spath == NULL) {
+                      cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
+                      return 1;
+                  }
+
+                  sysroot = string(spath);
+                  if (sysroot[sysroot.size() - 1] != '/')
+                      sysroot.append("/");
+
+                  if (update_release_sysroot)
+                      kernel_build_tree = sysroot + kernel_build_tree;
+
+                  debuginfo_path_insert_sysroot(sysroot);
+
+                  break;
+              }
+            case LONG_OPT_SYSENV:
+              if (client_options) {
+                  cerr << _F("ERROR: %s invalid with %s", "--sysenv", "--client-options") << endl;
+                  return 1;
+              } else {
+                  string sysenv_str = optarg;
+                  string value_str;
+		  char * value;
+                  size_t pos;
+                  if (sysroot.empty()) {
+                      cerr << "ERROR: --sysenv must follow --sysroot" << endl;
+                      return 1;
+                  }
+
+                  pos = sysenv_str.find("=");
+                  if (pos == string::npos) {
+                      cerr << _F("ERROR: %s is an invalid argument for --sysenv", optarg) << endl;
+                      return 1;
+                  }
+
+                  value_str = sysenv_str.substr(pos + 1);
+		  value = new char[value_str.size()+1];
+		  strcpy(value, value_str.c_str());
+                  sysenv[sysenv_str.substr(0, pos)] = value;
+
+                  break;
+              }
+
             default:
               // NOTREACHED unless one added a getopt option but not a corresponding switch/case:
               cerr << _F("Unhandled long argument id %d", stap_long_opt) << endl;
@@ -1387,8 +1447,13 @@ systemtap_session::setup_kernel_release (const char* kstr)
   else
     {
       kernel_release = string (kstr);
-      if (!kernel_release.empty())
+      if (!kernel_release.empty()) {
         kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
+        if (sysroot.empty())
+          update_release_sysroot = true;
+        else
+          kernel_build_tree = sysroot + kernel_build_tree;
+      }
 
       // PR10745
       // Let's not look for the kernel_source_tree; it's definitely
diff --git a/session.h b/session.h
index e128b2f..b5b8d82 100644
--- a/session.h
+++ b/session.h
@@ -140,6 +140,9 @@ public:
   std::string kernel_base_release;
   std::string kernel_build_tree;
   std::string kernel_source_tree;
+  std::string sysroot;
+  std::map<std::string,char *> sysenv;
+  bool update_release_sysroot;
   std::map<std::string,std::string> kernel_config;
   std::set<std::string> kernel_exports;
   std::string machine;
diff --git a/setupdwfl.cxx b/setupdwfl.cxx
index 82bc42a..fbffaf0 100644
--- a/setupdwfl.cxx
+++ b/setupdwfl.cxx
@@ -39,14 +39,14 @@ extern "C" {
 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
 static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build";
 static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
-static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr);
+static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr);
 
 // NB: kernel_build_tree doesn't enter into this, as it's for
 // kernel-side modules only.
 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
 static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug";
-static const char *debuginfo_usr_path = (debuginfo_env_arr
-					 ?: debuginfo_usr_path_arr);
+static char *debuginfo_usr_path = (char *)(debuginfo_env_arr
+					   ?: debuginfo_usr_path_arr);
 
 // A pointer to the current systemtap session for use only by a few
 // dwfl calls. DO NOT rely on this, as it is cleared after use.
@@ -146,7 +146,10 @@ setup_mod_deps()
     }
   else
     {
-      modulesdep = "/lib/modules/";
+      string sysroot = "";
+      if (current_session_for_find_debuginfo)
+        sysroot = current_session_for_find_debuginfo->sysroot;
+      modulesdep = sysroot + "/lib/modules/";
       modulesdep += elfutils_kernel_path;
       modulesdep += "/modules.dep";
     }
@@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename)
     }
 }
 
+static char * path_insert_sysroot(string sysroot, string path)
+{
+  char * path_new;
+  size_t pos = 1;
+  if (path[0] == '/')
+    path.replace(0, 1, sysroot);
+  while (true) {
+    pos = path.find(":/", pos);
+    if (pos == string::npos)
+      break;
+    path.replace(pos, 2, ":" + sysroot);
+    ++pos;
+  }
+  path_new = new char[path.size()+1];
+  strcpy (path_new, path.c_str());
+  return path_new;
+}
+
+void debuginfo_path_insert_sysroot(string sysroot)
+{
+  debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path);
+  debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path);
+}
+
 static DwflPtr
 setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
 {
@@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
   // no way to set the dwfl_callback.debuginfo_path and always
   // passs the plain kernel_release here.  So instead we have to
   // hard-code this magic here.
-  if (s.kernel_build_tree == string("/lib/modules/"
+  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
 				    + s.kernel_release
 				    + "/build"))
     elfutils_kernel_path = s.kernel_release;
@@ -413,7 +440,7 @@ setup_dwfl_kernel(const std::set<std::string> &names,
 }
 
 DwflPtr
-setup_dwfl_user(const std::string &name)
+setup_dwfl_user(const std::string &name, systemtap_session &s)
 {
   if (user_dwfl != NULL
       && user_modset.size() == 1
diff --git a/setupdwfl.h b/setupdwfl.h
index 48f9105..4686574 100644
--- a/setupdwfl.h
+++ b/setupdwfl.h
@@ -50,7 +50,7 @@ DwflPtr setup_dwfl_kernel(const std::set<std::string> &names,
 			  unsigned *found,
 			  systemtap_session &s);
 
-DwflPtr setup_dwfl_user(const std::string &name);
+DwflPtr setup_dwfl_user(const std::string &name, systemtap_session &s);
 DwflPtr setup_dwfl_user(std::vector<std::string>::const_iterator &begin,
 		        const std::vector<std::string>::const_iterator &end,
 		        bool all_needed, systemtap_session &s);
@@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod,
 int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex);
 std::string get_kernel_build_id (systemtap_session &s);
 int download_kernel_debuginfo (systemtap_session &s, std::string hex);
+void debuginfo_path_insert_sysroot(std::string sysroot);
 
 #endif
diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
index 1a9bf67..0e623fe 100644
--- a/tapset-itrace.cxx
+++ b/tapset-itrace.cxx
@@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder
     // If we have a path, we need to validate it.
     if (has_path)
       {
-        path = find_executable (path);
+        size_t pos;
+        path = find_executable (path, sess.sysroot, sess.sysenv);
         sess.unwindsym_modules.insert (path);
+        if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+          path.replace(pos, sess.sysroot.length(), "/");
       }
 
     finished_results.push_back(new itrace_derived_probe(sess, base, location,
diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
index 64ba900..133d42a 100644
--- a/tapset-utrace.cxx
+++ b/tapset-utrace.cxx
@@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder
       }
     else if (has_path)
       {
-        path = find_executable (path);
+        size_t pos;
+        path = find_executable (path, sess.sysroot, sess.sysenv);
         sess.unwindsym_modules.insert (path);
+	if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+	  path.replace(pos, sess.sysroot.length(), "/");
       }
     else if (has_pid)
       {
diff --git a/tapsets.cxx b/tapsets.cxx
index cb56170..6cdb8e1 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -584,13 +584,14 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params):
       has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
 
       if (has_process)
-        module_val = find_executable (module_val);
+        module_val = find_executable (module_val, sess.sysroot, sess.sysenv);
       if (has_library)
         {
           if (! contains_glob_chars (library_name))
             {
               path = module_val;
-              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
+              module_val = find_executable (library_name, sess.sysroot,
+                                            sess.sysenv, "LD_LIBRARY_PATH");
             }
           else
             path = library_name;
@@ -1137,7 +1138,7 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 {
   string reloc_section; // base section for relocation purposes
   Dwarf_Addr reloc_addr; // relocated
-  const string& module = dw.module_name; // "kernel" or other
+  string& module = dw.module_name; // "kernel" or other
   string funcname = dw_funcname;
 
   assert (! has_absolute); // already handled in dwarf_builder::build()
@@ -1188,6 +1189,14 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 
       if (has_process)
         {
+	  if (!sess.sysroot.empty())
+            {
+              size_t pos;
+              if ((pos = module.find(sess.sysroot)) != string::npos)
+                module.replace(pos, sess.sysroot.length(), "/");
+              if ((pos = path.find(sess.sysroot)) != string::npos)
+                path.replace(pos, sess.sysroot.length(), "/");
+            }
           results.push_back (new uprobe_derived_probe(funcname, filename, line,
                                                       module, reloc_section, addr, reloc_addr,
                                                       *this, scope_die));
@@ -2051,7 +2060,8 @@ query_one_library (const char *library, dwflpp & dw,
 {
   if (dw.function_name_matches_pattern(library, user_lib))
     {
-      string library_path = find_executable (library, "LD_LIBRARY_PATH");
+      string library_path = find_executable (library, "", dw.sess.sysenv,
+                                             "LD_LIBRARY_PATH");
       probe_point* specific_loc = new probe_point(*base_loc);
       specific_loc->optional = true;
       vector<probe_point::component*> derived_comps;
@@ -3906,7 +3916,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
 	    }
 	  else
 	    {
-	      module = find_executable (module); // canonicalize it
+	      module = find_executable (module, "", s.sysenv); // canonicalize it
 	      dw = db.get_user_dw(s, module);
 	    }
 	}
@@ -6546,13 +6556,14 @@ dwarf_builder::build(systemtap_session & sess,
     }
   else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS))
       {
+      module_name = sess.sysroot + module_name;
       if(has_null_param(filled_parameters, TOK_PROCESS))
         {
           wordexp_t words;
           int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF);
           if(rc || words.we_wordc <= 0)
             throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND"));
-          module_name = words.we_wordv[0];
+          module_name = sess.sysroot + words.we_wordv[0];
           filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map
           // in the case of TOK_MARK we need to modify locations as well
           if(location->components[0]->functor==TOK_PROCESS &&
@@ -6605,9 +6616,15 @@ dwarf_builder::build(systemtap_session & sess,
                   if (sess.verbose > 1)
                     clog << _F("Expanded process(\"%s\") to process(\"%s\")",
                                module_name.c_str(), eglobbed.c_str()) << endl;
+                  if (!sess.sysroot.empty())
+                    {
+                      size_t pos;
+                      if ((pos = eglobbed.find(sess.sysroot)) != string::npos)
+                        eglobbed.replace(pos, sess.sysroot.length(), "/");
+                    }
 
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (eglobbed));
+                                                    new literal_string (eglobbed));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6633,7 +6650,7 @@ dwarf_builder::build(systemtap_session & sess,
 
       // PR13338: unquote glob results
       module_name = unescape_glob_chars (module_name);
-      user_path = find_executable (module_name); // canonicalize it
+      user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it
 
       // if the executable starts with "#!", we look for the interpreter of the script
       {
@@ -6679,12 +6696,13 @@ dwarf_builder::build(systemtap_session & sess,
                     if (p3 != string::npos)
                     {
                        string env_path = path.substr(p3);
-                       user_path = find_executable (env_path);
+                       user_path = find_executable (env_path, sess.sysroot,
+                                                    sess.sysenv);
                     }
                 }
                 else
                 {
-                   user_path = find_executable (path);
+                  user_path = find_executable (path, sess.sysroot, sess.sysenv);
                 }
 
                 struct stat st;
@@ -6705,8 +6723,12 @@ dwarf_builder::build(systemtap_session & sess,
 
                   // synthesize a new probe_point, with the expanded string
                   probe_point *pp = new probe_point (*location);
+                  string user_path_tgt = user_path;
+                  size_t pos;
+                  if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+                    user_path_tgt.replace(pos, sess.sysroot.length(), "/");
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (user_path.c_str()));
+                                                                            new literal_string (user_path_tgt.c_str()));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6725,7 +6747,8 @@ dwarf_builder::build(systemtap_session & sess,
 
       if(get_param (parameters, TOK_LIBRARY, user_lib)
 	  && user_lib.length() && ! contains_glob_chars (user_lib))
-	module_name = find_executable (user_lib, "LD_LIBRARY_PATH");
+	module_name = find_executable (user_lib, sess.sysroot, sess.sysenv,
+                                       "LD_LIBRARY_PATH");
       else
 	module_name = user_path; // canonicalize it
 
@@ -8189,7 +8212,7 @@ struct kprobe_builder: public derived_probe_builder
 
 
 void
-kprobe_builder::build(systemtap_session &,
+kprobe_builder::build(systemtap_session & sess,
 		      probe * base,
 		      probe_point * location,
 		      literal_map_t const & parameters,
@@ -8212,9 +8235,20 @@ kprobe_builder::build(systemtap_session &,
   has_library = get_param (parameters, TOK_LIBRARY, library);
 
   if (has_path)
-    path = find_executable (path);
+    {
+      size_t pos;
+      path = find_executable (path, sess.sysroot, sess.sysenv);
+      if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
+        path.replace(pos, sess.sysroot.length(), "/");
+    }
   if (has_library)
-    library = find_executable (library, "LD_LIBRARY_PATH");
+    {
+      size_t pos;
+      library = find_executable (library, sess.sysroot, sess.sysenv,
+                                 "LD_LIBRARY_PATH");
+      if (!sess.sysroot.empty() && ((pos = library.find(sess.sysroot)) != string::npos))
+        library.replace(pos, sess.sysroot.length(), "/");
+    }
 
   if (has_function_str)
     {
diff --git a/translate.cxx b/translate.cxx
index 97847a8..70c4751 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session &s)
   // having the BUILDDIR we need to do a deep search (the specific
   // arch name dir in the kernel build tree is unknown).
   string vdso_dir;
-  if (s.kernel_build_tree == string("/lib/modules/"
+  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
 				    + s.kernel_release
 				    + "/build"))
-    vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso";
+    vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso";
   else
     vdso_dir = s.kernel_build_tree + "/arch/";
 
@@ -6353,7 +6353,7 @@ emit_symbol_data (systemtap_session& s)
       string modname = *it;
       assert (modname.length() != 0);
       if (! is_user_module (modname)) continue;
-      DwflPtr dwfl_ptr = setup_dwfl_user (modname);
+      DwflPtr dwfl_ptr = setup_dwfl_user (modname, s);
       Dwfl *dwfl = dwfl_ptr.get()->dwfl;
       if (dwfl != NULL) // tolerate missing data; will warn below
         {
diff --git a/util.cxx b/util.cxx
index 93cf12a..4158f0d 100644
--- a/util.cxx
+++ b/util.cxx
@@ -345,7 +345,8 @@ tokenize_cxx(const string& str, vector<string>& tokens)
 // same policy as execvp().  A program name not containing a slash
 // will be searched along the $PATH.
 
-string find_executable(const string& name, const string& env_path)
+string find_executable(const string& name, const string& sysroot,
+		       map<string, char*>& sysenv, const string& env_path)
 {
   string retpath;
 
@@ -356,11 +357,15 @@ string find_executable(const string& name, const string& env_path)
 
   if (name.find('/') != string::npos) // slash in the path already?
     {
-      retpath = name;
+      retpath = sysroot + name;
     }
   else // Nope, search $PATH.
     {
-      char *path = getenv(env_path.c_str());
+      char *path;
+      if (sysenv.count(env_path) != 0)
+        path = sysenv[env_path];
+      else
+        path = getenv(env_path.c_str());
       if (path)
         {
           // Split PATH up.
@@ -370,7 +375,7 @@ string find_executable(const string& name, const string& env_path)
           // Search the path looking for the first executable of the right name.
           for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
             {
-              string fname = *i + "/" + name;
+              string fname = sysroot + *i + "/" + name;
               const char *f = fname.c_str();
 
               // Look for a normal executable file.
@@ -389,13 +394,24 @@ string find_executable(const string& name, const string& env_path)
   // Could not find the program on the $PATH.  We'll just fall back to
   // the unqualified name, which our caller will probably fail with.
   if (retpath == "")
-    retpath = name;
+    retpath = sysroot + name;
 
   // Canonicalize the path name.
   char *cf = canonicalize_file_name (retpath.c_str());
   if (cf)
     {
-      retpath = string(cf);
+      string scf = string(cf);
+      if (sysroot.empty())
+        retpath = scf;
+      else {
+        int pos = scf.find(sysroot);
+        if (pos == 0)
+          retpath = scf;
+        else {
+          cerr << _F("ERROR: file %s not in sysroot %s", cf, sysroot.c_str()) << endl;
+          exit(1);
+        }
+      }
       free (cf);
     }
 
diff --git a/util.h b/util.h
index e576036..44e41e4 100644
--- a/util.h
+++ b/util.h
@@ -12,6 +12,7 @@
 #include <cctype>
 #include <set>
 #include <iomanip>
+#include <map>
 extern "C" {
 #include <libintl.h>
 #include <locale.h>
@@ -51,6 +52,8 @@ void tokenize(const std::string& str, std::vector<std::string>& tokens,
 	      const std::string& delimiters);
 void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens);
 std::string find_executable(const std::string& name,
+			    const std::string& sysroot,
+			    std::map<std::string,char *>& sysenv,
 			    const std::string& env_path = "PATH");
 const std::string cmdstr_quoted(const std::string& cmd);
 const std::string cmdstr_join(const std::vector<std::string>& cmds);
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv
  2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth
@ 2012-02-17 14:39   ` Wade Farnsworth
  2012-02-24 22:56   ` Josh Stone
  2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
  2 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-02-17 14:39 UTC (permalink / raw)
  To: systemtap, jistone

Hi all,

Anyone have a chance to review this yet?

Thanks in advance!

-Wade

Wade Farnsworth wrote:
> This adds new command-line options to facilitate different file locations at
> compile-time versus run-time when generating stap kernel modules for a remote
> system:
>
> 1. --sysroot=DIR
>     Specifies a separate filesystem for the remote system on the local
>     system.  The following stap functionalities will make use of this:
>
>     a. When compiling process and library probes with a remote filesystem path
>        (e.g. process("/bin/foo") with --sysroot=/bar/baz).  In this case symbols
>        will be taken from the local filesystem (/bar/baz/bin/foo), but the
>        resulting .ko will still contain paths on the remote filesystem
>        (/bin/foo).
>
>     b. When passing a kernel release with -r (not a full path), the kernel
>        build directory will be expected in the sysroot.
>
>     c. When DWARF debug info is contained in a separate file from the
>        executable, the sysroot is used to find the debug info files.
>
>     d. All calls to find_executable() search the path passed in the
>        argument env_path relative to the sysroot.  For example if
>        PATH=/bin/foo, and --sysroot=/bar/baz is provided, then
>        find_executable() called with env_path == "PATH" will search
>        /bar/baz/bin/foo.
>
>     e. stap attempts to detect if a path in a probe would be outside of the
>        sysroot and errors appropriately.  This situation may occur, for
>        example, if the path contains several ".." directories.
>
> 2. --sysenv=VAR=VALUE
>     Specifies a different environment variable for the remote system as opposed
>     to the local one, and that the value on the remote system should be used.
>     Currently only valid env_path arguments to find_executable() are handled
>     (i.e. PATH, LD_LIBRARY_PATH).  If --sysroot is provided and --sysenv
>     is omitted, then the local environment relative to the sysroot will
>     be used.
>
> These options are disabled for systemtap clients.
>
> Signed-off-by: Wade Farnsworth<wade_farnsworth@mentor.com>
> ---
>
> Josh, I believe I have implemented all of your comments on the previous version
> of this patch.  Any further suggestions are welcome!
>
> -v2: Implemented several improvements per Josh Stone's comment.
>
>   cmdline.cxx       |    2 +
>   cmdline.h         |    2 +
>   dwflpp.cxx        |    4 +-
>   hash.cxx          |    3 +-
>   session.cxx       |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>   session.h         |    3 ++
>   setupdwfl.cxx     |   39 ++++++++++++++++++++++++++----
>   setupdwfl.h       |    3 +-
>   tapset-itrace.cxx |    5 +++-
>   tapset-utrace.cxx |    5 +++-
>   tapsets.cxx       |   64 ++++++++++++++++++++++++++++++++++++++------------
>   translate.cxx     |    6 ++--
>   util.cxx          |   28 +++++++++++++++++----
>   util.h            |    3 ++
>   14 files changed, 197 insertions(+), 37 deletions(-)
>
> diff --git a/cmdline.cxx b/cmdline.cxx
> index 88e02f9..881a5c3 100644
> --- a/cmdline.cxx
> +++ b/cmdline.cxx
> @@ -50,5 +50,7 @@ struct option stap_long_options[] = {
>     { "privilege", 1,&stap_long_opt, LONG_OPT_PRIVILEGE },
>     { "suppress-handler-errors", 0,&stap_long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS },
>     { "modinfo", 1,&stap_long_opt, LONG_OPT_MODINFO },
> +  { "sysroot", 1,&stap_long_opt, LONG_OPT_SYSROOT },
> +  { "sysenv", 1,&stap_long_opt, LONG_OPT_SYSENV },
>     { NULL, 0, NULL, 0 }
>   };
> diff --git a/cmdline.h b/cmdline.h
> index 3229a7b..680f290 100644
> --- a/cmdline.h
> +++ b/cmdline.h
> @@ -44,6 +44,8 @@ extern "C" {
>   #define LONG_OPT_PRIVILEGE 28
>   #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29
>   #define LONG_OPT_MODINFO 30
> +#define LONG_OPT_SYSROOT 31
> +#define LONG_OPT_SYSENV 32
>
>   // NB: when adding new options, consider very carefully whether they
>   // should be restricted from stap clients (after --client-options)!
> diff --git a/dwflpp.cxx b/dwflpp.cxx
> index 4d78187..17fd5c6 100644
> --- a/dwflpp.cxx
> +++ b/dwflpp.cxx
> @@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string&  name, systemtap_session&  s, bool debuginfo_n
>       {
>         if (debuginfo_needed) {
>           // Suggest a likely kernel dir to find debuginfo rpm for
> -        string dir = string("/lib/modules/" + sess.kernel_release );
> +        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
>           find_debug_rpms(sess, dir.c_str());
>         }
>         throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
> @@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string>  &names, bool debuginfo_needed)
>       {
>         if (debuginfo_needed) {
>           // Suggest a likely kernel dir to find debuginfo rpm for
> -        string dir = string("/lib/modules/" + sess.kernel_release );
> +        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
>           find_debug_rpms(sess, dir.c_str());
>         }
>         throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
> diff --git a/hash.cxx b/hash.cxx
> index c435a03..69334f5 100644
> --- a/hash.cxx
> +++ b/hash.cxx
> @@ -133,6 +133,7 @@ void create_hash_log(const string&type_str, const string&parms, const string&
>   static const hash&
>   get_base_hash (systemtap_session&  s)
>   {
> +  map<string, char*>  dummy;
>     if (s.base_hash)
>       return *s.base_hash;
>
> @@ -158,7 +159,7 @@ get_base_hash (systemtap_session&  s)
>     // Hash compiler path, size, and mtime.  We're just going to assume
>     // we'll be using gcc. XXX: getting kbuild to spit out out would be
>     // better, especially since this is fooled by ccache.
> -  h.add_path("Compiler ", find_executable("gcc"));
> +  h.add_path("Compiler ", find_executable("gcc", "", dummy));
>
>     // Hash the systemtap size and mtime.  We could use VERSION/DATE,
>     // but when developing systemtap that doesn't work well (since you
> diff --git a/session.cxx b/session.cxx
> index 24c329a..2c5be33 100644
> --- a/session.cxx
> +++ b/session.cxx
> @@ -20,6 +20,7 @@
>   #include "util.h"
>   #include "cmdline.h"
>   #include "git_version.h"
> +#include "setupdwfl.h"
>
>   #include<cerrno>
>   #include<cstdlib>
> @@ -86,6 +87,8 @@ systemtap_session::systemtap_session ():
>     kernel_release = string (buf.release);
>     release = kernel_release;
>     kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
> +  sysroot = "";
> +  update_release_sysroot = false;
>     architecture = machine = normalize_machine(buf.machine);
>
>     for (unsigned i=0; i<5; i++) perpass_verbose[i]=0;
> @@ -533,6 +536,13 @@ systemtap_session::usage (int exitcode)
>       "              yes,no,ask,<timeout value>\n"
>       "   --dump-probe-types\n"
>       "              show a list of available probe types.\n"
> +    "   --sysroot=DIR\n"
> +    "              specify sysroot directory where executables are located.\n"
> +    "   --sysenv=VAR=VALUE\n"
> +    "              provide an alternate value for an environment variable\n"
> +    "              where the value on a remote system differs.  Path\n"
> +    "              variables (e.g. PATH, LD_LIBRARY_PATH) are assumed to be\n"
> +    "              relatve to the sysroot.\n"
>       , compatible.c_str())<<  endl
>     ;
>
> @@ -1097,6 +1107,56 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
>                 modinfos.push_back (string(optarg));
>                 break;
>
> +            case LONG_OPT_SYSROOT:
> +              if (client_options) {
> +                  cerr<<  _F("ERROR: %s invalid with %s", "--sysroot", "--client-options")<<  endl;
> +                  return 1;
> +              } else {
> +                  const char *spath = canonicalize_file_name (optarg);
> +                  if (spath == NULL) {
> +                      cerr<<  _F("ERROR: %s is an invalid directory for --sysroot", optarg)<<  endl;
> +                      return 1;
> +                  }
> +
> +                  sysroot = string(spath);
> +                  if (sysroot[sysroot.size() - 1] != '/')
> +                      sysroot.append("/");
> +
> +                  if (update_release_sysroot)
> +                      kernel_build_tree = sysroot + kernel_build_tree;
> +
> +                  debuginfo_path_insert_sysroot(sysroot);
> +
> +                  break;
> +              }
> +            case LONG_OPT_SYSENV:
> +              if (client_options) {
> +                  cerr<<  _F("ERROR: %s invalid with %s", "--sysenv", "--client-options")<<  endl;
> +                  return 1;
> +              } else {
> +                  string sysenv_str = optarg;
> +                  string value_str;
> +		  char * value;
> +                  size_t pos;
> +                  if (sysroot.empty()) {
> +                      cerr<<  "ERROR: --sysenv must follow --sysroot"<<  endl;
> +                      return 1;
> +                  }
> +
> +                  pos = sysenv_str.find("=");
> +                  if (pos == string::npos) {
> +                      cerr<<  _F("ERROR: %s is an invalid argument for --sysenv", optarg)<<  endl;
> +                      return 1;
> +                  }
> +
> +                  value_str = sysenv_str.substr(pos + 1);
> +		  value = new char[value_str.size()+1];
> +		  strcpy(value, value_str.c_str());
> +                  sysenv[sysenv_str.substr(0, pos)] = value;
> +
> +                  break;
> +              }
> +
>               default:
>                 // NOTREACHED unless one added a getopt option but not a corresponding switch/case:
>                 cerr<<  _F("Unhandled long argument id %d", stap_long_opt)<<  endl;
> @@ -1387,8 +1447,13 @@ systemtap_session::setup_kernel_release (const char* kstr)
>     else
>       {
>         kernel_release = string (kstr);
> -      if (!kernel_release.empty())
> +      if (!kernel_release.empty()) {
>           kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
> +        if (sysroot.empty())
> +          update_release_sysroot = true;
> +        else
> +          kernel_build_tree = sysroot + kernel_build_tree;
> +      }
>
>         // PR10745
>         // Let's not look for the kernel_source_tree; it's definitely
> diff --git a/session.h b/session.h
> index e128b2f..b5b8d82 100644
> --- a/session.h
> +++ b/session.h
> @@ -140,6 +140,9 @@ public:
>     std::string kernel_base_release;
>     std::string kernel_build_tree;
>     std::string kernel_source_tree;
> +  std::string sysroot;
> +  std::map<std::string,char *>  sysenv;
> +  bool update_release_sysroot;
>     std::map<std::string,std::string>  kernel_config;
>     std::set<std::string>  kernel_exports;
>     std::string machine;
> diff --git a/setupdwfl.cxx b/setupdwfl.cxx
> index 82bc42a..fbffaf0 100644
> --- a/setupdwfl.cxx
> +++ b/setupdwfl.cxx
> @@ -39,14 +39,14 @@ extern "C" {
>   // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
>   static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build";
>   static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
> -static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr);
> +static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr);
>
>   // NB: kernel_build_tree doesn't enter into this, as it's for
>   // kernel-side modules only.
>   // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
>   static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug";
> -static const char *debuginfo_usr_path = (debuginfo_env_arr
> -					 ?: debuginfo_usr_path_arr);
> +static char *debuginfo_usr_path = (char *)(debuginfo_env_arr
> +					   ?: debuginfo_usr_path_arr);
>
>   // A pointer to the current systemtap session for use only by a few
>   // dwfl calls. DO NOT rely on this, as it is cleared after use.
> @@ -146,7 +146,10 @@ setup_mod_deps()
>       }
>     else
>       {
> -      modulesdep = "/lib/modules/";
> +      string sysroot = "";
> +      if (current_session_for_find_debuginfo)
> +        sysroot = current_session_for_find_debuginfo->sysroot;
> +      modulesdep = sysroot + "/lib/modules/";
>         modulesdep += elfutils_kernel_path;
>         modulesdep += "/modules.dep";
>       }
> @@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename)
>       }
>   }
>
> +static char * path_insert_sysroot(string sysroot, string path)
> +{
> +  char * path_new;
> +  size_t pos = 1;
> +  if (path[0] == '/')
> +    path.replace(0, 1, sysroot);
> +  while (true) {
> +    pos = path.find(":/", pos);
> +    if (pos == string::npos)
> +      break;
> +    path.replace(pos, 2, ":" + sysroot);
> +    ++pos;
> +  }
> +  path_new = new char[path.size()+1];
> +  strcpy (path_new, path.c_str());
> +  return path_new;
> +}
> +
> +void debuginfo_path_insert_sysroot(string sysroot)
> +{
> +  debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path);
> +  debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path);
> +}
> +
>   static DwflPtr
>   setup_dwfl_kernel (unsigned *modules_found, systemtap_session&s)
>   {
> @@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session&s)
>     // no way to set the dwfl_callback.debuginfo_path and always
>     // passs the plain kernel_release here.  So instead we have to
>     // hard-code this magic here.
> -  if (s.kernel_build_tree == string("/lib/modules/"
> +  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
>   				    + s.kernel_release
>   				    + "/build"))
>       elfutils_kernel_path = s.kernel_release;
> @@ -413,7 +440,7 @@ setup_dwfl_kernel(const std::set<std::string>  &names,
>   }
>
>   DwflPtr
> -setup_dwfl_user(const std::string&name)
> +setup_dwfl_user(const std::string&name, systemtap_session&s)
>   {
>     if (user_dwfl != NULL
>         &&  user_modset.size() == 1
> diff --git a/setupdwfl.h b/setupdwfl.h
> index 48f9105..4686574 100644
> --- a/setupdwfl.h
> +++ b/setupdwfl.h
> @@ -50,7 +50,7 @@ DwflPtr setup_dwfl_kernel(const std::set<std::string>  &names,
>   			  unsigned *found,
>   			  systemtap_session&s);
>
> -DwflPtr setup_dwfl_user(const std::string&name);
> +DwflPtr setup_dwfl_user(const std::string&name, systemtap_session&s);
>   DwflPtr setup_dwfl_user(std::vector<std::string>::const_iterator&begin,
>   		        const std::vector<std::string>::const_iterator&end,
>   		        bool all_needed, systemtap_session&s);
> @@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod,
>   int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex);
>   std::string get_kernel_build_id (systemtap_session&s);
>   int download_kernel_debuginfo (systemtap_session&s, std::string hex);
> +void debuginfo_path_insert_sysroot(std::string sysroot);
>
>   #endif
> diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
> index 1a9bf67..0e623fe 100644
> --- a/tapset-itrace.cxx
> +++ b/tapset-itrace.cxx
> @@ -114,8 +114,11 @@ struct itrace_builder: public derived_probe_builder
>       // If we have a path, we need to validate it.
>       if (has_path)
>         {
> -        path = find_executable (path);
> +        size_t pos;
> +        path = find_executable (path, sess.sysroot, sess.sysenv);
>           sess.unwindsym_modules.insert (path);
> +        if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +          path.replace(pos, sess.sysroot.length(), "/");
>         }
>
>       finished_results.push_back(new itrace_derived_probe(sess, base, location,
> diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
> index 64ba900..133d42a 100644
> --- a/tapset-utrace.cxx
> +++ b/tapset-utrace.cxx
> @@ -679,8 +679,11 @@ struct utrace_builder: public derived_probe_builder
>         }
>       else if (has_path)
>         {
> -        path = find_executable (path);
> +        size_t pos;
> +        path = find_executable (path, sess.sysroot, sess.sysenv);
>           sess.unwindsym_modules.insert (path);
> +	if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +	  path.replace(pos, sess.sysroot.length(), "/");
>         }
>       else if (has_pid)
>         {
> diff --git a/tapsets.cxx b/tapsets.cxx
> index cb56170..6cdb8e1 100644
> --- a/tapsets.cxx
> +++ b/tapsets.cxx
> @@ -584,13 +584,14 @@ base_query::base_query(dwflpp&  dw, literal_map_t const&  params):
>         has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
>
>         if (has_process)
> -        module_val = find_executable (module_val);
> +        module_val = find_executable (module_val, sess.sysroot, sess.sysenv);
>         if (has_library)
>           {
>             if (! contains_glob_chars (library_name))
>               {
>                 path = module_val;
> -              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
> +              module_val = find_executable (library_name, sess.sysroot,
> +                                            sess.sysenv, "LD_LIBRARY_PATH");
>               }
>             else
>               path = library_name;
> @@ -1137,7 +1138,7 @@ dwarf_query::add_probe_point(const string&  dw_funcname,
>   {
>     string reloc_section; // base section for relocation purposes
>     Dwarf_Addr reloc_addr; // relocated
> -  const string&  module = dw.module_name; // "kernel" or other
> +  string&  module = dw.module_name; // "kernel" or other
>     string funcname = dw_funcname;
>
>     assert (! has_absolute); // already handled in dwarf_builder::build()
> @@ -1188,6 +1189,14 @@ dwarf_query::add_probe_point(const string&  dw_funcname,
>
>         if (has_process)
>           {
> +	  if (!sess.sysroot.empty())
> +            {
> +              size_t pos;
> +              if ((pos = module.find(sess.sysroot)) != string::npos)
> +                module.replace(pos, sess.sysroot.length(), "/");
> +              if ((pos = path.find(sess.sysroot)) != string::npos)
> +                path.replace(pos, sess.sysroot.length(), "/");
> +            }
>             results.push_back (new uprobe_derived_probe(funcname, filename, line,
>                                                         module, reloc_section, addr, reloc_addr,
>                                                         *this, scope_die));
> @@ -2051,7 +2060,8 @@ query_one_library (const char *library, dwflpp&  dw,
>   {
>     if (dw.function_name_matches_pattern(library, user_lib))
>       {
> -      string library_path = find_executable (library, "LD_LIBRARY_PATH");
> +      string library_path = find_executable (library, "", dw.sess.sysenv,
> +                                             "LD_LIBRARY_PATH");
>         probe_point* specific_loc = new probe_point(*base_loc);
>         specific_loc->optional = true;
>         vector<probe_point::component*>  derived_comps;
> @@ -3906,7 +3916,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
>   	    }
>   	  else
>   	    {
> -	      module = find_executable (module); // canonicalize it
> +	      module = find_executable (module, "", s.sysenv); // canonicalize it
>   	      dw = db.get_user_dw(s, module);
>   	    }
>   	}
> @@ -6546,13 +6556,14 @@ dwarf_builder::build(systemtap_session&  sess,
>       }
>     else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS))
>         {
> +      module_name = sess.sysroot + module_name;
>         if(has_null_param(filled_parameters, TOK_PROCESS))
>           {
>             wordexp_t words;
>             int rc = wordexp(sess.cmd.c_str(),&words, WRDE_NOCMD|WRDE_UNDEF);
>             if(rc || words.we_wordc<= 0)
>               throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND"));
> -          module_name = words.we_wordv[0];
> +          module_name = sess.sysroot + words.we_wordv[0];
>             filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map
>             // in the case of TOK_MARK we need to modify locations as well
>             if(location->components[0]->functor==TOK_PROCESS&&
> @@ -6605,9 +6616,15 @@ dwarf_builder::build(systemtap_session&  sess,
>                     if (sess.verbose>  1)
>                       clog<<  _F("Expanded process(\"%s\") to process(\"%s\")",
>                                  module_name.c_str(), eglobbed.c_str())<<  endl;
> +                  if (!sess.sysroot.empty())
> +                    {
> +                      size_t pos;
> +                      if ((pos = eglobbed.find(sess.sysroot)) != string::npos)
> +                        eglobbed.replace(pos, sess.sysroot.length(), "/");
> +                    }
>
>                     probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
> -                                                                            new literal_string (eglobbed));
> +                                                    new literal_string (eglobbed));
>                     ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
>                     pp->components[0] = ppc;
>
> @@ -6633,7 +6650,7 @@ dwarf_builder::build(systemtap_session&  sess,
>
>         // PR13338: unquote glob results
>         module_name = unescape_glob_chars (module_name);
> -      user_path = find_executable (module_name); // canonicalize it
> +      user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it
>
>         // if the executable starts with "#!", we look for the interpreter of the script
>         {
> @@ -6679,12 +6696,13 @@ dwarf_builder::build(systemtap_session&  sess,
>                       if (p3 != string::npos)
>                       {
>                          string env_path = path.substr(p3);
> -                       user_path = find_executable (env_path);
> +                       user_path = find_executable (env_path, sess.sysroot,
> +                                                    sess.sysenv);
>                       }
>                   }
>                   else
>                   {
> -                   user_path = find_executable (path);
> +                  user_path = find_executable (path, sess.sysroot, sess.sysenv);
>                   }
>
>                   struct stat st;
> @@ -6705,8 +6723,12 @@ dwarf_builder::build(systemtap_session&  sess,
>
>                     // synthesize a new probe_point, with the expanded string
>                     probe_point *pp = new probe_point (*location);
> +                  string user_path_tgt = user_path;
> +                  size_t pos;
> +                  if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +                    user_path_tgt.replace(pos, sess.sysroot.length(), "/");
>                     probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
> -                                                                            new literal_string (user_path.c_str()));
> +                                                                            new literal_string (user_path_tgt.c_str()));
>                     ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
>                     pp->components[0] = ppc;
>
> @@ -6725,7 +6747,8 @@ dwarf_builder::build(systemtap_session&  sess,
>
>         if(get_param (parameters, TOK_LIBRARY, user_lib)
>   	&&  user_lib.length()&&  ! contains_glob_chars (user_lib))
> -	module_name = find_executable (user_lib, "LD_LIBRARY_PATH");
> +	module_name = find_executable (user_lib, sess.sysroot, sess.sysenv,
> +                                       "LD_LIBRARY_PATH");
>         else
>   	module_name = user_path; // canonicalize it
>
> @@ -8189,7 +8212,7 @@ struct kprobe_builder: public derived_probe_builder
>
>
>   void
> -kprobe_builder::build(systemtap_session&,
> +kprobe_builder::build(systemtap_session&  sess,
>   		      probe * base,
>   		      probe_point * location,
>   		      literal_map_t const&  parameters,
> @@ -8212,9 +8235,20 @@ kprobe_builder::build(systemtap_session&,
>     has_library = get_param (parameters, TOK_LIBRARY, library);
>
>     if (has_path)
> -    path = find_executable (path);
> +    {
> +      size_t pos;
> +      path = find_executable (path, sess.sysroot, sess.sysenv);
> +      if (!sess.sysroot.empty()&&  ((pos = path.find(sess.sysroot)) != string::npos))
> +        path.replace(pos, sess.sysroot.length(), "/");
> +    }
>     if (has_library)
> -    library = find_executable (library, "LD_LIBRARY_PATH");
> +    {
> +      size_t pos;
> +      library = find_executable (library, sess.sysroot, sess.sysenv,
> +                                 "LD_LIBRARY_PATH");
> +      if (!sess.sysroot.empty()&&  ((pos = library.find(sess.sysroot)) != string::npos))
> +        library.replace(pos, sess.sysroot.length(), "/");
> +    }
>
>     if (has_function_str)
>       {
> diff --git a/translate.cxx b/translate.cxx
> index 97847a8..70c4751 100644
> --- a/translate.cxx
> +++ b/translate.cxx
> @@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session&s)
>     // having the BUILDDIR we need to do a deep search (the specific
>     // arch name dir in the kernel build tree is unknown).
>     string vdso_dir;
> -  if (s.kernel_build_tree == string("/lib/modules/"
> +  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
>   				    + s.kernel_release
>   				    + "/build"))
> -    vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso";
> +    vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso";
>     else
>       vdso_dir = s.kernel_build_tree + "/arch/";
>
> @@ -6353,7 +6353,7 @@ emit_symbol_data (systemtap_session&  s)
>         string modname = *it;
>         assert (modname.length() != 0);
>         if (! is_user_module (modname)) continue;
> -      DwflPtr dwfl_ptr = setup_dwfl_user (modname);
> +      DwflPtr dwfl_ptr = setup_dwfl_user (modname, s);
>         Dwfl *dwfl = dwfl_ptr.get()->dwfl;
>         if (dwfl != NULL) // tolerate missing data; will warn below
>           {
> diff --git a/util.cxx b/util.cxx
> index 93cf12a..4158f0d 100644
> --- a/util.cxx
> +++ b/util.cxx
> @@ -345,7 +345,8 @@ tokenize_cxx(const string&  str, vector<string>&  tokens)
>   // same policy as execvp().  A program name not containing a slash
>   // will be searched along the $PATH.
>
> -string find_executable(const string&  name, const string&  env_path)
> +string find_executable(const string&  name, const string&  sysroot,
> +		       map<string, char*>&  sysenv, const string&  env_path)
>   {
>     string retpath;
>
> @@ -356,11 +357,15 @@ string find_executable(const string&  name, const string&  env_path)
>
>     if (name.find('/') != string::npos) // slash in the path already?
>       {
> -      retpath = name;
> +      retpath = sysroot + name;
>       }
>     else // Nope, search $PATH.
>       {
> -      char *path = getenv(env_path.c_str());
> +      char *path;
> +      if (sysenv.count(env_path) != 0)
> +        path = sysenv[env_path];
> +      else
> +        path = getenv(env_path.c_str());
>         if (path)
>           {
>             // Split PATH up.
> @@ -370,7 +375,7 @@ string find_executable(const string&  name, const string&  env_path)
>             // Search the path looking for the first executable of the right name.
>             for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
>               {
> -              string fname = *i + "/" + name;
> +              string fname = sysroot + *i + "/" + name;
>                 const char *f = fname.c_str();
>
>                 // Look for a normal executable file.
> @@ -389,13 +394,24 @@ string find_executable(const string&  name, const string&  env_path)
>     // Could not find the program on the $PATH.  We'll just fall back to
>     // the unqualified name, which our caller will probably fail with.
>     if (retpath == "")
> -    retpath = name;
> +    retpath = sysroot + name;
>
>     // Canonicalize the path name.
>     char *cf = canonicalize_file_name (retpath.c_str());
>     if (cf)
>       {
> -      retpath = string(cf);
> +      string scf = string(cf);
> +      if (sysroot.empty())
> +        retpath = scf;
> +      else {
> +        int pos = scf.find(sysroot);
> +        if (pos == 0)
> +          retpath = scf;
> +        else {
> +          cerr<<  _F("ERROR: file %s not in sysroot %s", cf, sysroot.c_str())<<  endl;
> +          exit(1);
> +        }
> +      }
>         free (cf);
>       }
>
> diff --git a/util.h b/util.h
> index e576036..44e41e4 100644
> --- a/util.h
> +++ b/util.h
> @@ -12,6 +12,7 @@
>   #include<cctype>
>   #include<set>
>   #include<iomanip>
> +#include<map>
>   extern "C" {
>   #include<libintl.h>
>   #include<locale.h>
> @@ -51,6 +52,8 @@ void tokenize(const std::string&  str, std::vector<std::string>&  tokens,
>   	      const std::string&  delimiters);
>   void tokenize_cxx(const std::string&  str, std::vector<std::string>&  tokens);
>   std::string find_executable(const std::string&  name,
> +			    const std::string&  sysroot,
> +			    std::map<std::string,char *>&  sysenv,
>   			    const std::string&  env_path = "PATH");
>   const std::string cmdstr_quoted(const std::string&  cmd);
>   const std::string cmdstr_join(const std::vector<std::string>&  cmds);

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv
  2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth
  2012-02-17 14:39   ` Wade Farnsworth
@ 2012-02-24 22:56   ` Josh Stone
  2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
  2 siblings, 0 replies; 15+ messages in thread
From: Josh Stone @ 2012-02-24 22:56 UTC (permalink / raw)
  To: Wade Farnsworth; +Cc: systemtap

Looks pretty good.  I found a few things in review, noted below, but
otherwise I think we can go ahead and push this into the repo, and patch
any other issues as they arise.

We should have at least some minimal testing for these options.  It's
hard since the testsuite can't assume any location of a real sysroot,
but at least it should be sanity checked that something like this
doesn't break:  stap --sysroot=/ --sysenv=PATH=$PATH ...

Docs are needed too -- please update stap.1 and NEWS.

Thanks,
Josh


(review is heavily snipped, but hopefully it makes sense...)

On 02/09/2012 10:26 AM, Wade Farnsworth wrote:
>    // Hash compiler path, size, and mtime.  We're just going to assume
>    // we'll be using gcc. XXX: getting kbuild to spit out out would be
>    // better, especially since this is fooled by ccache.
> -  h.add_path("Compiler ", find_executable("gcc"));
> +  h.add_path("Compiler ", find_executable("gcc", "", dummy));

Not your fault, but that comment is getting more urgent. (or rather,
this way of hashing gcc is getting more irrelevent.)  Tracking the file
info of a ccache wrapper is not helpful, and this is also missing the
boat if CROSS_COMPILE is used.  May have to look at kbuild again, or
manually emulate kbuild's logic in choosing a compiler...

> @@ -86,6 +87,8 @@ systemtap_session::systemtap_session ():
>    kernel_release = string (buf.release);
>    release = kernel_release;
>    kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
> +  sysroot = "";
> +  update_release_sysroot = false;

These two and sysenv should be addressed in the session copy-ctor too.

> +            case LONG_OPT_SYSROOT:
> +              if (client_options) {
> +                  cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl;
> +                  return 1;
> +              } else {
> +                  const char *spath = canonicalize_file_name (optarg);
> +                  if (spath == NULL) {
> +                      cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
> +                      return 1;
> +                  }
> +
> +                  sysroot = string(spath);
> +                  if (sysroot[sysroot.size() - 1] != '/')
> +                      sysroot.append("/");
> +
> +                  if (update_release_sysroot)
> +                      kernel_build_tree = sysroot + kernel_build_tree;

This method of "update_release_sysroot" feels convoluted to me.  For
one, if --sysroot occurs multiple times, it will get prepended every
time.  (If there are other reasons to prohibit multiple sysroot, then
please check that.)

How about instead, just delay sysroot prepending until after all arg
processing?  I think in passes_0_4() right at the start of pass 0 is
better, just before the comment that says:

 // Now that no further changes to s.kernel_build_tree can occur [...]

> +
> +                  debuginfo_path_insert_sysroot(sysroot);

This too should probably wait until options are all settled.

>  DwflPtr
> -setup_dwfl_user(const std::string &name)
> +setup_dwfl_user(const std::string &name, systemtap_session &s)
>  {
>    if (user_dwfl != NULL
>        && user_modset.size() == 1

Missing code to make use of the new "s" here?

> +        if (!sess.sysroot.empty() && ((pos = path.find(sess.sysroot)) != string::npos))
> +          path.replace(pos, sess.sysroot.length(), "/");

IMHO, this replacement is common enough to deserve a function.

>    // Canonicalize the path name.
>    char *cf = canonicalize_file_name (retpath.c_str());
>    if (cf)
>      {
> -      retpath = string(cf);
> +      string scf = string(cf);
> +      if (sysroot.empty())
> +        retpath = scf;
> +      else {
> +        int pos = scf.find(sysroot);
> +        if (pos == 0)
> +          retpath = scf;
> +        else {
> +          cerr << _F("ERROR: file %s not in sysroot %s", cf, sysroot.c_str()) << endl;
> +          exit(1);

We need to do better than an exit(1) here, because there will be
temporary files and possibly --remote connections that need to be
cleaned up.  Probably "throw runtime_error" will suffice instead.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 0/3] PR12331: Introduce stap options --sysroot and --sysenv
  2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth
  2012-02-17 14:39   ` Wade Farnsworth
  2012-02-24 22:56   ` Josh Stone
@ 2012-03-02 14:47   ` Wade Farnsworth
  2012-03-02 14:48     ` [PATCH v3 1/3] " Wade Farnsworth
                       ` (3 more replies)
  2 siblings, 4 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-02 14:47 UTC (permalink / raw)
  To: systemtap, jistone

This patchset introduces --sysroot and --sysenv options for stap, which
improve functionality in environments where the compiling system differs
from the one running the probes.

See Patch 1/3's description for more details on what has been implemented.

v2: Implemented several improvements per Josh Stone's comments.
v3: Further improvements per Josh Stone.  Include documentation and test cases
    for the new options.

Wade Farnsworth (3):
  PR12331: Introduce stap options --sysroot and --sysenv
  PR12331: Document --sysroot and --sysenv
  PR12331: Add testcase for --sysroot and --sysenv

 NEWS                                        |    3 +
 cmdline.cxx                                 |    2 +
 cmdline.h                                   |    2 +
 dwflpp.cxx                                  |    4 +-
 hash.cxx                                    |    3 +-
 main.cxx                                    |    9 ++++
 session.cxx                                 |   62 +++++++++++++++++++++++++++
 session.h                                   |    3 +
 setupdwfl.cxx                               |   37 ++++++++++++++--
 setupdwfl.h                                 |    1 +
 stap.1                                      |   11 +++++
 tapset-itrace.cxx                           |    3 +-
 tapset-utrace.cxx                           |    3 +-
 tapsets.cxx                                 |   54 +++++++++++++++++------
 tapsets.h                                   |    1 +
 testsuite/systemtap.base/sysroot_sysenv.exp |   15 ++++++
 testsuite/systemtap.base/sysroot_sysenv.stp |    3 +
 translate.cxx                               |    4 +-
 util.cxx                                    |   26 +++++++++---
 util.h                                      |    3 +
 20 files changed, 216 insertions(+), 33 deletions(-)
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 1/3] PR12331: Introduce stap options --sysroot and --sysenv
  2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
@ 2012-03-02 14:48     ` Wade Farnsworth
  2012-03-02 14:48     ` [PATCH v3 2/3] PR12331: Document " Wade Farnsworth
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-02 14:48 UTC (permalink / raw)
  To: systemtap, jistone

This adds new command-line options to facilitate different file locations at
compile-time versus run-time when generating stap kernel modules for a remote
system:

1. --sysroot=DIR
   Specifies a separate filesystem for the remote system on the local
   system.  The following stap functionalities will make use of this:

   a. When compiling process and library probes with a remote filesystem path
      (e.g. process("/bin/foo") with --sysroot=/bar/baz).  In this case symbols
      will be taken from the local filesystem (/bar/baz/bin/foo), but the
      resulting .ko will still contain paths on the remote filesystem
      (/bin/foo).

   b. When passing a kernel release with -r (not a full path), the kernel
      build directory will be expected in the sysroot.

   c. When DWARF debug info is contained in a separate file from the
      executable, the sysroot is used to find the debug info files.

   d. All calls to find_executable() search the path passed in the
      argument env_path relative to the sysroot.  For example if
      PATH=/bin/foo, and --sysroot=/bar/baz is provided, then
      find_executable() called with env_path == "PATH" will search
      /bar/baz/bin/foo.

   e. stap attempts to detect if a path in a probe would be outside of the
      sysroot and errors appropriately.  This situation may occur, for
      example, if the path contains several ".." directories.

2. --sysenv=VAR=VALUE
   Specifies a different environment variable for the remote system as opposed
   to the local one, and that the value on the remote system should be used.
   Currently only valid env_path arguments to find_executable() are handled
   (i.e. PATH, LD_LIBRARY_PATH).  If --sysroot is provided and --sysenv
   is omitted, then the local environment relative to the sysroot will
   be used.

These options are disabled for systemtap clients.

Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com>
---
 cmdline.cxx       |    2 +
 cmdline.h         |    2 +
 dwflpp.cxx        |    4 +-
 hash.cxx          |    3 +-
 main.cxx          |    9 +++++++
 session.cxx       |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 session.h         |    3 ++
 setupdwfl.cxx     |   37 +++++++++++++++++++++++++++----
 setupdwfl.h       |    1 +
 tapset-itrace.cxx |    3 +-
 tapset-utrace.cxx |    3 +-
 tapsets.cxx       |   54 +++++++++++++++++++++++++++++++++------------
 tapsets.h         |    1 +
 translate.cxx     |    4 +-
 util.cxx          |   26 +++++++++++++++++-----
 util.h            |    3 ++
 16 files changed, 184 insertions(+), 33 deletions(-)

diff --git a/cmdline.cxx b/cmdline.cxx
index 88e02f9..881a5c3 100644
--- a/cmdline.cxx
+++ b/cmdline.cxx
@@ -50,5 +50,7 @@ struct option stap_long_options[] = {
   { "privilege", 1, &stap_long_opt, LONG_OPT_PRIVILEGE },
   { "suppress-handler-errors", 0, &stap_long_opt, LONG_OPT_SUPPRESS_HANDLER_ERRORS },
   { "modinfo", 1, &stap_long_opt, LONG_OPT_MODINFO },
+  { "sysroot", 1, &stap_long_opt, LONG_OPT_SYSROOT },
+  { "sysenv", 1, &stap_long_opt, LONG_OPT_SYSENV },
   { NULL, 0, NULL, 0 }
 };
diff --git a/cmdline.h b/cmdline.h
index 3229a7b..680f290 100644
--- a/cmdline.h
+++ b/cmdline.h
@@ -44,6 +44,8 @@ extern "C" {
 #define LONG_OPT_PRIVILEGE 28
 #define LONG_OPT_SUPPRESS_HANDLER_ERRORS 29
 #define LONG_OPT_MODINFO 30
+#define LONG_OPT_SYSROOT 31
+#define LONG_OPT_SYSENV 32
 
 // NB: when adding new options, consider very carefully whether they
 // should be restricted from stap clients (after --client-options)!
diff --git a/dwflpp.cxx b/dwflpp.cxx
index dd42962..6cb2fdb 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session & s, bool debuginfo_n
     {
       if (debuginfo_needed) {
         // Suggest a likely kernel dir to find debuginfo rpm for
-        string dir = string("/lib/modules/" + sess.kernel_release );
+        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
         find_debug_rpms(sess, dir.c_str());
       }
       throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
@@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed)
     {
       if (debuginfo_needed) {
         // Suggest a likely kernel dir to find debuginfo rpm for
-        string dir = string("/lib/modules/" + sess.kernel_release );
+        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
         find_debug_rpms(sess, dir.c_str());
       }
       throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
diff --git a/hash.cxx b/hash.cxx
index c435a03..69334f5 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -133,6 +133,7 @@ void create_hash_log(const string &type_str, const string &parms, const string &
 static const hash&
 get_base_hash (systemtap_session& s)
 {
+  map<string, char*> dummy;
   if (s.base_hash)
     return *s.base_hash;
 
@@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s)
   // Hash compiler path, size, and mtime.  We're just going to assume
   // we'll be using gcc. XXX: getting kbuild to spit out out would be
   // better, especially since this is fooled by ccache.
-  h.add_path("Compiler ", find_executable("gcc"));
+  h.add_path("Compiler ", find_executable("gcc", "", dummy));
 
   // Hash the systemtap size and mtime.  We could use VERSION/DATE,
   // but when developing systemtap that doesn't work well (since you
diff --git a/main.cxx b/main.cxx
index 9e55f8e..4707989 100644
--- a/main.cxx
+++ b/main.cxx
@@ -24,6 +24,7 @@
 #include "csclient.h"
 #include "remote.h"
 #include "tapsets.h"
+#include "setupdwfl.h"
 
 #include <libintl.h>
 #include <locale.h>
@@ -486,6 +487,14 @@ passes_0_4 (systemtap_session &s)
 
   s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
 
+  // Update various paths to include the sysroot, if provided.
+  if (!s.sysroot.empty())
+    {
+      if (s.update_release_sysroot && !s.sysroot.empty())
+        s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
+      debuginfo_path_insert_sysroot(s.sysroot);
+    }
+
   // Now that no further changes to s.kernel_build_tree can occur, let's use it.
   if ((rc = parse_kernel_config (s)) != 0)
     {
diff --git a/session.cxx b/session.cxx
index 24c329a..73b2a19 100644
--- a/session.cxx
+++ b/session.cxx
@@ -149,6 +149,8 @@ systemtap_session::systemtap_session ():
   download_dbinfo = 0;
   suppress_handler_errors = false;
   native_build = true; // presumed
+  sysroot = "";
+  update_release_sysroot = false;
 
   /*  adding in the XDG_DATA_DIRS variable path,
    *  this searches in conjunction with SYSTEMTAP_TAPSET
@@ -310,6 +312,9 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   systemtap_v_check = other.systemtap_v_check;
   download_dbinfo = other.download_dbinfo;
   suppress_handler_errors = other.suppress_handler_errors;
+  sysroot = other.sysroot;
+  update_release_sysroot = other.update_release_sysroot;
+  sysenv = other.sysenv;
 
   include_path = other.include_path;
   runtime_path = other.runtime_path;
@@ -533,6 +538,13 @@ systemtap_session::usage (int exitcode)
     "              yes,no,ask,<timeout value>\n"
     "   --dump-probe-types\n"
     "              show a list of available probe types.\n"
+    "   --sysroot=DIR\n"
+    "              specify sysroot directory where target files (executables,\n"    "              libraries, etc.) are located.\n"
+    "   --sysenv=VAR=VALUE\n"
+    "              provide an alternate value for an environment variable\n"
+    "              where the value on a remote system differs.  Path\n"
+    "              variables (e.g. PATH, LD_LIBRARY_PATH) are assumed to be\n"
+    "              relative to the sysroot.\n"
     , compatible.c_str()) << endl
   ;
 
@@ -1097,6 +1109,55 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
               modinfos.push_back (string(optarg));
               break;
 
+            case LONG_OPT_SYSROOT:
+              if (client_options) {
+                  cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl;
+                  return 1;
+              }
+              if (!sysroot.empty()) {
+                  cerr << "ERROR: multiple --sysroot options not supported" << endl;
+                  return 1;
+	      } else {
+                  const char *spath = canonicalize_file_name (optarg);
+                  if (spath == NULL) {
+                      cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
+                      return 1;
+                  }
+
+                  sysroot = string(spath);
+                  if (sysroot[sysroot.size() - 1] != '/')
+                      sysroot.append("/");
+
+                  break;
+              }
+            case LONG_OPT_SYSENV:
+              if (client_options) {
+                  cerr << _F("ERROR: %s invalid with %s", "--sysenv", "--client-options") << endl;
+                  return 1;
+              } else {
+                  string sysenv_str = optarg;
+                  string value_str;
+		  char * value;
+                  size_t pos;
+                  if (sysroot.empty()) {
+                      cerr << "ERROR: --sysenv must follow --sysroot" << endl;
+                      return 1;
+                  }
+
+                  pos = sysenv_str.find("=");
+                  if (pos == string::npos) {
+                      cerr << _F("ERROR: %s is an invalid argument for --sysenv", optarg) << endl;
+                      return 1;
+                  }
+
+                  value_str = sysenv_str.substr(pos + 1);
+		  value = new char[value_str.size()+1];
+		  strcpy(value, value_str.c_str());
+                  sysenv[sysenv_str.substr(0, pos)] = value;
+
+                  break;
+              }
+
             default:
               // NOTREACHED unless one added a getopt option but not a corresponding switch/case:
               cerr << _F("Unhandled long argument id %d", stap_long_opt) << endl;
@@ -1386,6 +1447,7 @@ systemtap_session::setup_kernel_release (const char* kstr)
     }
   else
     {
+      update_release_sysroot = true;
       kernel_release = string (kstr);
       if (!kernel_release.empty())
         kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
diff --git a/session.h b/session.h
index e128b2f..b5b8d82 100644
--- a/session.h
+++ b/session.h
@@ -140,6 +140,9 @@ public:
   std::string kernel_base_release;
   std::string kernel_build_tree;
   std::string kernel_source_tree;
+  std::string sysroot;
+  std::map<std::string,char *> sysenv;
+  bool update_release_sysroot;
   std::map<std::string,std::string> kernel_config;
   std::set<std::string> kernel_exports;
   std::string machine;
diff --git a/setupdwfl.cxx b/setupdwfl.cxx
index 82bc42a..91bfd39 100644
--- a/setupdwfl.cxx
+++ b/setupdwfl.cxx
@@ -39,14 +39,14 @@ extern "C" {
 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
 static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build";
 static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
-static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr);
+static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr);
 
 // NB: kernel_build_tree doesn't enter into this, as it's for
 // kernel-side modules only.
 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
 static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug";
-static const char *debuginfo_usr_path = (debuginfo_env_arr
-					 ?: debuginfo_usr_path_arr);
+static char *debuginfo_usr_path = (char *)(debuginfo_env_arr
+					   ?: debuginfo_usr_path_arr);
 
 // A pointer to the current systemtap session for use only by a few
 // dwfl calls. DO NOT rely on this, as it is cleared after use.
@@ -146,7 +146,10 @@ setup_mod_deps()
     }
   else
     {
-      modulesdep = "/lib/modules/";
+      string sysroot = "";
+      if (current_session_for_find_debuginfo)
+        sysroot = current_session_for_find_debuginfo->sysroot;
+      modulesdep = sysroot + "/lib/modules/";
       modulesdep += elfutils_kernel_path;
       modulesdep += "/modules.dep";
     }
@@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename)
     }
 }
 
+static char * path_insert_sysroot(string sysroot, string path)
+{
+  char * path_new;
+  size_t pos = 1;
+  if (path[0] == '/')
+    path.replace(0, 1, sysroot);
+  while (true) {
+    pos = path.find(":/", pos);
+    if (pos == string::npos)
+      break;
+    path.replace(pos, 2, ":" + sysroot);
+    ++pos;
+  }
+  path_new = new char[path.size()+1];
+  strcpy (path_new, path.c_str());
+  return path_new;
+}
+
+void debuginfo_path_insert_sysroot(string sysroot)
+{
+  debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path);
+  debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path);
+}
+
 static DwflPtr
 setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
 {
@@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
   // no way to set the dwfl_callback.debuginfo_path and always
   // passs the plain kernel_release here.  So instead we have to
   // hard-code this magic here.
-  if (s.kernel_build_tree == string("/lib/modules/"
+  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
 				    + s.kernel_release
 				    + "/build"))
     elfutils_kernel_path = s.kernel_release;
diff --git a/setupdwfl.h b/setupdwfl.h
index 48f9105..aa1c800 100644
--- a/setupdwfl.h
+++ b/setupdwfl.h
@@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod,
 int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex);
 std::string get_kernel_build_id (systemtap_session &s);
 int download_kernel_debuginfo (systemtap_session &s, std::string hex);
+void debuginfo_path_insert_sysroot(std::string sysroot);
 
 #endif
diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
index 1a9bf67..94a47da 100644
--- a/tapset-itrace.cxx
+++ b/tapset-itrace.cxx
@@ -114,8 +114,9 @@ struct itrace_builder: public derived_probe_builder
     // If we have a path, we need to validate it.
     if (has_path)
       {
-        path = find_executable (path);
+        path = find_executable (path, sess.sysroot, sess.sysenv);
         sess.unwindsym_modules.insert (path);
+        path_remove_sysroot(sess, path);
       }
 
     finished_results.push_back(new itrace_derived_probe(sess, base, location,
diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
index 64ba900..8c98435 100644
--- a/tapset-utrace.cxx
+++ b/tapset-utrace.cxx
@@ -679,8 +679,9 @@ struct utrace_builder: public derived_probe_builder
       }
     else if (has_path)
       {
-        path = find_executable (path);
+        path = find_executable (path, sess.sysroot, sess.sysenv);
         sess.unwindsym_modules.insert (path);
+        path_remove_sysroot(sess, path);
       }
     else if (has_pid)
       {
diff --git a/tapsets.cxx b/tapsets.cxx
index 716e23c..c2d00bb 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -584,13 +584,14 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params):
       has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
 
       if (has_process)
-        module_val = find_executable (module_val);
+        module_val = find_executable (module_val, sess.sysroot, sess.sysenv);
       if (has_library)
         {
           if (! contains_glob_chars (library_name))
             {
               path = module_val;
-              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
+              module_val = find_executable (library_name, sess.sysroot,
+                                            sess.sysenv, "LD_LIBRARY_PATH");
             }
           else
             path = library_name;
@@ -1127,6 +1128,13 @@ bad:
                        base_probe->tok);
 }
 
+void path_remove_sysroot(const systemtap_session& sess, string& path)
+{
+  size_t pos;
+  if (!sess.sysroot.empty() &&
+      (pos = path.find(sess.sysroot)) != string::npos)
+    path.replace(pos, sess.sysroot.length(), "/");
+}
 
 void
 dwarf_query::add_probe_point(const string& dw_funcname,
@@ -1137,7 +1145,7 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 {
   string reloc_section; // base section for relocation purposes
   Dwarf_Addr reloc_addr; // relocated
-  const string& module = dw.module_name; // "kernel" or other
+  string& module = dw.module_name; // "kernel" or other
   string funcname = dw_funcname;
 
   assert (! has_absolute); // already handled in dwarf_builder::build()
@@ -1188,6 +1196,8 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 
       if (has_process)
         {
+          path_remove_sysroot(sess, module);
+          path_remove_sysroot(sess, path);
           results.push_back (new uprobe_derived_probe(funcname, filename, line,
                                                       module, reloc_section, addr, reloc_addr,
                                                       *this, scope_die));
@@ -2051,7 +2061,8 @@ query_one_library (const char *library, dwflpp & dw,
 {
   if (dw.function_name_matches_pattern(library, user_lib))
     {
-      string library_path = find_executable (library, "LD_LIBRARY_PATH");
+      string library_path = find_executable (library, "", dw.sess.sysenv,
+                                             "LD_LIBRARY_PATH");
       probe_point* specific_loc = new probe_point(*base_loc);
       specific_loc->optional = true;
       vector<probe_point::component*> derived_comps;
@@ -3906,7 +3917,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
 	    }
 	  else
 	    {
-	      module = find_executable (module); // canonicalize it
+	      module = find_executable (module, "", s.sysenv); // canonicalize it
 	      dw = db.get_user_dw(s, module);
 	    }
 	}
@@ -6546,13 +6557,14 @@ dwarf_builder::build(systemtap_session & sess,
     }
   else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS))
       {
+      module_name = sess.sysroot + module_name;
       if(has_null_param(filled_parameters, TOK_PROCESS))
         {
           wordexp_t words;
           int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF);
           if(rc || words.we_wordc <= 0)
             throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND"));
-          module_name = words.we_wordv[0];
+          module_name = sess.sysroot + words.we_wordv[0];
           filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map
           // in the case of TOK_MARK we need to modify locations as well
           if(location->components[0]->functor==TOK_PROCESS &&
@@ -6605,9 +6617,10 @@ dwarf_builder::build(systemtap_session & sess,
                   if (sess.verbose > 1)
                     clog << _F("Expanded process(\"%s\") to process(\"%s\")",
                                module_name.c_str(), eglobbed.c_str()) << endl;
+                  path_remove_sysroot(sess, eglobbed);
 
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (eglobbed));
+                                                    new literal_string (eglobbed));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6633,7 +6646,7 @@ dwarf_builder::build(systemtap_session & sess,
 
       // PR13338: unquote glob results
       module_name = unescape_glob_chars (module_name);
-      user_path = find_executable (module_name); // canonicalize it
+      user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it
 
       // if the executable starts with "#!", we look for the interpreter of the script
       {
@@ -6679,12 +6692,13 @@ dwarf_builder::build(systemtap_session & sess,
                     if (p3 != string::npos)
                     {
                        string env_path = path.substr(p3);
-                       user_path = find_executable (env_path);
+                       user_path = find_executable (env_path, sess.sysroot,
+                                                    sess.sysenv);
                     }
                 }
                 else
                 {
-                   user_path = find_executable (path);
+                  user_path = find_executable (path, sess.sysroot, sess.sysenv);
                 }
 
                 struct stat st;
@@ -6705,8 +6719,10 @@ dwarf_builder::build(systemtap_session & sess,
 
                   // synthesize a new probe_point, with the expanded string
                   probe_point *pp = new probe_point (*location);
+                  string user_path_tgt = user_path;
+                  path_remove_sysroot(sess, user_path_tgt);
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (user_path.c_str()));
+                                                                            new literal_string (user_path_tgt.c_str()));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6725,7 +6741,8 @@ dwarf_builder::build(systemtap_session & sess,
 
       if(get_param (parameters, TOK_LIBRARY, user_lib)
 	  && user_lib.length() && ! contains_glob_chars (user_lib))
-	module_name = find_executable (user_lib, "LD_LIBRARY_PATH");
+	module_name = find_executable (user_lib, sess.sysroot, sess.sysenv,
+                                       "LD_LIBRARY_PATH");
       else
 	module_name = user_path; // canonicalize it
 
@@ -8189,7 +8206,7 @@ struct kprobe_builder: public derived_probe_builder
 
 
 void
-kprobe_builder::build(systemtap_session &,
+kprobe_builder::build(systemtap_session & sess,
 		      probe * base,
 		      probe_point * location,
 		      literal_map_t const & parameters,
@@ -8212,9 +8229,16 @@ kprobe_builder::build(systemtap_session &,
   has_library = get_param (parameters, TOK_LIBRARY, library);
 
   if (has_path)
-    path = find_executable (path);
+    {
+      path = find_executable (path, sess.sysroot, sess.sysenv);
+      path_remove_sysroot(sess, path);
+    }
   if (has_library)
-    library = find_executable (library, "LD_LIBRARY_PATH");
+    {
+      library = find_executable (library, sess.sysroot, sess.sysenv,
+                                 "LD_LIBRARY_PATH");
+      path_remove_sysroot(sess, library);
+    }
 
   if (has_function_str)
     {
diff --git a/tapsets.h b/tapsets.h
index c5fb30c..530bf51 100644
--- a/tapsets.h
+++ b/tapsets.h
@@ -31,6 +31,7 @@ void register_tapset_timers(systemtap_session& sess);
 void register_tapset_perf(systemtap_session& sess);
 void register_tapset_utrace(systemtap_session& sess);
 
+void path_remove_sysroot(const systemtap_session& sess, std::string& path);
 
 // ------------------------------------------------------------------------
 // Generic derived_probe_group: contains an ordinary vector of the
diff --git a/translate.cxx b/translate.cxx
index 97847a8..2b8d012 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session &s)
   // having the BUILDDIR we need to do a deep search (the specific
   // arch name dir in the kernel build tree is unknown).
   string vdso_dir;
-  if (s.kernel_build_tree == string("/lib/modules/"
+  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
 				    + s.kernel_release
 				    + "/build"))
-    vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso";
+    vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso";
   else
     vdso_dir = s.kernel_build_tree + "/arch/";
 
diff --git a/util.cxx b/util.cxx
index c14695b..7ece67f 100644
--- a/util.cxx
+++ b/util.cxx
@@ -346,7 +346,8 @@ tokenize_cxx(const string& str, vector<string>& tokens)
 // same policy as execvp().  A program name not containing a slash
 // will be searched along the $PATH.
 
-string find_executable(const string& name, const string& env_path)
+string find_executable(const string& name, const string& sysroot,
+		       map<string, char*>& sysenv, const string& env_path)
 {
   string retpath;
 
@@ -357,11 +358,15 @@ string find_executable(const string& name, const string& env_path)
 
   if (name.find('/') != string::npos) // slash in the path already?
     {
-      retpath = name;
+      retpath = sysroot + name;
     }
   else // Nope, search $PATH.
     {
-      char *path = getenv(env_path.c_str());
+      char *path;
+      if (sysenv.count(env_path) != 0)
+        path = sysenv[env_path];
+      else
+        path = getenv(env_path.c_str());
       if (path)
         {
           // Split PATH up.
@@ -371,7 +376,7 @@ string find_executable(const string& name, const string& env_path)
           // Search the path looking for the first executable of the right name.
           for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
             {
-              string fname = *i + "/" + name;
+              string fname = sysroot + *i + "/" + name;
               const char *f = fname.c_str();
 
               // Look for a normal executable file.
@@ -390,13 +395,22 @@ string find_executable(const string& name, const string& env_path)
   // Could not find the program on the $PATH.  We'll just fall back to
   // the unqualified name, which our caller will probably fail with.
   if (retpath == "")
-    retpath = name;
+    retpath = sysroot + name;
 
   // Canonicalize the path name.
   char *cf = canonicalize_file_name (retpath.c_str());
   if (cf)
     {
-      retpath = string(cf);
+      string scf = string(cf);
+      if (sysroot.empty())
+        retpath = scf;
+      else {
+        int pos = scf.find(sysroot);
+        if (pos == 0)
+          retpath = scf;
+        else
+          throw runtime_error(_F("find_executable(): file %s not in sysroot %s", cf, sysroot.c_str()));
+      }
       free (cf);
     }
 
diff --git a/util.h b/util.h
index e576036..44e41e4 100644
--- a/util.h
+++ b/util.h
@@ -12,6 +12,7 @@
 #include <cctype>
 #include <set>
 #include <iomanip>
+#include <map>
 extern "C" {
 #include <libintl.h>
 #include <locale.h>
@@ -51,6 +52,8 @@ void tokenize(const std::string& str, std::vector<std::string>& tokens,
 	      const std::string& delimiters);
 void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens);
 std::string find_executable(const std::string& name,
+			    const std::string& sysroot,
+			    std::map<std::string,char *>& sysenv,
 			    const std::string& env_path = "PATH");
 const std::string cmdstr_quoted(const std::string& cmd);
 const std::string cmdstr_join(const std::vector<std::string>& cmds);
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 2/3] PR12331: Document --sysroot and --sysenv
  2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
  2012-03-02 14:48     ` [PATCH v3 1/3] " Wade Farnsworth
@ 2012-03-02 14:48     ` Wade Farnsworth
  2012-03-02 14:49     ` [PATCH v3 3/3] PR12331: Add testcase for " Wade Farnsworth
  2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
  3 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-02 14:48 UTC (permalink / raw)
  To: systemtap, jistone

Update stap.1 and NEWS to document the new options.
---
 NEWS   |    3 +++
 stap.1 |   11 +++++++++++
 2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index 6b52cf9..e5142c8 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,9 @@
   removed in release 1.9:
       daddr_to_string()
 
+- Addition of stap --sysroot and --sysenv options to facilitate different
+  paths and environment variables at run-time.
+
 * What's new in version 1.7, 2012-02-01
 
 - Map inserting and deleting is now significantly faster due to
diff --git a/stap.1 b/stap.1
index 731ed21..cc7ebad 100644
--- a/stap.1
+++ b/stap.1
@@ -527,7 +527,18 @@ show abrt output, and ask before continuing download. No timeout will be set.
 .BI <timeout>
 specify a timeout as a positive number to stop the download if it is taking 
 too long.
+.RE
+
+.TP
+.BI \-\-sysroot "=DIR"
+Specify sysroot directory where target files (executables, libraries, etc.)
+are located.
 
+.TP
+.BI \-\-sysenv "=VAR=VALUE"
+Provide an alternate value for an environment variable where the value on a
+remote system differs.  Path variables (e.g. PATH, LD_LIBRARY_PATH) are assumed
+to be relative to the sysroot.
 
 .SH ARGUMENTS
 
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v3 3/3] PR12331: Add testcase for --sysroot and --sysenv
  2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
  2012-03-02 14:48     ` [PATCH v3 1/3] " Wade Farnsworth
  2012-03-02 14:48     ` [PATCH v3 2/3] PR12331: Document " Wade Farnsworth
@ 2012-03-02 14:49     ` Wade Farnsworth
  2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
  3 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-02 14:49 UTC (permalink / raw)
  To: systemtap, jistone

Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com>
---
 testsuite/systemtap.base/sysroot_sysenv.exp |   15 +++++++++++++++
 testsuite/systemtap.base/sysroot_sysenv.stp |    3 +++
 2 files changed, 18 insertions(+), 0 deletions(-)
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp

diff --git a/testsuite/systemtap.base/sysroot_sysenv.exp b/testsuite/systemtap.base/sysroot_sysenv.exp
new file mode 100644
index 0000000..72b6822
--- /dev/null
+++ b/testsuite/systemtap.base/sysroot_sysenv.exp
@@ -0,0 +1,15 @@
+set test "sysroot_sysenv"
+
+if {[installtest_p] && [utrace_p] && [uprobes_p]} {
+  spawn stap --sysroot=/ --sysenv=PATH=$env(PATH) $srcdir/$subdir/$test.stp ls -c "ls > /dev/null"
+  expect {
+    -timeout 180
+    -re {^process begin\r\n} { pass "$test" }
+    timeout { fail "$test (timeout)" }
+    eof { fail "$test" }
+  }
+} else {
+  untested "$test"
+}
+catch {close}
+wait
diff --git a/testsuite/systemtap.base/sysroot_sysenv.stp b/testsuite/systemtap.base/sysroot_sysenv.stp
new file mode 100644
index 0000000..950936f
--- /dev/null
+++ b/testsuite/systemtap.base/sysroot_sysenv.stp
@@ -0,0 +1,3 @@
+probe process(@1).begin {
+  println("process begin")
+}
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 0/3] Introduce stap options --sysroot and --sysenv
  2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
                       ` (2 preceding siblings ...)
  2012-03-02 14:49     ` [PATCH v3 3/3] PR12331: Add testcase for " Wade Farnsworth
@ 2012-03-08 14:48     ` Wade Farnsworth
  2012-03-08 14:49       ` [PATCH v4 1/3] PR12331: " Wade Farnsworth
                         ` (3 more replies)
  3 siblings, 4 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-08 14:48 UTC (permalink / raw)
  To: systemtap, jistone, fche

This patchset introduces --sysroot and --sysenv options for stap, which
improve functionality in environments where the compiling system differs
from the one running the probes.

See Patch 1/3's description for more details on what has been implemented.

v2 - Implemented several improvements per Josh Stone's comments.
v3 - Further improvements per Josh Stone.  Include documentation and test cases
     for the new options.
v4 - Add more detail to the man page for --sysroot to clarify which paths
     are affected.
   - Changed handling of paths where both sysroot and non-
     sysroot versions are needed so that it's clear which version we're tracking.
   - Store the sysenv variable as map<string, string> instead of
     <string, char*>.
    

Wade Farnsworth (3):
  PR12331: Introduce stap options --sysroot and --sysenv
  PR12331: Document --sysroot and --sysenv
  PR12331: Add testcase for --sysroot and --sysenv

 cmdline.cxx                                 |    2 +
 cmdline.h                                   |    2 +
 dwflpp.cxx                                  |    4 +-
 hash.cxx                                    |    3 +-
 main.cxx                                    |    9 ++++
 session.cxx                                 |   59 ++++++++++++++++++++++++
 session.h                                   |    3 +
 setupdwfl.cxx                               |   37 +++++++++++++--
 setupdwfl.h                                 |    1 +
 stap.1                                      |   13 +++++
 tapset-itrace.cxx                           |    7 ++-
 tapset-utrace.cxx                           |    7 ++-
 tapsets.cxx                                 |   66 ++++++++++++++++++---------
 tapsets.h                                   |    2 +
 testsuite/systemtap.base/sysroot_sysenv.exp |   15 ++++++
 testsuite/systemtap.base/sysroot_sysenv.stp |    3 +
 translate.cxx                               |    4 +-
 util.cxx                                    |   27 +++++++++---
 util.h                                      |    3 +
 19 files changed, 224 insertions(+), 43 deletions(-)
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 1/3] PR12331: Introduce stap options --sysroot and --sysenv
  2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
@ 2012-03-08 14:49       ` Wade Farnsworth
  2012-03-08 14:50       ` [PATCH v4 2/3] PR12331: Document " Wade Farnsworth
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-08 14:49 UTC (permalink / raw)
  To: systemtap, jistone, fche

This adds new command-line options to facilitate different file locations at
compile-time versus run-time when generating stap kernel modules for a remote
system:

1. --sysroot=DIR
   Specifies a separate filesystem for the remote system on the local
   system.  The following stap functionalities will make use of this:

   a. When compiling process and library probes with a remote filesystem path
      (e.g. process("/bin/foo") with --sysroot=/bar/baz).  In this case symbols
      will be taken from the local filesystem (/bar/baz/bin/foo), but the
      resulting .ko will still contain paths on the remote filesystem
      (/bin/foo).

   b. When passing a kernel release with -r (not a full path), the kernel
      build directory will be expected in the sysroot.

   c. When DWARF debug info is contained in a separate file from the
      executable, the sysroot is used to find the debug info files.

   d. All calls to find_executable() search the path passed in the
      argument env_path relative to the sysroot.  For example if
      PATH=/bin/foo, and --sysroot=/bar/baz is provided, then
      find_executable() called with env_path == "PATH" will search
      /bar/baz/bin/foo.

   e. stap attempts to detect if a path in a probe would be outside of the
      sysroot and errors appropriately.  This situation may occur, for
      example, if the path contains several ".." directories.

2. --sysenv=VAR=VALUE
   Specifies a different environment variable for the remote system as opposed
   to the local one, and that the value on the remote system should be used.
   Currently only valid env_path arguments to find_executable() are handled
   (i.e. PATH, LD_LIBRARY_PATH).  If --sysroot is provided and --sysenv
   is omitted, then the local environment relative to the sysroot will
   be used.

These options are disabled for systemtap clients.

Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com>
---
 cmdline.cxx       |    2 +
 cmdline.h         |    2 +
 dwflpp.cxx        |    4 +-
 hash.cxx          |    3 +-
 main.cxx          |    9 +++++++
 session.cxx       |   59 +++++++++++++++++++++++++++++++++++++++++++++++
 session.h         |    3 ++
 setupdwfl.cxx     |   37 +++++++++++++++++++++++++----
 setupdwfl.h       |    1 +
 tapset-itrace.cxx |    7 +++--
 tapset-utrace.cxx |    7 +++--
 tapsets.cxx       |   66 ++++++++++++++++++++++++++++++++++++-----------------
 tapsets.h         |    2 +
 translate.cxx     |    4 +-
 util.cxx          |   27 +++++++++++++++++-----
 util.h            |    3 ++
 16 files changed, 193 insertions(+), 43 deletions(-)

diff --git a/cmdline.cxx b/cmdline.cxx
index 04d741e..720d34a 100644
--- a/cmdline.cxx
+++ b/cmdline.cxx
@@ -55,5 +55,7 @@ struct option stap_long_options[] = {
   { "rlimit-nproc", 1, &stap_long_opt, LONG_OPT_RLIMIT_NPROC },
   { "rlimit-stack", 1, &stap_long_opt, LONG_OPT_RLIMIT_STACK },
   { "rlimit-fsize", 1, &stap_long_opt, LONG_OPT_RLIMIT_FSIZE },
+  { "sysroot", 1, &stap_long_opt, LONG_OPT_SYSROOT },
+  { "sysenv", 1, &stap_long_opt, LONG_OPT_SYSENV },
   { NULL, 0, NULL, 0 }
 };
diff --git a/cmdline.h b/cmdline.h
index 4a09bd0..b41c734 100644
--- a/cmdline.h
+++ b/cmdline.h
@@ -49,6 +49,8 @@ extern "C" {
 #define LONG_OPT_RLIMIT_NPROC 33
 #define LONG_OPT_RLIMIT_STACK 34
 #define LONG_OPT_RLIMIT_FSIZE 35
+#define LONG_OPT_SYSROOT 36
+#define LONG_OPT_SYSENV 37
 
 // NB: when adding new options, consider very carefully whether they
 // should be restricted from stap clients (after --client-options)!
diff --git a/dwflpp.cxx b/dwflpp.cxx
index dd42962..6cb2fdb 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -321,7 +321,7 @@ dwflpp::setup_kernel(const string& name, systemtap_session & s, bool debuginfo_n
     {
       if (debuginfo_needed) {
         // Suggest a likely kernel dir to find debuginfo rpm for
-        string dir = string("/lib/modules/" + sess.kernel_release );
+        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
         find_debug_rpms(sess, dir.c_str());
       }
       throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
@@ -359,7 +359,7 @@ dwflpp::setup_kernel(const vector<string> &names, bool debuginfo_needed)
     {
       if (debuginfo_needed) {
         // Suggest a likely kernel dir to find debuginfo rpm for
-        string dir = string("/lib/modules/" + sess.kernel_release );
+        string dir = string(sess.sysroot + "/lib/modules/" + sess.kernel_release );
         find_debug_rpms(sess, dir.c_str());
       }
       throw semantic_error (_F("missing %s kernel/module debuginfo under '%s'",
diff --git a/hash.cxx b/hash.cxx
index c435a03..f665ac3 100644
--- a/hash.cxx
+++ b/hash.cxx
@@ -133,6 +133,7 @@ void create_hash_log(const string &type_str, const string &parms, const string &
 static const hash&
 get_base_hash (systemtap_session& s)
 {
+  map<string, string> dummy;
   if (s.base_hash)
     return *s.base_hash;
 
@@ -158,7 +159,7 @@ get_base_hash (systemtap_session& s)
   // Hash compiler path, size, and mtime.  We're just going to assume
   // we'll be using gcc. XXX: getting kbuild to spit out out would be
   // better, especially since this is fooled by ccache.
-  h.add_path("Compiler ", find_executable("gcc"));
+  h.add_path("Compiler ", find_executable("gcc", "", dummy));
 
   // Hash the systemtap size and mtime.  We could use VERSION/DATE,
   // but when developing systemtap that doesn't work well (since you
diff --git a/main.cxx b/main.cxx
index c08cf18..84f6e7c 100644
--- a/main.cxx
+++ b/main.cxx
@@ -24,6 +24,7 @@
 #include "csclient.h"
 #include "remote.h"
 #include "tapsets.h"
+#include "setupdwfl.h"
 
 #include <libintl.h>
 #include <locale.h>
@@ -487,6 +488,14 @@ passes_0_4 (systemtap_session &s)
 
   s.kernel_base_release.assign(s.kernel_release, 0, s.kernel_release.find('-'));
 
+  // Update various paths to include the sysroot, if provided.
+  if (!s.sysroot.empty())
+    {
+      if (s.update_release_sysroot && !s.sysroot.empty())
+        s.kernel_build_tree = s.sysroot + s.kernel_build_tree;
+      debuginfo_path_insert_sysroot(s.sysroot);
+    }
+
   // Now that no further changes to s.kernel_build_tree can occur, let's use it.
   if ((rc = parse_kernel_config (s)) != 0)
     {
diff --git a/session.cxx b/session.cxx
index b8fc17f..95ddda3 100644
--- a/session.cxx
+++ b/session.cxx
@@ -150,6 +150,8 @@ systemtap_session::systemtap_session ():
   download_dbinfo = 0;
   suppress_handler_errors = false;
   native_build = true; // presumed
+  sysroot = "";
+  update_release_sysroot = false;
 
   /*  adding in the XDG_DATA_DIRS variable path,
    *  this searches in conjunction with SYSTEMTAP_TAPSET
@@ -311,6 +313,9 @@ systemtap_session::systemtap_session (const systemtap_session& other,
   systemtap_v_check = other.systemtap_v_check;
   download_dbinfo = other.download_dbinfo;
   suppress_handler_errors = other.suppress_handler_errors;
+  sysroot = other.sysroot;
+  update_release_sysroot = other.update_release_sysroot;
+  sysenv = other.sysenv;
 
   include_path = other.include_path;
   runtime_path = other.runtime_path;
@@ -534,6 +539,13 @@ systemtap_session::usage (int exitcode)
     "              yes,no,ask,<timeout value>\n"
     "   --dump-probe-types\n"
     "              show a list of available probe types.\n"
+    "   --sysroot=DIR\n"
+    "              specify sysroot directory where target files (executables,\n"    "              libraries, etc.) are located.\n"
+    "   --sysenv=VAR=VALUE\n"
+    "              provide an alternate value for an environment variable\n"
+    "              where the value on a remote system differs.  Path\n"
+    "              variables (e.g. PATH, LD_LIBRARY_PATH) are assumed to be\n"
+    "              relative to the sysroot.\n"
     , compatible.c_str()) << endl
   ;
 
@@ -1139,6 +1151,52 @@ systemtap_session::parse_cmdline (int argc, char * const argv [])
                 cerr << _F("Unable to set resource limits for rlimit_fsize : %s", strerror (errno)) << endl;
               break;
 
+            case LONG_OPT_SYSROOT:
+              if (client_options) {
+                  cerr << _F("ERROR: %s invalid with %s", "--sysroot", "--client-options") << endl;
+                  return 1;
+              } else if (!sysroot.empty()) {
+                  cerr << "ERROR: multiple --sysroot options not supported" << endl;
+                  return 1;
+              } else {
+                  const char *spath = canonicalize_file_name (optarg);
+                  if (spath == NULL) {
+                      cerr << _F("ERROR: %s is an invalid directory for --sysroot", optarg) << endl;
+                      return 1;
+                  }
+
+                  sysroot = string(spath);
+                  if (sysroot[sysroot.size() - 1] != '/')
+                      sysroot.append("/");
+
+                  break;
+              }
+
+            case LONG_OPT_SYSENV:
+              if (client_options) {
+                  cerr << _F("ERROR: %s invalid with %s", "--sysenv", "--client-options") << endl;
+                  return 1;
+              } else {
+                  string sysenv_str = optarg;
+                  string value;
+                  size_t pos;
+                  if (sysroot.empty()) {
+                      cerr << "ERROR: --sysenv must follow --sysroot" << endl;
+                      return 1;
+                  }
+
+                  pos = sysenv_str.find("=");
+                  if (pos == string::npos) {
+                      cerr << _F("ERROR: %s is an invalid argument for --sysenv", optarg) << endl;
+                      return 1;
+                  }
+
+                  value = sysenv_str.substr(pos + 1);
+                  sysenv[sysenv_str.substr(0, pos)] = value;
+
+                  break;
+              }
+
             default:
               // NOTREACHED unless one added a getopt option but not a corresponding switch/case:
               cerr << _F("Unhandled long argument id %d", stap_long_opt) << endl;
@@ -1428,6 +1486,7 @@ systemtap_session::setup_kernel_release (const char* kstr)
     }
   else
     {
+      update_release_sysroot = true;
       kernel_release = string (kstr);
       if (!kernel_release.empty())
         kernel_build_tree = "/lib/modules/" + kernel_release + "/build";
diff --git a/session.h b/session.h
index e128b2f..a82f1d1 100644
--- a/session.h
+++ b/session.h
@@ -140,6 +140,9 @@ public:
   std::string kernel_base_release;
   std::string kernel_build_tree;
   std::string kernel_source_tree;
+  std::string sysroot;
+  std::map<std::string,std::string> sysenv;
+  bool update_release_sysroot;
   std::map<std::string,std::string> kernel_config;
   std::set<std::string> kernel_exports;
   std::string machine;
diff --git a/setupdwfl.cxx b/setupdwfl.cxx
index 82bc42a..91bfd39 100644
--- a/setupdwfl.cxx
+++ b/setupdwfl.cxx
@@ -39,14 +39,14 @@ extern "C" {
 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
 static const char *debuginfo_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug:build";
 static const char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
-static const char *debuginfo_path = (debuginfo_env_arr ?: debuginfo_path_arr);
+static char *debuginfo_path = (char *)(debuginfo_env_arr ?: debuginfo_path_arr);
 
 // NB: kernel_build_tree doesn't enter into this, as it's for
 // kernel-side modules only.
 // XXX: also consider adding $HOME/.debug/ for perf build-id-cache
 static const char *debuginfo_usr_path_arr = "+:.debug:/usr/lib/debug:/var/cache/abrt-di/usr/lib/debug";
-static const char *debuginfo_usr_path = (debuginfo_env_arr
-					 ?: debuginfo_usr_path_arr);
+static char *debuginfo_usr_path = (char *)(debuginfo_env_arr
+					   ?: debuginfo_usr_path_arr);
 
 // A pointer to the current systemtap session for use only by a few
 // dwfl calls. DO NOT rely on this, as it is cleared after use.
@@ -146,7 +146,10 @@ setup_mod_deps()
     }
   else
     {
-      modulesdep = "/lib/modules/";
+      string sysroot = "";
+      if (current_session_for_find_debuginfo)
+        sysroot = current_session_for_find_debuginfo->sysroot;
+      modulesdep = sysroot + "/lib/modules/";
       modulesdep += elfutils_kernel_path;
       modulesdep += "/modules.dep";
     }
@@ -280,6 +283,30 @@ setup_dwfl_report_kernel_p(const char* modname, const char* filename)
     }
 }
 
+static char * path_insert_sysroot(string sysroot, string path)
+{
+  char * path_new;
+  size_t pos = 1;
+  if (path[0] == '/')
+    path.replace(0, 1, sysroot);
+  while (true) {
+    pos = path.find(":/", pos);
+    if (pos == string::npos)
+      break;
+    path.replace(pos, 2, ":" + sysroot);
+    ++pos;
+  }
+  path_new = new char[path.size()+1];
+  strcpy (path_new, path.c_str());
+  return path_new;
+}
+
+void debuginfo_path_insert_sysroot(string sysroot)
+{
+  debuginfo_path = path_insert_sysroot(sysroot, debuginfo_path);
+  debuginfo_usr_path = path_insert_sysroot(sysroot, debuginfo_usr_path);
+}
+
 static DwflPtr
 setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
 {
@@ -295,7 +322,7 @@ setup_dwfl_kernel (unsigned *modules_found, systemtap_session &s)
   // no way to set the dwfl_callback.debuginfo_path and always
   // passs the plain kernel_release here.  So instead we have to
   // hard-code this magic here.
-  if (s.kernel_build_tree == string("/lib/modules/"
+  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
 				    + s.kernel_release
 				    + "/build"))
     elfutils_kernel_path = s.kernel_release;
diff --git a/setupdwfl.h b/setupdwfl.h
index 48f9105..aa1c800 100644
--- a/setupdwfl.h
+++ b/setupdwfl.h
@@ -69,5 +69,6 @@ int internal_find_debuginfo (Dwfl_Module *mod,
 int execute_abrt_action_install_debuginfo_to_abrt_cache (std::string hex);
 std::string get_kernel_build_id (systemtap_session &s);
 int download_kernel_debuginfo (systemtap_session &s, std::string hex);
+void debuginfo_path_insert_sysroot(std::string sysroot);
 
 #endif
diff --git a/tapset-itrace.cxx b/tapset-itrace.cxx
index 1a9bf67..982ad46 100644
--- a/tapset-itrace.cxx
+++ b/tapset-itrace.cxx
@@ -100,7 +100,7 @@ struct itrace_builder: public derived_probe_builder
 		     std::map<std::string, literal *> const & parameters,
 		     vector<derived_probe *> & finished_results)
   {
-    string path;
+    string path, path_tgt;
     int64_t pid = 0;
     int single_step;
 
@@ -114,12 +114,13 @@ struct itrace_builder: public derived_probe_builder
     // If we have a path, we need to validate it.
     if (has_path)
       {
-        path = find_executable (path);
+        path = find_executable (path, sess.sysroot, sess.sysenv);
         sess.unwindsym_modules.insert (path);
+        path_tgt = path_remove_sysroot(sess, path);
       }
 
     finished_results.push_back(new itrace_derived_probe(sess, base, location,
-							has_path, path, pid,
+							has_path, path_tgt, pid,
 							single_step
 							));
   }
diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
index 64ba900..1ad99cf 100644
--- a/tapset-utrace.cxx
+++ b/tapset-utrace.cxx
@@ -642,7 +642,7 @@ struct utrace_builder: public derived_probe_builder
 		     literal_map_t const & parameters,
 		     vector<derived_probe *> & finished_results)
   {
-    string path;
+    string path, path_tgt;
     int64_t pid;
 
     bool has_path = get_param (parameters, TOK_PROCESS, path);
@@ -679,8 +679,9 @@ struct utrace_builder: public derived_probe_builder
       }
     else if (has_path)
       {
-        path = find_executable (path);
+        path = find_executable (path, sess.sysroot, sess.sysenv);
         sess.unwindsym_modules.insert (path);
+        path_tgt = path_remove_sysroot(sess, path);
       }
     else if (has_pid)
       {
@@ -693,7 +694,7 @@ struct utrace_builder: public derived_probe_builder
       }
 
     finished_results.push_back(new utrace_derived_probe(sess, base, location,
-							has_path, path, pid,
+							has_path, path_tgt, pid,
 							flags));
   }
 };
diff --git a/tapsets.cxx b/tapsets.cxx
index 716e23c..7dee698 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -584,13 +584,14 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params):
       has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
 
       if (has_process)
-        module_val = find_executable (module_val);
+        module_val = find_executable (module_val, sess.sysroot, sess.sysenv);
       if (has_library)
         {
           if (! contains_glob_chars (library_name))
             {
-              path = module_val;
-              module_val = find_executable (library_name, "LD_LIBRARY_PATH");
+              path = path_remove_sysroot(sess, module_val);
+              module_val = find_executable (library_name, sess.sysroot,
+                                            sess.sysenv, "LD_LIBRARY_PATH");
             }
           else
             path = library_name;
@@ -1127,6 +1128,15 @@ bad:
                        base_probe->tok);
 }
 
+string path_remove_sysroot(const systemtap_session& sess, const string& path)
+{
+  size_t pos;
+  string retval = path;
+  if (!sess.sysroot.empty() &&
+      (pos = retval.find(sess.sysroot)) != string::npos)
+    retval.replace(pos, sess.sysroot.length(), "/");
+  return retval;
+}
 
 void
 dwarf_query::add_probe_point(const string& dw_funcname,
@@ -1188,8 +1198,9 @@ dwarf_query::add_probe_point(const string& dw_funcname,
 
       if (has_process)
         {
+          string module_tgt = path_remove_sysroot(sess, module);
           results.push_back (new uprobe_derived_probe(funcname, filename, line,
-                                                      module, reloc_section, addr, reloc_addr,
+                                                      module_tgt, reloc_section, addr, reloc_addr,
                                                       *this, scope_die));
         }
       else
@@ -2051,7 +2062,8 @@ query_one_library (const char *library, dwflpp & dw,
 {
   if (dw.function_name_matches_pattern(library, user_lib))
     {
-      string library_path = find_executable (library, "LD_LIBRARY_PATH");
+      string library_path = find_executable (library, "", dw.sess.sysenv,
+                                             "LD_LIBRARY_PATH");
       probe_point* specific_loc = new probe_point(*base_loc);
       specific_loc->optional = true;
       vector<probe_point::component*> derived_comps;
@@ -3906,7 +3918,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
 	    }
 	  else
 	    {
-	      module = find_executable (module); // canonicalize it
+              module = find_executable (module, "", s.sysenv); // canonicalize it
 	      dw = db.get_user_dw(s, module);
 	    }
 	}
@@ -6546,13 +6558,14 @@ dwarf_builder::build(systemtap_session & sess,
     }
   else if (get_param (parameters, TOK_PROCESS, module_name) || has_null_param(parameters, TOK_PROCESS))
       {
+      module_name = sess.sysroot + module_name;
       if(has_null_param(filled_parameters, TOK_PROCESS))
         {
           wordexp_t words;
           int rc = wordexp(sess.cmd.c_str(), &words, WRDE_NOCMD|WRDE_UNDEF);
           if(rc || words.we_wordc <= 0)
             throw semantic_error(_("unspecified process probe is invalid without a -c COMMAND"));
-          module_name = words.we_wordv[0];
+          module_name = sess.sysroot + words.we_wordv[0];
           filled_parameters[TOK_PROCESS] = new literal_string(module_name);// this needs to be used in place of the blank map
           // in the case of TOK_MARK we need to modify locations as well
           if(location->components[0]->functor==TOK_PROCESS &&
@@ -6605,9 +6618,10 @@ dwarf_builder::build(systemtap_session & sess,
                   if (sess.verbose > 1)
                     clog << _F("Expanded process(\"%s\") to process(\"%s\")",
                                module_name.c_str(), eglobbed.c_str()) << endl;
+                  string eglobbed_tgt = path_remove_sysroot(sess, eglobbed);
 
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (eglobbed));
+                                                    new literal_string (eglobbed_tgt));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6633,7 +6647,7 @@ dwarf_builder::build(systemtap_session & sess,
 
       // PR13338: unquote glob results
       module_name = unescape_glob_chars (module_name);
-      user_path = find_executable (module_name); // canonicalize it
+      user_path = find_executable (module_name, "", sess.sysenv); // canonicalize it
 
       // if the executable starts with "#!", we look for the interpreter of the script
       {
@@ -6679,12 +6693,13 @@ dwarf_builder::build(systemtap_session & sess,
                     if (p3 != string::npos)
                     {
                        string env_path = path.substr(p3);
-                       user_path = find_executable (env_path);
+                       user_path = find_executable (env_path, sess.sysroot,
+                                                    sess.sysenv);
                     }
                 }
                 else
                 {
-                   user_path = find_executable (path);
+                  user_path = find_executable (path, sess.sysroot, sess.sysenv);
                 }
 
                 struct stat st;
@@ -6705,8 +6720,9 @@ dwarf_builder::build(systemtap_session & sess,
 
                   // synthesize a new probe_point, with the expanded string
                   probe_point *pp = new probe_point (*location);
+                  string user_path_tgt = path_remove_sysroot(sess, user_path);
                   probe_point::component* ppc = new probe_point::component (TOK_PROCESS,
-                                                                            new literal_string (user_path.c_str()));
+                                                                            new literal_string (user_path_tgt.c_str()));
                   ppc->tok = location->components[0]->tok; // overwrite [0] slot, pattern matched above
                   pp->components[0] = ppc;
 
@@ -6725,7 +6741,8 @@ dwarf_builder::build(systemtap_session & sess,
 
       if(get_param (parameters, TOK_LIBRARY, user_lib)
 	  && user_lib.length() && ! contains_glob_chars (user_lib))
-	module_name = find_executable (user_lib, "LD_LIBRARY_PATH");
+        module_name = find_executable (user_lib, sess.sysroot, sess.sysenv,
+                                       "LD_LIBRARY_PATH");
       else
 	module_name = user_path; // canonicalize it
 
@@ -8189,14 +8206,14 @@ struct kprobe_builder: public derived_probe_builder
 
 
 void
-kprobe_builder::build(systemtap_session &,
+kprobe_builder::build(systemtap_session & sess,
 		      probe * base,
 		      probe_point * location,
 		      literal_map_t const & parameters,
 		      vector<derived_probe *> & finished_results)
 {
   string function_string_val, module_string_val;
-  string path, library;
+  string path, library, path_tgt, library_tgt;
   int64_t statement_num_val = 0, maxactive_val = 0;
   bool has_function_str, has_module_str, has_statement_num;
   bool has_absolute, has_return, has_maxactive;
@@ -8212,9 +8229,16 @@ kprobe_builder::build(systemtap_session &,
   has_library = get_param (parameters, TOK_LIBRARY, library);
 
   if (has_path)
-    path = find_executable (path);
+    {
+      path = find_executable (path, sess.sysroot, sess.sysenv);
+      path_tgt = path_remove_sysroot(sess, path);
+    }
   if (has_library)
-    library = find_executable (library, "LD_LIBRARY_PATH");
+    {
+      library = find_executable (library, sess.sysroot, sess.sysenv,
+                                 "LD_LIBRARY_PATH");
+      library_tgt = path_remove_sysroot(sess, library);
+    }
 
   if (has_function_str)
     {
@@ -8229,8 +8253,8 @@ kprobe_builder::build(systemtap_session &,
 							    has_path,
 							    has_library,
 							    maxactive_val,
-							    path,
-							    library));
+							    path_tgt,
+							    library_tgt));
     }
   else
     {
@@ -8247,8 +8271,8 @@ kprobe_builder::build(systemtap_session &,
 							    has_path,
 							    has_library,
 							    maxactive_val,
-							    path,
-							    library));
+							    path_tgt,
+							    library_tgt));
     }
 }
 
diff --git a/tapsets.h b/tapsets.h
index c5fb30c..ad0ed70 100644
--- a/tapsets.h
+++ b/tapsets.h
@@ -31,6 +31,8 @@ void register_tapset_timers(systemtap_session& sess);
 void register_tapset_perf(systemtap_session& sess);
 void register_tapset_utrace(systemtap_session& sess);
 
+std::string path_remove_sysroot(const systemtap_session& sess,
+				const std::string& path);
 
 // ------------------------------------------------------------------------
 // Generic derived_probe_group: contains an ordinary vector of the
diff --git a/translate.cxx b/translate.cxx
index 97847a8..2b8d012 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -6242,10 +6242,10 @@ add_unwindsym_vdso (systemtap_session &s)
   // having the BUILDDIR we need to do a deep search (the specific
   // arch name dir in the kernel build tree is unknown).
   string vdso_dir;
-  if (s.kernel_build_tree == string("/lib/modules/"
+  if (s.kernel_build_tree == string(s.sysroot + "/lib/modules/"
 				    + s.kernel_release
 				    + "/build"))
-    vdso_dir = "/lib/modules/" + s.kernel_release + "/vdso";
+    vdso_dir = s.sysroot + "/lib/modules/" + s.kernel_release + "/vdso";
   else
     vdso_dir = s.kernel_build_tree + "/arch/";
 
diff --git a/util.cxx b/util.cxx
index ea90732..a7d8c3b 100644
--- a/util.cxx
+++ b/util.cxx
@@ -387,7 +387,9 @@ tokenize_cxx(const string& str, vector<string>& tokens)
 // same policy as execvp().  A program name not containing a slash
 // will be searched along the $PATH.
 
-string find_executable(const string& name, const string& env_path)
+string find_executable(const string& name, const string& sysroot,
+		       map<string, string>& sysenv,
+		       const string& env_path)
 {
   string retpath;
 
@@ -398,11 +400,15 @@ string find_executable(const string& name, const string& env_path)
 
   if (name.find('/') != string::npos) // slash in the path already?
     {
-      retpath = name;
+      retpath = sysroot + name;
     }
   else // Nope, search $PATH.
     {
-      char *path = getenv(env_path.c_str());
+      char *path;
+      if (sysenv.count(env_path) != 0)
+        path = (char *)sysenv[env_path].c_str();
+      else
+        path = getenv(env_path.c_str());
       if (path)
         {
           // Split PATH up.
@@ -412,7 +418,7 @@ string find_executable(const string& name, const string& env_path)
           // Search the path looking for the first executable of the right name.
           for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); i++)
             {
-              string fname = *i + "/" + name;
+              string fname = sysroot + *i + "/" + name;
               const char *f = fname.c_str();
 
               // Look for a normal executable file.
@@ -431,13 +437,22 @@ string find_executable(const string& name, const string& env_path)
   // Could not find the program on the $PATH.  We'll just fall back to
   // the unqualified name, which our caller will probably fail with.
   if (retpath == "")
-    retpath = name;
+    retpath = sysroot + name;
 
   // Canonicalize the path name.
   char *cf = canonicalize_file_name (retpath.c_str());
   if (cf)
     {
-      retpath = string(cf);
+      string scf = string(cf);
+      if (sysroot.empty())
+        retpath = scf;
+      else {
+        int pos = scf.find(sysroot);
+        if (pos == 0)
+          retpath = scf;
+        else
+          throw runtime_error(_F("find_executable(): file %s not in sysroot %s", cf, sysroot.c_str()));
+      }
       free (cf);
     }
 
diff --git a/util.h b/util.h
index 64a9746..b4d9ebf 100644
--- a/util.h
+++ b/util.h
@@ -12,6 +12,7 @@
 #include <cctype>
 #include <set>
 #include <iomanip>
+#include <map>
 extern "C" {
 #include <libintl.h>
 #include <locale.h>
@@ -53,6 +54,8 @@ void tokenize_full(const std::string& str, std::vector<std::string>& tokens,
 	      const std::string& delimiters);
 void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens);
 std::string find_executable(const std::string& name,
+			    const std::string& sysroot,
+			    std::map<std::string,std::string>& sysenv,
 			    const std::string& env_path = "PATH");
 const std::string cmdstr_quoted(const std::string& cmd);
 const std::string cmdstr_join(const std::vector<std::string>& cmds);
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 2/3] PR12331: Document --sysroot and --sysenv
  2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
  2012-03-08 14:49       ` [PATCH v4 1/3] PR12331: " Wade Farnsworth
@ 2012-03-08 14:50       ` Wade Farnsworth
  2012-03-08 14:51       ` [PATCH v4 3/3] PR12331: Add testcase for " Wade Farnsworth
  2012-03-09  6:56       ` [PATCH v4 0/3] Introduce stap options " Josh Stone
  3 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-08 14:50 UTC (permalink / raw)
  To: systemtap, jistone, fche

Update stap.1 and NEWS to document the new options.
---
 stap.1 |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/stap.1 b/stap.1
index 43658de..52afb0d 100644
--- a/stap.1
+++ b/stap.1
@@ -555,6 +555,19 @@ no limits are imposed.
 Specify the maximum size of files that the process may create, in bytes. If nothing is specified, no limits are
 imposed.
 
+.TP
+.BI \-\-sysroot "=DIR"
+Specify sysroot directory where target files (executables, libraries, etc.)
+are located.  With \fI\-r RELEASE\fR, the sysroot will be searched for the
+appropriate kernel build directory.  With \fI\-r /DIR\fR, however, the sysroot
+will not be used to find the kernel build.
+
+.TP
+.BI \-\-sysenv "=VAR=VALUE"
+Provide an alternate value for an environment variable where the value on a
+remote system differs.  Path variables (e.g. PATH, LD_LIBRARY_PATH) are assumed
+to be relative to the directory provided by \fI\-\-sysroot\fR, if provided.
+
 .SH ARGUMENTS
 
 Any additional arguments on the command line are passed to the script
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 3/3] PR12331: Add testcase for --sysroot and --sysenv
  2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
  2012-03-08 14:49       ` [PATCH v4 1/3] PR12331: " Wade Farnsworth
  2012-03-08 14:50       ` [PATCH v4 2/3] PR12331: Document " Wade Farnsworth
@ 2012-03-08 14:51       ` Wade Farnsworth
  2012-03-09  6:56       ` [PATCH v4 0/3] Introduce stap options " Josh Stone
  3 siblings, 0 replies; 15+ messages in thread
From: Wade Farnsworth @ 2012-03-08 14:51 UTC (permalink / raw)
  To: systemtap, jistone, fche

Signed-off-by: Wade Farnsworth <wade_farnsworth@mentor.com>
---
 testsuite/systemtap.base/sysroot_sysenv.exp |   15 +++++++++++++++
 testsuite/systemtap.base/sysroot_sysenv.stp |    3 +++
 2 files changed, 18 insertions(+), 0 deletions(-)
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.exp
 create mode 100644 testsuite/systemtap.base/sysroot_sysenv.stp

diff --git a/testsuite/systemtap.base/sysroot_sysenv.exp b/testsuite/systemtap.base/sysroot_sysenv.exp
new file mode 100644
index 0000000..72b6822
--- /dev/null
+++ b/testsuite/systemtap.base/sysroot_sysenv.exp
@@ -0,0 +1,15 @@
+set test "sysroot_sysenv"
+
+if {[installtest_p] && [utrace_p] && [uprobes_p]} {
+  spawn stap --sysroot=/ --sysenv=PATH=$env(PATH) $srcdir/$subdir/$test.stp ls -c "ls > /dev/null"
+  expect {
+    -timeout 180
+    -re {^process begin\r\n} { pass "$test" }
+    timeout { fail "$test (timeout)" }
+    eof { fail "$test" }
+  }
+} else {
+  untested "$test"
+}
+catch {close}
+wait
diff --git a/testsuite/systemtap.base/sysroot_sysenv.stp b/testsuite/systemtap.base/sysroot_sysenv.stp
new file mode 100644
index 0000000..950936f
--- /dev/null
+++ b/testsuite/systemtap.base/sysroot_sysenv.stp
@@ -0,0 +1,3 @@
+probe process(@1).begin {
+  println("process begin")
+}
-- 
1.7.0.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 0/3] Introduce stap options --sysroot and --sysenv
  2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
                         ` (2 preceding siblings ...)
  2012-03-08 14:51       ` [PATCH v4 3/3] PR12331: Add testcase for " Wade Farnsworth
@ 2012-03-09  6:56       ` Josh Stone
  3 siblings, 0 replies; 15+ messages in thread
From: Josh Stone @ 2012-03-09  6:56 UTC (permalink / raw)
  To: Wade Farnsworth; +Cc: systemtap, fche

On 03/08/2012 06:48 AM, Wade Farnsworth wrote:
> This patchset introduces --sysroot and --sysenv options for stap, which
> improve functionality in environments where the compiling system differs
> from the one running the probes.
> 
> See Patch 1/3's description for more details on what has been implemented.
> 
> v2 - Implemented several improvements per Josh Stone's comments.
> v3 - Further improvements per Josh Stone.  Include documentation and test cases
>      for the new options.
> v4 - Add more detail to the man page for --sysroot to clarify which paths
>      are affected.
>    - Changed handling of paths where both sysroot and non-
>      sysroot versions are needed so that it's clear which version we're tracking.
>    - Store the sysenv variable as map<string, string> instead of
>      <string, char*>.
>     
> 
> Wade Farnsworth (3):
>   PR12331: Introduce stap options --sysroot and --sysenv
>   PR12331: Document --sysroot and --sysenv
>   PR12331: Add testcase for --sysroot and --sysenv

Thanks, these are now merged and pushed.  I did have to fix some
conflicts with commit 372c6458, but I think I did that right. :)

Josh

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-03-09  6:56 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-09 14:51 [PATCH] Add --sysroot option Wade Farnsworth
2012-01-20 15:49 ` Wade Farnsworth
2012-01-20 18:11 ` Josh Stone
2012-02-09 18:26 ` [PATCH v2] PR12331: Introduce stap options --sysroot and --sysenv Wade Farnsworth
2012-02-17 14:39   ` Wade Farnsworth
2012-02-24 22:56   ` Josh Stone
2012-03-02 14:47   ` [PATCH v3 0/3] " Wade Farnsworth
2012-03-02 14:48     ` [PATCH v3 1/3] " Wade Farnsworth
2012-03-02 14:48     ` [PATCH v3 2/3] PR12331: Document " Wade Farnsworth
2012-03-02 14:49     ` [PATCH v3 3/3] PR12331: Add testcase for " Wade Farnsworth
2012-03-08 14:48     ` [PATCH v4 0/3] Introduce stap options " Wade Farnsworth
2012-03-08 14:49       ` [PATCH v4 1/3] PR12331: " Wade Farnsworth
2012-03-08 14:50       ` [PATCH v4 2/3] PR12331: Document " Wade Farnsworth
2012-03-08 14:51       ` [PATCH v4 3/3] PR12331: Add testcase for " Wade Farnsworth
2012-03-09  6:56       ` [PATCH v4 0/3] Introduce stap options " Josh Stone

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).