]> sourceware.org Git - systemtap.git/commitdiff
PR14706: Add proto-exec support in stapdyn
authorJosh Stone <jistone@redhat.com>
Thu, 7 Feb 2013 21:02:30 +0000 (13:02 -0800)
committerJosh Stone <jistone@redhat.com>
Thu, 7 Feb 2013 21:02:30 +0000 (13:02 -0800)
This adds preliminary support for stapdyn to follow execs, but the code
it instrument the new process is currently blocked out.  I'm seeing
dyninst hang during loadLibrary, waiting for IRPC, but haven't yet
figured out why.

* stapdyn/mutatee.cxx (mutatee_freezer): New helper to automatically
  stop a process and then continue it when leaving that scope.
  (mutatee::begin_callback): Use a mutatee_freezer.
  (mutatee::thread_callback): Use a mutatee_freezer.
  (mutatee::copy_forked_instrumentation): Use two mutatee_freezers.
  (mutatee::instrument_dynprobes): Support a flag to indicate this is
  post-exec, so first run any process.end probes from before exec.
  (mutatee::exec_reset_instrumentation): New, clear all members that are
  invalidated by the process exec.
* stapdyn/mutator.cxx (g_exec_callback): New global callback for execs.
  (mutator::exec_callback): New specific callback for execs.  Clear old
  instrumentation, then instrument it anew (buggy, #if 0 for now).

stapdyn/mutatee.cxx
stapdyn/mutatee.h
stapdyn/mutator.cxx
stapdyn/mutator.h

index 3134b51eac736d4600e9af9c4df1af8d8894b267..40e84fb4687ba84055fe72cb1d24111f7745aa17 100644 (file)
@@ -83,6 +83,33 @@ get_dwarf_registers(BPatch_process *app,
 }
 
 
+// Simple object to temporarily make sure a process is stopped
+class mutatee_freezer {
+    mutatee& m;
+    bool already_stopped;
+
+  public:
+    mutatee_freezer(mutatee& m):
+      m(m), already_stopped(m.is_stopped())
+    {
+      // If process is currently running, stop it.
+      if (!already_stopped && !m.stop_execution())
+        {
+          staplog(3) << "stopping process failed, stopped="
+                     << m.is_stopped() << ", terminated="
+                     << m.is_terminated() << endl;
+        }
+    }
+
+    ~mutatee_freezer()
+    {
+      // Let the process continue (if it wasn't stopped when we started).
+      if (!already_stopped)
+        m.continue_execution();
+    }
+};
+
+
 mutatee::mutatee(BPatch_process* process):
   pid(process? process->getPid() : 0),
   process(process), stap_dso(NULL),
@@ -405,14 +432,9 @@ void
 mutatee::begin_callback()
 {
   // process->oneTimeCode() requires that the process be stopped
-  bool stopped = process->isStopped();
-  if (!stopped && !stop_execution())
-    {
-      staplog(3) << "stopping process failed, stopped="
-                << process->isStopped() << ", terminated="
-                << process->isTerminated() << endl;
-      return;
-    }
+  mutatee_freezer mf(*this);
+  if (!is_stopped())
+    return;
 
   for (size_t i = 0; i < attached_probes.size(); ++i)
     {
@@ -423,10 +445,6 @@ mutatee::begin_callback()
          call_utrace_dynprobe(probe);
        }
     }
-
-  // Let the process continue (if it wasn't stopped when we started).
-  if (!stopped)
-    continue_execution();
 }
 
 
@@ -466,14 +484,9 @@ mutatee::thread_callback(BPatch_thread *thread, bool create_p)
 
   // thread->oneTimeCode() requires that the process (not just the
   // thread) be stopped. So, stop the process if needed.
-  bool stopped = process->isStopped();
-  if (!stopped && !stop_execution())
-    {
-      staplog(3) << "stopping process failed, stopped="
-                << process->isStopped() << ", terminated="
-                << process->isTerminated() << endl;
-      return;
-    }
+  mutatee_freezer mf(*this);
+  if (!is_stopped())
+    return;
 
   for (size_t i = 0; i < attached_probes.size(); ++i)
     {
@@ -486,10 +499,6 @@ mutatee::thread_callback(BPatch_thread *thread, bool create_p)
          call_utrace_dynprobe(probe, thread);
        }
     }
-
-  // Let the process continue (if it wasn't stopped when we started).
-  if (!stopped)
-    continue_execution();
 }
 
 void
