public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* process.plt.return probes
@ 2014-07-01 18:12 Stan Cox
  0 siblings, 0 replies; only message in thread
From: Stan Cox @ 2014-07-01 18:12 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 1318 bytes --]

This patch (not fully tested but complete enough to spur discussion) 
adds plt.return.  First, a brief discussion of what the plt (program 
linkage table) and got (global offset table do:

.text
  1. foo@plt jumps to .got.plt entry via .plt entry
    callq 0x1,foo@plt

.plt
  1a. first here
    0x0  jmpq 0xN(%rip) # 0x10
  3. which pushes foo's entry #
    0x4  pushq 0x4c
  4. then jumps to rtld which puts address of foo into .got.plt entry
    0x8  jmpq <rtld>

.got.plt
  1b. second here
  2. then jumps to insn after plt entry jump
  5. so going forward jumps will be here to target
    0x10 jmpq 0x4

The current process.plt mechanism works by setting a probe at the 
.got.plt address.  To allow for process.plt.return probes this mechanism 
has been enhanced as follows:
iterate_over_plt
->query_one_plt
   ->iterate_over_libraries
     has been changed to iterate if there is no .interp; in which case
     each interpreter is tried until success.  (The ldd command uses
     ld-linux --verify; but posix_spawn cannot check errno,
                        so it cannot do something similar, can it?)
     ->pltreturn_library_callback
       looks for entry in the elf symbol table
   if entry found in a library
   then handle as process.function[.return]
   else handle via existing process.plt.statement




[-- Attachment #2: stap-plt.patch --]
[-- Type: text/x-patch, Size: 10388 bytes --]

/work/scox/systemtap/src /work/scox/systemtap/bld /work/scox/systemtap/bld ~
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 09407b4..6ab8fd3 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -1248,6 +1248,23 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
   assert (this->module_name.length() != 0);
 
   Dwarf_Addr bias;
+
+  // Interpreters should follow startswith("/lib/ld") || startswith("/lib64/ld")
+  // Untrustworthy loaders should not be installed in those paths.
+  // See also http://sourceware.org/git/?p=glibc.git;a=blob;f=shlib-versions;hb=HEAD
+
+  string interpreters [] = {
+      "",                               // desired interpreter entry
+      "/lib64/ld-linux-x86-64.so.2",   // x8664
+      "/lib/ld-linux.so.2",            // x86
+      "/lib/ld64.so.1",                // s390x, ppc64
+      "/lib64/ld64.so.1",
+      "/lib/ld-linux-ia64.so.2",       // ia64
+      "/emul/ia32-linux/lib/ld-linux.so.2",
+      "/lib/ld-linux.so.3",            // arm
+      "/lib/ld-linux-armhf.so.3"      // arm
+  };
+
 //  We cannot use this: dwarf_getelf (dwfl_module_getdwarf (module, &bias))
   Elf *elf = dwfl_module_getelf (module, &bias);
 //  elf_getphdrnum (elf, &phnum) is not available in all versions of elfutils
@@ -1270,27 +1287,7 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
         }
     }
 
-  if (interpreter.length() == 0)
-    return;
-  // If it gets cumbersome to maintain this whitelist, we could just check for
-  // startswith("/lib/ld") || startswith("/lib64/ld"), and trust that no admin
-  // would install untrustworthy loaders in those paths.
-  // See also http://sourceware.org/git/?p=glibc.git;a=blob;f=shlib-versions;hb=HEAD
-  if (interpreter != "/lib/ld.so.1"                     // s390, ppc
-      && interpreter != "/lib/ld64.so.1"                // s390x, ppc64
-      && interpreter != "/lib64/ld64.so.1"
-      && interpreter != "/lib/ld-linux-ia64.so.2"       // ia64
-      && interpreter != "/emul/ia32-linux/lib/ld-linux.so.2"
-      && interpreter != "/lib64/ld-linux-x86-64.so.2"   // x8664
-      && interpreter != "/lib/ld-linux.so.2"            // x86
-      && interpreter != "/lib/ld-linux.so.3"            // arm
-      && interpreter != "/lib/ld-linux-armhf.so.3"      // arm
-      )
-    {
-      sess.print_warning (_F("module %s --ldd skipped: unsupported interpreter: %s",
-                               module_name.c_str(), interpreter.c_str()));
-      return;
-    }
+  interpreters[0] = interpreter;
 
   vector<string> ldd_command;
   ldd_command.push_back("/usr/bin/env");
