]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Handle T-stopped detach for old kernels
authorJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 2 Dec 2013 20:52:26 +0000 (21:52 +0100)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Mon, 2 Dec 2013 20:52:26 +0000 (21:52 +0100)
Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>
tests/ChangeLog
tests/backtrace.c

index af0e1c3d5c6ecf8028cafb214ab7d275eee56602..ba6dab241c56c199871055bdcbad269cb06640f6 100644 (file)
@@ -1,3 +1,10 @@
+2013-12-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+       Handle T-stopped detach for old kernels.
+       * backtrace.c: Include sys/syscall.h.
+       (linux_proc_pid_is_stopped): New function.
+       (ptrace_detach_stopped): Handle old kernels.
+
 2013-12-02  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * Makefile.am (check_PROGRAMS): Add backtrace, backtrace-child,
index 06d3878211c3745b48c69d3bb8ee776a6174ec91..68ad95d616fea31e148b006fe41fa7cb77c6dd0d 100644 (file)
@@ -36,6 +36,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <argp.h>
+#include <sys/syscall.h>
 #include ELFUTILS_HEADER(dwfl)
 
 static int
@@ -253,13 +254,43 @@ prepare_thread (pid_t pid2 __attribute__ ((unused)),
 #include <unistd.h>
 #define tgkill(pid, tid, sig) syscall (__NR_tgkill, (pid), (tid), (sig))
 
+static bool
+linux_proc_pid_is_stopped (pid_t pid)
+{
+  char buffer[64];
+  FILE *procfile;
+  bool retval, have_state;
+
+  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
+  procfile = fopen (buffer, "r");
+  if (procfile == NULL)
+    return false;
+
+  have_state = false;
+  while (fgets (buffer, sizeof (buffer), procfile) != NULL)
+    if (strncmp (buffer, "State:", 6) == 0)
+      {
+       have_state = true;
+       break;
+      }
+  retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
+  fclose (procfile);
+  return retval;
+}
+
 static void
 ptrace_detach_stopped (pid_t pid)
 {
+  syscall (__NR_tkill, pid, SIGSTOP);
   errno = 0;
   long l = ptrace (PTRACE_DETACH, pid, NULL, (void *) (intptr_t) SIGSTOP);
   assert_perror (errno);
   assert (l == 0);
+  // Wait till the SIGSTOP settles down.
+  int i;
+  for (i = 0; i < 100000; i++)
+    if (linux_proc_pid_is_stopped (pid))
+      break;
 }
 
 static void