@@ -506,7 +515,8 @@ mutatee::find_attached_probes(uint64_t flag,
 
 // Look for probe matches in all objects.
 void
-mutatee::instrument_dynprobes(const vector<dynprobe_target>& targets)
+mutatee::instrument_dynprobes(const vector<dynprobe_target>& targets,
+                              bool after_exec_p)
 {
   if (!process || !stap_dso || targets.empty())
     return;
@@ -515,6 +525,13 @@ mutatee::instrument_dynprobes(const vector<dynprobe_target>& targets)
   if (!image)
     return;
 
+  // If this is post-exec, run any process.end from the pre-exec process
+  if (after_exec_p && !attached_probes.empty())
+    {
+      exit_callback(NULL);
+      attached_probes.clear();
+    }
+
   // Match non object/path specific probes.
   instrument_global_dynprobes(targets);
 
@@ -533,6 +550,9 @@ mutatee::copy_forked_instrumentation(mutatee& other)
   if (!process)
     return;
 
+  // Freeze both processes, so we have a stable base.
+  mutatee_freezer mf_parent(other), mf(*this);
+
   // Find the same stap module in the fork
   if (other.stap_dso)
     {
@@ -576,6 +596,21 @@ mutatee::copy_forked_instrumentation(mutatee& other)
 }
 
 
+// Reset instrumentation after an exec
+void
+mutatee::exec_reset_instrumentation()
+{
+  // Reset members that are now out of date
+  stap_dso = NULL;
+  snippets.clear();
+  semaphores.clear();
+
+  // NB: the utrace attached_probes are saved, so process.end can run as the
+  // new process is instrumented.  Thus, no attached_probes.clear() yet.
+  utrace_enter_function = NULL;
+}
+
+
 // Remove all BPatch snippets we've instrumented in the target
 void
 mutatee::remove_instrumentation()
index 0875540f3bce0f71efbadefe23a59ea30d5156a7..996ea4809de7c32949c47fc2b18f4ad7af2d0b45 100644 (file)
@@ -71,11 +71,15 @@ class mutatee {
                                      const std::vector<dynprobe_target>& targets);
 
     // Look for probe matches in all objects.
-    void instrument_dynprobes(const std::vector<dynprobe_target>& targets);
+    void instrument_dynprobes(const std::vector<dynprobe_target>& targets,
+                              bool after_exec_p=false);
 
     // Copy data for forked instrumentation
     void copy_forked_instrumentation(mutatee& other);
 
+    // Reset instrumentation after an exec
+    void exec_reset_instrumentation();
+
     // Remove all BPatch snippets we've instrumented in the target
     void remove_instrumentation();
 
index ea95c564423542f35db5a9e3ce89e7edb0c59377..ea9a4bd110a6793b78dd54143c454c9cd09c390e 100644 (file)
@@ -49,6 +49,14 @@ g_post_fork_callback(BPatch_thread *parent, BPatch_thread *child)
 }
 
 
+static void
+g_exec_callback(BPatch_thread *thread)
+{
+  for (size_t i = 0; i < g_mutators.size(); ++i)
+    g_mutators[i]->exec_callback(thread);
+}
+
+
 static void
 g_exit_callback(BPatch_thread *thread, BPatch_exitType type)
 {
@@ -170,6 +178,7 @@ mutator::load ()
       // STAPDYN_PROBE_FLAG_PROC_BEGIN, because we might want to trigger
       // any of the other types of probes in new processes too.
       patch.registerPostForkCallback(g_post_fork_callback);
+      patch.registerExecCallback(g_exec_callback);
 
       // Do we need a exit callback?
       if (matching_probes_exist(STAPDYN_PROBE_FLAG_PROC_END))
@@ -471,6 +480,8 @@ mutator::dynamic_library_callback(BPatch_thread *thread,
     return;
 
   BPatch_process* process = thread->getProcess();
+  staplog(1) << "dlopen \"" << module->libraryName()
+             << "\", pid = " << process->getPid() << endl;
   boost::shared_ptr<mutatee> mut = find_mutatee(process);
   if (mut)
     mut->instrument_object_dynprobes(module->getObject(), targets);
@@ -505,6 +516,35 @@ mutator::post_fork_callback(BPatch_thread *parent, BPatch_thread *child)
 }
 
 
+// Callback to respond to exec events.  Check if it matches our
+// targets, and handle accordingly.
+void
+mutator::exec_callback(BPatch_thread *thread)
+{
+  if (!thread)
+    return;
+
+  BPatch_process* process = thread->getProcess();
+
+  staplog(1) << "exec, pid = " << process->getPid() << endl;
+
+  boost::shared_ptr<mutatee> mut = find_mutatee(process);
+  if (mut)
+    {
+      // Clear previous instrumentation
+      mut->exec_reset_instrumentation();
+
+      // FIXME the loadLibrary is hanging in Dyninst waiting for IRPC.
+      // I've tried deferring this until update_mutatees() too - same hang.
+#if 0
+      // Load our module again in the new process
+      if (mut->load_stap_dso(module_name))
+        mut->instrument_dynprobes(targets, true);
+#endif
+    }
+}
+
+
 void
 mutator::exit_callback(BPatch_thread *thread,
                       BPatch_exitType type __attribute__((unused)))
index 96206315da32e36891ae5ccbccc837e0296adec3..44743cd4cbf108d18605f46d94754e320bfee456 100644 (file)
@@ -89,6 +89,7 @@ class mutator {
     // Callback to respond to post fork events.  Check if it matches
     // our targets, and handle accordingly.
     void post_fork_callback(BPatch_thread *parent, BPatch_thread *child);
+    void exec_callback(BPatch_thread *thread);
     void exit_callback(BPatch_thread *thread, BPatch_exitType type);
 
     void thread_create_callback(BPatch_process *proc, BPatch_thread *thread);
This page took 0.032785 seconds and 5 git commands to generate.