@@ -1300,6 +1297,15 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
   ldd_command.push_back(interpreter);
   ldd_command.push_back(module_name);
 
+  for (unsigned int i = 0; i < sizeof (interpreters) / sizeof (void*); i++)
+    {
+      // interpreter not setup yet
+      if (interpreters[0].length() == 0 && i == 0)
+        continue;
+      // found desired interpreter; skip remainder of interpreter list
+      else if (interpreters[0].length() > 0 && i > 0)
+        continue;
+      ldd_command[4] = interpreters[i];
       FILE *fp;
       int child_fd;
       pid_t child = stap_spawn_piped(sess.verbose, ldd_command, NULL, &child_fd);
@@ -1351,9 +1357,13 @@ dwflpp::iterate_over_libraries<void>(void (*callback)(void*, const char*),
               free (soname);
               free (shlib);
             }
+          if (! added.empty())
+            interpreters[0] = interpreters[i];
+
           if ((fclose(fp) || stap_waitpid(sess.verbose, child)))
             sess.print_warning("failed to read libraries from " + module_name + ": " + strerror(errno));
         }
+    }
 
   for (std::set<std::string>::iterator it = added.begin();
       it != added.end();
diff --git a/dwflpp.h b/dwflpp.h
index 2d4a656..548bd87 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -105,7 +105,8 @@ module_info
   info_status symtab_status;    // symbol table cached?
 
   std::set<std::string> inlined_funcs;
-  std::set<std::string> plt_funcs;
+//  std::set<std::string> plt_funcs;
+  std::map<std::string,std::string> plt_funcs;
   std::set<std::pair<std::string,std::string> > marks; /* <provider,name> */
 
   void get_symtab();
diff --git a/tapsets.cxx b/tapsets.cxx
index edbcf92..8e14b80 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -587,6 +587,7 @@ struct base_query
   static bool get_number_param(literal_map_t const & params,
 			       string const & k, Dwarf_Addr & v);
   static void query_library_callback (base_query *me, const char *data);
+  static void pltreturn_library_callback (dwarf_query *me, const char *data);
   static void query_plt_callback (base_query *me, const char *link, size_t addr);
   virtual void query_library (const char *data) = 0;
   virtual void query_plt (const char *link, size_t addr) = 0;
@@ -2442,15 +2443,55 @@ void
 base_query::query_plt_callback (base_query *me, const char *entry, size_t address)
 {
   if (me->dw.function_name_matches_pattern (entry, me->plt_val))
+    {
       me->query_plt (entry, address);
-  me->dw.mod_info->plt_funcs.insert(entry);
+      if (me->dw.mod_info->plt_funcs[entry].length() == 0)
+        me->dw.mod_info->plt_funcs[entry] = "";
+    }
+  //       dw.mod_info->marks.insert(make_pair(provider_name, probe_name));
+  // for itmarks...marks.begin()  itmarks->first.c_str()
+}
+
+
+void
+base_query::pltreturn_library_callback (dwarf_query *me, const char *entry)
+{
+  static Dwfl_Callbacks callbacks = {
+      &dwfl_linux_proc_find_elf,
+      &dwfl_standard_find_debuginfo,
+      NULL,
+      NULL,
+    };
+  Dwfl *dwfl = dwfl_begin (&callbacks);
+
+  Dwfl_Module *module = dwfl_report_offline (dwfl, entry, entry, -1);
+  int syms = dwfl_module_getsymtab (module);
+   DWFL_ASSERT (_("Getting symbols"), syms >= 0);
+
+   // Search elf symbol table of shared object for entry
+   for (int i = 0; i < syms; i++)
+     {
+       GElf_Sym sym;
+       GElf_Word shndxp;
+       const char *symname = dwfl_module_getsym(module, i, &sym, &shndxp);
+       if (symname && strcmp (me->plt_val.c_str(), symname) == 0)
+         {
+           if (GELF_ST_TYPE(sym.st_info) == STT_FUNC
+               && (GELF_ST_BIND(sym.st_info) == STB_GLOBAL
+                   || GELF_ST_BIND(sym.st_info) == STB_WEAK
+                   || GELF_ST_BIND(sym.st_info) == STB_GNU_UNIQUE))
+             {
+               me->dw.mod_info->plt_funcs[me->plt_val] = entry;
+             }
+         }
+     }
 }
 
 
 void
 query_one_plt (const char *entry, long addr, dwflpp & dw,
     probe * base_probe, probe_point *base_loc,
-    vector<derived_probe *> & results, base_query *q)
+    vector<derived_probe *> & results, dwarf_query *q)
   {
       string module = dw.module_name;
       if (q->has_process)
@@ -2458,7 +2499,7 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
 
       probe_point* specific_loc = new probe_point(*base_loc);
       specific_loc->well_formed = true;
-
+      string save_plt_val;
       vector<probe_point::component*> derived_comps;
 
       if (dw.sess.verbose > 2)
@@ -2477,6 +2518,14 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
         else if ((*it)->functor == TOK_PLT)
           {
             // Replace possibly globby component
+            save_plt_val = q->plt_val;
+            q->plt_val = entry;
+            q->dw.iterate_over_libraries (&q->pltreturn_library_callback, q);
+            q->plt_val = save_plt_val;
+
+            if (q->dw.mod_info->plt_funcs[entry].length() == 0)
+              {
+                // Cannot find entry in a library: PROCESS.PLT.STATEMENT
                 *it = new probe_point::component(TOK_PLT,
                     new literal_string(entry));
                 derived_comps.push_back(*it);
@@ -2484,7 +2533,23 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
                     new literal_number(addr, true)));
               }
             else
