]> sourceware.org Git - systemtap.git/commitdiff
stapdyn: Reorganize utrace probing, and get end-by-exec working
authorJosh Stone <jistone@redhat.com>
Sat, 15 Feb 2014 01:25:12 +0000 (17:25 -0800)
committerJosh Stone <jistone@redhat.com>
Sat, 15 Feb 2014 01:25:12 +0000 (17:25 -0800)
* mutatee.cxx (mutatee::exec_reset_instrumentation): Save process.end
  probes into exec_proc_end_probes, and clear the rest of attached_probes.
  (mutatee::call_utrace_dynprobes): Take a whole vector of probes, and do
  the lookup for utrace_enter_function here.
  (mutatee::find_attached_probes): Return the vector directly.
  (mutatee::thread_callback): Use find_attached_probes, and pass that to
  call_utrace_dynprobes as is.
  (mutatee::begin_callback): Ditto.
  (mutatee::exit_callback): Ditto, except treat exec specially.
  (mutatee::instrument_dynprobes): Don't try to deal with exec here,
  because the stap module probably isn't ready yet.
* mutator.cxx (mutator::exec_callback): Call mutatee::exit_callback.
  (mutator::exit_callback): Align the fake-local probe hits to work more
  similarly to mutatee::exit_callback.

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

index 08adfe2dd50ac7a45a792b933530e10d41e2413c..de0120208f2705dc60b1b89ee3ee9cd6a994d95e 100644 (file)
@@ -194,24 +194,40 @@ mutatee::update_semaphores(unsigned short delta, size_t start)
 
 
 void
-mutatee::call_utrace_dynprobe(const dynprobe_location& probe,
-                              BPatch_thread* thread)
+mutatee::call_utrace_dynprobes(const vector<dynprobe_location>& probes,
+                              BPatch_thread* thread)
 {
-  if (utrace_enter_function != NULL)
+  if (!stap_dso || probes.empty())
+    return;
+
+  if (utrace_enter_function == NULL)
+    {
+      vector<BPatch_function *> functions;
+      stap_dso->findFunction("enter_dyninst_utrace_probe",
+                            functions);
+      if (!functions.empty())
+       utrace_enter_function = functions[0];
+      else
+       {
+         staplog(1) << "no utrace enter function in pid " << pid << "!" << endl;
+         return;
+       }
+    }
+
+  for (size_t i = 0; i < probes.size(); ++i)
     {
+      const dynprobe_location& probe = probes[i];
       vector<BPatch_snippet *> args;
       args.push_back(new BPatch_constExpr((int64_t)probe.index));
       args.push_back(new BPatch_constExpr((void*)NULL)); // pt_regs
-      staplog(2) << "calling utrace function in pid " << pid
-                << " with " << args.size() << " args" << endl;
       BPatch_funcCallExpr call(*utrace_enter_function, args);
+      staplog(3) << "calling utrace function in pid " << pid
+                << " for probe index " << probe.index << endl;
       if (thread)
        thread->oneTimeCode(call);
       else
        process->oneTimeCode(call);
     }
-  else
-    staplog(1) << "no utrace enter function in pid " << pid << "!" << endl;
 }
 
 
