This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libdwfl: linux-pid-attach.c don't detach threads already attached.


While working on using the pid unwinder in ltrace I noticed it didn't
really play well with a process that might already be ptrace attached
to the thread under inspection. This patch solves that by detecting the
thread already is ptrace attached and making sure we don't detach it
ourselves in that case.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 libdwfl/ChangeLog          |   10 ++++++++++
 libdwfl/linux-pid-attach.c |   37 +++++++++++++++++++++++++++++--------
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 74d11e0..a215bef 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2013-12-21  Mark Wielaard  <mjw@redhat.com>
+
+	* linux-pid-attach.c (struct pid_arg): New field should_detach.
+	(ptrace_attach): New argument should_detachp. Set to false when
+	the process is already ptrace attached to this tid. Set to true
+	otherwise.
+	(pid_set_initial_registers): Call ptrace_attach with extra
+	argument pid_arg->should_detach.
+	(pid_thread_detach): Check pid_arg->should_detach before detaching.
+
 2013-12-20  Mark Wielaard  <mjw@redhat.com>
 
 	* dwfl_frame.c (one_arg): New struct.
diff --git a/libdwfl/linux-pid-attach.c b/libdwfl/linux-pid-attach.c
index 13e60f8..d9d26d0 100644
--- a/libdwfl/linux-pid-attach.c
+++ b/libdwfl/linux-pid-attach.c
@@ -44,6 +44,8 @@ struct pid_arg
   pid_t tid_attached;
   /* Valid only if TID_ATTACHED is not zero.  */
   bool tid_was_stopped;
+  /* If true and TID_ATTACHED is not zero we should detach.  */
+  bool should_detach;
 };
 
 static bool
@@ -71,13 +73,27 @@ linux_proc_pid_is_stopped (pid_t pid)
 }
 
 static bool
-ptrace_attach (pid_t tid, bool *tid_was_stoppedp)
+ptrace_attach (pid_t tid, bool *tid_was_stoppedp, bool *should_detachp)
 {
   if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
     {
+      if (errno == EPERM)
+	{
+	  // The process might already be attached and stopped this thread.
+	  // Check whether it is and if so, do not stop and detach later.
+	  long data;
+	  if (ptrace (PTRACE_GETEVENTMSG, tid, NULL, &data) == 0)
+	    {
+	      *should_detachp = false;
+	      return true;
+	    }
+	  // No luck, we really failed. Make sure we return the right error.
+	  errno = EPERM;
+	}
       __libdwfl_seterrno (DWFL_E_ERRNO);
       return false;
     }
+  *should_detachp = true;
   *tid_was_stoppedp = linux_proc_pid_is_stopped (tid);
   if (*tid_was_stoppedp)
     {
@@ -236,7 +252,8 @@ pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
   struct pid_arg *pid_arg = thread_arg;
   assert (pid_arg->tid_attached == 0);
   pid_t tid = INTUSE(dwfl_thread_tid) (thread);
-  if (! ptrace_attach (tid, &pid_arg->tid_was_stopped))
+  if (! ptrace_attach (tid, &pid_arg->tid_was_stopped,
+		       &pid_arg->should_detach))
     return false;
   pid_arg->tid_attached = tid;
   Dwfl_Process *process = thread->process;
@@ -260,12 +277,16 @@ pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
   pid_t tid = INTUSE(dwfl_thread_tid) (thread);
   assert (pid_arg->tid_attached == tid);
   pid_arg->tid_attached = 0;
-  /* This handling is needed only on older Linux kernels such as
-     2.6.32-358.23.2.el6.ppc64.  Later kernels such as 3.11.7-200.fc19.x86_64
-     remember the T (stopped) state themselves and no longer need to pass
-     SIGSTOP during PTRACE_DETACH.  */
-  ptrace (PTRACE_DETACH, tid, NULL,
-	  (void *) (intptr_t) (pid_arg->tid_was_stopped ? SIGSTOP : 0));
+  if (pid_arg->should_detach)
+    {
+      /* This handling is needed only on older Linux kernels such as
+         2.6.32-358.23.2.el6.ppc64.  Later kernels such as
+         3.11.7-200.fc19.x86_64 remember the T (stopped) state
+         themselves and no longer need to pass SIGSTOP during
+         PTRACE_DETACH.  */
+      ptrace (PTRACE_DETACH, tid, NULL,
+	      (void *) (intptr_t) (pid_arg->tid_was_stopped ? SIGSTOP : 0));
+    }
 }
 
 static const Dwfl_Thread_Callbacks pid_thread_callbacks =
-- 
1.7.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]