+              {
+                // Found entry in a library: PROCESS.FUNCTION
+                // Change TOK_PROCESS argument to the found library path
+                // TODO not the ideal way to do this
+                derived_comps[0]->arg = new literal_string(q->dw.mod_info->plt_funcs[entry].c_str());
+                *it = new probe_point::component(TOK_FUNCTION,
+                    new literal_string(entry));
                 derived_comps.push_back(*it);
+              }
+          }
+        else if ((*it)->functor == TOK_RETURN)
+          {
+            derived_comps.push_back(new probe_point::component(TOK_RETURN));
+          }
+        else
+          derived_comps.push_back(*it);
+
       probe_point* derived_loc = new probe_point(*specific_loc);
       derived_loc->components = derived_comps;
       probe *new_base = new probe (new probe (base_probe, specific_loc),
@@ -2493,6 +2558,7 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
       plt_expanding_visitor pltv (e);
       pltv.replace (new_base->body);
       derive_probes(dw.sess, new_base, results);
+      return;
   }
 
 
@@ -5211,6 +5277,23 @@ dwarf_derived_probe::register_plt_variants(systemtap_session& s,
   root->bind_str(TOK_PLT)->bind_num(TOK_STATEMENT)
     ->bind_privilege(pr_all)
     ->bind(dw);
+
+  root->bind(TOK_PLT)
+    ->bind(TOK_RETURN)
+    ->bind_privilege(pr_all)
+    ->bind(dw);
+  root->bind_str(TOK_PLT)
+    ->bind(TOK_RETURN)
+    ->bind_privilege(pr_all)
+    ->bind(dw);
+  root->bind(TOK_PLT)->bind_num(TOK_STATEMENT)
+    ->bind(TOK_RETURN)
+    ->bind_privilege(pr_all)
+    ->bind(dw);
+  root->bind_str(TOK_PLT)->bind_num(TOK_STATEMENT)
+    ->bind(TOK_RETURN)
+    ->bind_privilege(pr_all)
+    ->bind(dw);
 }
 
 void
@@ -7420,8 +7503,11 @@ suggest_plt_functions(systemtap_session& sess,
     {
       map<string, module_info*>::const_iterator itcache;
       if ((itcache = cache.find(*itmod)) != cache.end())
-        funcs.insert(itcache->second->plt_funcs.begin(),
-                     itcache->second->plt_funcs.end());
+        for (std::map<string,string>::iterator it=itcache->second->plt_funcs.begin();
+            it != itcache->second->plt_funcs.end(); ++it)
+        funcs.insert(it->first);
+//        funcs.insert(itcache->second->plt_funcs.begin(),
+//                     itcache->second->plt_funcs.end());
     }
 
   if (sess.verbose > 2)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2014-07-01 18:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-01 18:12 process.plt.return probes Stan Cox

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).