@@ -220,19 +236,7 @@ mutatee::call_utrace_dynprobe(const dynprobe_location& probe,
 void
 mutatee::instrument_utrace_dynprobe(const dynprobe_location& probe)
 {
-  if (!stap_dso)
-    return;
-
-  if (utrace_enter_function == NULL)
-    {
-      vector<BPatch_function *> functions;
-      stap_dso->findFunction("enter_dyninst_utrace_probe",
-                            functions);
-      if (!functions.empty())
-       utrace_enter_function = functions[0];
-    }
-
-  // Remember this probe. It will get called from a callback function.
+  // Just remember this probe. It will get called from a callback function.
   attached_probes.push_back(probe);
 }
 
@@ -474,56 +478,65 @@ mutatee::instrument_object_dynprobes(BPatch_object* object,
 
 
 void
-mutatee::begin_callback()
+mutatee::begin_callback(BPatch_thread *thread)
 {
+  const vector<dynprobe_location>& proc_begin_probes =
+    find_attached_probes(STAPDYN_PROBE_FLAG_PROC_BEGIN);
+
+  // Shortcut out if there aren't any relevant probes
+  if (proc_begin_probes.empty())
+    return;
+
   // process->oneTimeCode() requires that the process be stopped
   mutatee_freezer mf(*this);
   if (!is_stopped())
     return;
 
-  for (size_t i = 0; i < attached_probes.size(); ++i)
-    {
-      const dynprobe_location& probe = attached_probes[i];
-      if (probe.flags & STAPDYN_PROBE_FLAG_PROC_BEGIN)
-       {
-         staplog(2) << "found begin proc probe in pid " << pid
-                    << ", index = " << probe.index << endl;
-         call_utrace_dynprobe(probe);
-       }
-    }
+  staplog(2) << "firing " << proc_begin_probes.size()
+            << " process.begin probes in pid " << pid << endl;
+  call_utrace_dynprobes(proc_begin_probes, thread);
 }
 
 
-// FIXME: We have a problem with STAPDYN_PROBE_FLAG_PROC_END
-// (i.e. 'process.end' probes).
-//
-// If we use dyninst's registerExitCallback(), when that callback
-// hits, we can't stop the process before it exits. So, we can't call
-// oneTimeCode() as we've done for the thread callbacks. So, that
-// doesn't work.
-//
-// When registerExitCallback() hits, we could just run the probe
-// locally, but then the probe context wouldn't be correct.
-
+// FIXME: When dyninst's registerExitCallback() hits, it's too late
+// to stop the process and inject oneTimeCode() for process.end.
+// So while the code here works for post-exec "end", for now the
+// mutator::exit_callback() will run its probes locally in stapdyn.
 void
-mutatee::exit_callback(BPatch_thread *thread)
+mutatee::exit_callback(BPatch_thread *thread, bool exec_p)
 {
-  for (size_t i = 0; i < attached_probes.size(); ++i)
-    {
-      const dynprobe_location& probe = attached_probes[i];
-      if (probe.flags & STAPDYN_PROBE_FLAG_PROC_END)
-       {
-         staplog(2) << "found end proc probe in pid " << pid
-                    << ", index = " << probe.index << endl;
-         call_utrace_dynprobe(probe, thread);
-       }
-    }
+  const vector<dynprobe_location>& proc_end_probes =
+    exec_p ? exec_proc_end_probes
+    : find_attached_probes(STAPDYN_PROBE_FLAG_PROC_END);
+
+  // Shortcut out if there aren't any relevant probes
+  if (proc_end_probes.empty())
+    return;
+
+  // thread->oneTimeCode() requires that the process (not just the
+  // thread) be stopped. So, stop the process if needed.
+  mutatee_freezer mf(*this);
+  if (!is_stopped())
+    return;
+
+  staplog(2) << "firing " << proc_end_probes.size()
+            << " process.end probes in pid " << pid << endl;
+  call_utrace_dynprobes(proc_end_probes, thread);
 }
 
 
 void
 mutatee::thread_callback(BPatch_thread *thread, bool create_p)
 {
+  const vector<dynprobe_location>& probes =
+    find_attached_probes(create_p
+                        ? STAPDYN_PROBE_FLAG_THREAD_BEGIN
+                        : STAPDYN_PROBE_FLAG_THREAD_END);
+
+  // Shortcut out if there aren't any relevant probes
+  if (probes.empty())
+    return;
+
   // If 'thread' is the main process, just return. We can't stop the
   // process before it terminates.
   if (thread->getLWP() == process->getPid())
@@ -535,36 +548,30 @@ mutatee::thread_callback(BPatch_thread *thread, bool create_p)
   if (!is_stopped())
     return;
 
-  for (size_t i = 0; i < attached_probes.size(); ++i)
-    {
-      const dynprobe_location& probe = attached_probes[i];
-      if ((create_p && probe.flags & STAPDYN_PROBE_FLAG_THREAD_BEGIN)
-         || (!create_p && probe.flags & STAPDYN_PROBE_FLAG_THREAD_END))
-        {
-         staplog(2) << "found " << (create_p ? "begin" : "end")
-                    << " thread probe in pid " << pid
-                    << ", index = " << probe.index << endl;
-         call_utrace_dynprobe(probe, thread);
-       }
-    }
+  staplog(2) << "firing " << probes.size()
+            << " process.thread." << (create_p ? "begin" : "end")
+            << " probes in pid " << pid << endl;
+  call_utrace_dynprobes(probes, thread);
 }
 
-void
-mutatee::find_attached_probes(uint64_t flag,
-                             vector<const dynprobe_location *>&probes)
+
+vector<dynprobe_location>
+mutatee::find_attached_probes(uint64_t flag)
 {
+  vector<dynprobe_location> probes;
   for (size_t i = 0; i < attached_probes.size(); ++i)
     {
       const dynprobe_location& probe = attached_probes[i];
       if (probe.flags & flag)
-       probes.push_back(&probe);
+       probes.push_back(probe);
     }
+  return probes;
 }
 
+
 // Look for probe matches in all objects.
 void
-mutatee::instrument_dynprobes(const vector<dynprobe_target>& targets,
-                              bool after_exec_p)
+mutatee::instrument_dynprobes(const vector<dynprobe_target>& targets)
 {
   if (!process || !stap_dso || targets.empty())
     return;
@@ -573,13 +580,6 @@ 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);
 
@@ -638,9 +638,14 @@ mutatee::copy_forked_instrumentation(mutatee& other)
         semaphores.push_back(semaphore);
     }
 
-  // Update utrace probes to match
+  // Update utrace probes to match, except PID-based probes.
+  // (A forked PID will never be the same as the parent.)
   for (size_t i = 0; i < other.attached_probes.size(); ++i)
-    instrument_utrace_dynprobe(other.attached_probes[i]);
+    {
+      const dynprobe_location& probe = other.attached_probes[i];
+      if (probe.offset == 0)
+       instrument_utrace_dynprobe(probe);
+    }
 }
 
 
