crash_dump: print the identity of tracers.

Instead of printing a useless "ptrace attach failed: strerror(EPERM)"
message, print the name and pid of a competing tracer when we fail to
attach because a process is already being ptraced.

Bug: http://b/31531918
Test: debuggerd_test32, debuggerd_test64 on aosp_angler
Test: strace -p `pidof surfaceflinger`; debuggerd -b surfaceflinger
Change-Id: Ifd3f80fe03de30ff38c0e0068560a7b12875f29d
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 4b1e51d..cd1da50 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -79,9 +79,27 @@
   return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0;
 }
 
+static pid_t get_tracer(pid_t tracee) {
+  // Check to see if the thread is being ptraced by another process.
+  android::procinfo::ProcessInfo process_info;
+  if (android::procinfo::GetProcessInfo(tracee, &process_info)) {
+    return process_info.tracer;
+  }
+  return -1;
+}
+
 // Attach to a thread, and verify that it's still a member of the given process
 static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) {
   if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) {
+    if (errno == EPERM) {
+      pid_t tracer = get_tracer(tid);
+      if (tracer != -1) {
+        *error = StringPrintf("failed to attach to thread %d, already traced by %d (%s)", tid,
+                              tracer, get_process_name(tracer).c_str());
+        return false;
+      }
+    }
+
     *error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno));
     return false;
   }
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index b51fc66..dbf81a4 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -16,10 +16,11 @@
 
 #include <err.h>
 #include <fcntl.h>
-#include <unistd.h>
 #include <sys/capability.h>
 #include <sys/prctl.h>
+#include <sys/ptrace.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <chrono>
 #include <regex>
@@ -569,6 +570,40 @@
   ASSERT_BACKTRACE_FRAME(result, "tgkill");
 }
 
+TEST_F(CrasherTest, competing_tracer) {
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    while (true) {
+    }
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+
+  ASSERT_EQ(0, ptrace(PTRACE_SEIZE, crasher_pid, 0, 0));
+  ASSERT_EQ(0, kill(crasher_pid, SIGABRT));
+
+  int status;
+  ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
+  ASSERT_TRUE(WIFSTOPPED(status));
+  ASSERT_EQ(SIGABRT, WSTOPSIG(status));
+
+  ASSERT_EQ(0, ptrace(PTRACE_CONT, crasher_pid, 0, SIGABRT));
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  std::string regex = R"(failed to attach to thread \d+, already traced by )";
+  regex += std::to_string(gettid());
+  regex += R"( \(.+debuggerd_test)";
+  ASSERT_MATCH(result, regex.c_str());
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, crasher_pid, 0, SIGABRT));
+  AssertDeath(SIGABRT);
+}
+
 TEST(crash_dump, zombie) {
   pid_t forkpid = fork();