@@ -653,8 +658,11 @@ mutatee::exec_reset_instrumentation()
   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.
+  // NB: the utrace process.end probes are saved, so they can run right
+  // before the new process does its process.begin.
+  exec_proc_end_probes = find_attached_probes(STAPDYN_PROBE_FLAG_PROC_END);
+
+  attached_probes.clear();
   utrace_enter_function = NULL;
 }
 
index b7abb88c75989512633905c5d4c7dad76071d6f8..432774a4000bc94ce3fef7d2f80457436a44061d 100644 (file)
@@ -36,14 +36,17 @@ class mutatee {
     std::vector<dynprobe_location> attached_probes;
     BPatch_function* utrace_enter_function;
 
+    // process.end probes saved to run after exec
+    std::vector<dynprobe_location> exec_proc_end_probes;
+
     // disable implicit constructors by not implementing these
     mutatee (const mutatee& other);
     mutatee& operator= (const mutatee& other);
 
     void update_semaphores(unsigned short delta, size_t start=0);
 
-    void call_utrace_dynprobe(const dynprobe_location& probe,
-                              BPatch_thread* thread=NULL);
+    void call_utrace_dynprobes(const std::vector<dynprobe_location>& probes,
+                               BPatch_thread* thread=NULL);
     void instrument_utrace_dynprobe(const dynprobe_location& probe);
     void instrument_global_dynprobe_target(const dynprobe_target& target);
     void instrument_global_dynprobes(const std::vector<dynprobe_target>& targets);
@@ -73,8 +76,7 @@ class mutatee {
                                      const std::vector<dynprobe_target>& targets);
 
     // Look for probe matches in all objects.
-    void instrument_dynprobes(const std::vector<dynprobe_target>& targets,
-                              bool after_exec_p=false);
+    void instrument_dynprobes(const std::vector<dynprobe_target>& targets);
 
     // Copy data for forked instrumentation
     void copy_forked_instrumentation(mutatee& other);
@@ -102,12 +104,11 @@ class mutatee {
 
     bool check_exit() { return check_dyninst_exit(process); }
 
-    void begin_callback();
-    void exit_callback(BPatch_thread *thread);
+    void begin_callback(BPatch_thread *thread=NULL);
+    void exit_callback(BPatch_thread *thread, bool exec_p=false);
     void thread_callback(BPatch_thread *thread, bool create_p);
 
-    void find_attached_probes(uint64_t flag,
-                             std::vector<const dynprobe_location *>&probes);
+    std::vector<dynprobe_location> find_attached_probes(uint64_t flag);
 };
 
 #endif // MUTATEE_H
index 93217697e4b76ada486a1cac2147fd3d0bdb1d6c..8c1a32cd7d1fe6fc565546061efdbd07ec726f4e 100644 (file)
@@ -689,7 +689,7 @@ mutator::post_fork_callback(BPatch_thread *parent, BPatch_thread *child)
       m->copy_forked_instrumentation(*mut);
 
       // Trigger any process.begin probes.
-      m->begin_callback();
+      m->begin_callback(child);
     }
 }
 
@@ -719,7 +719,7 @@ mutator::exec_callback(BPatch_thread *thread)
       if (mut->load_stap_dso(module_name))
         {
           if (!targets.empty())
-            mut->instrument_dynprobes(targets, true);
+            mut->instrument_dynprobes(targets);
 
           // Now we map the shared-memory into the target
           if (!module_shmem.empty())
@@ -729,8 +729,11 @@ mutator::exec_callback(BPatch_thread *thread)
               mut->call_function("stp_dyninst_shm_connect", args);
             }
 
+          // Trigger any process.end probes for the pre-exec process.
+          mut->exit_callback(thread, true);
+
           // Trigger any process.begin probes.
-          mut->begin_callback();
+          mut->begin_callback(thread);
         }
 #endif
     }
@@ -747,21 +750,8 @@ mutator::exit_callback(BPatch_thread *thread,
   // 'thread' is the thread that requested the exit, not necessarily the
   // main thread.
   BPatch_process* process = thread->getProcess();
-
-  if (utrace_enter_fn == NULL)
-    {
-      try
-        {
-         set_dlsym(utrace_enter_fn, module, "enter_dyninst_utrace_probe");
-       }
-      catch (runtime_error& e)
-        {
-         staperror() << e.what() << endl;
-         return;
-       }
-    }
-
-  staplog(1) << "exit callback, pid = " << process->getPid() << endl;
+  int pid = process->getPid();
+  staplog(1) << "exit callback, pid = " << pid << endl;
 
   boost::shared_ptr<mutatee> mut = find_mutatee(process);
   if (mut)
@@ -772,14 +762,31 @@ mutator::exit_callback(BPatch_thread *thread,
       // exiting before we can). So, we'll call the probe(s) locally
       // here. This works, but the context is wrong (the mutator, not
       // the mutatee).
-      vector<const dynprobe_location *> exit_probes;
-      mut->find_attached_probes(STAPDYN_PROBE_FLAG_PROC_END, exit_probes);
-      for (size_t p = 0; p < exit_probes.size(); ++p)
+      const vector<dynprobe_location>& proc_end_probes =
+       mut->find_attached_probes(STAPDYN_PROBE_FLAG_PROC_END);
+      if (proc_end_probes.empty())
+       return;
+
+      if (utrace_enter_fn == NULL)
+       try
+         {
+           set_dlsym(utrace_enter_fn, module, "enter_dyninst_utrace_probe");
+         }
+       catch (runtime_error& e)
+         {
+           staperror() << e.what() << endl;
+           return;
+         }
+
+      staplog(2) << "firing " << proc_end_probes.size()
+                << " process.end probes in the mutator for pid "
+                << pid << endl;
+      for (size_t p = 0; p < proc_end_probes.size(); ++p)
         {
-         const dynprobe_location *probe = exit_probes[p];
-         staplog(2) << "found end proc probe in pid " << process->getPid()
-                    << ", index = " << probe->index << endl;
-         int rc = utrace_enter_fn(probe->index, NULL);
+         const dynprobe_location& probe = proc_end_probes[p];
+         staplog(3) << "calling utrace function in the mutator for pid "
+                    << pid << ", probe index " << probe.index << endl;
+         int rc = utrace_enter_fn(probe.index, NULL);
          if (rc)
            stapwarn() << "enter_dyninst_utrace_probe returned "
                       << rc << endl;
This page took 0.042384 seconds and 5 git commands to generate.