crash_dump: fork a copy of the target's address space.

Reduce the amount of time that a process remains paused by pausing its
threads, fetching their registers, and then performing unwinding on a
copy of its address space. This also works around a kernel change
that's in 4.9 that prevents ptrace from reading memory of processes
that we don't have immediate permissions to ptrace (even if we
previously ptraced them).

Bug: http://b/62112103
Bug: http://b/63989615
Test: treehugger
Change-Id: I7b9cc5dd8f54a354bc61f1bda0d2b7a8a55733c4
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 1b74652..247d806 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -21,6 +21,8 @@
 #include <errno.h>
 #include <signal.h>
 #include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
 #include <sys/ptrace.h>
 #include <sys/uio.h>
 #include <sys/wait.h>
@@ -34,7 +36,9 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <backtrace/Backtrace.h>
+#include <debuggerd/handler.h>
 #include <log/log.h>
+#include <unwindstack/Memory.h>
 
 using android::base::unique_fd;
 
@@ -117,34 +121,10 @@
   }
 }
 
-bool wait_for_signal(pid_t tid, siginfo_t* siginfo) {
-  while (true) {
-    int status;
-    pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL));
-    if (n == -1) {
-      ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
-      return false;
-    } else if (n == tid) {
-      if (WIFSTOPPED(status)) {
-        if (ptrace(PTRACE_GETSIGINFO, tid, nullptr, siginfo) != 0) {
-          ALOGE("PTRACE_GETSIGINFO failed: %s", strerror(errno));
-          return false;
-        }
-        return true;
-      } else {
-        ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
-        // This is the only circumstance under which we can allow a detach
-        // to fail with ESRCH, which indicates the tid has exited.
-        return false;
-      }
-    }
-  }
-}
-
 #define MEMORY_BYTES_TO_DUMP 256
 #define MEMORY_BYTES_PER_LINE 16
 
-void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
+void dump_memory(log_t* log, unwindstack::Memory* memory, uintptr_t addr, const char* fmt, ...) {
   std::string log_msg;
   va_list ap;
   va_start(ap, fmt);
@@ -172,7 +152,7 @@
   // Dump 256 bytes
   uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
   memset(data, 0, MEMORY_BYTES_TO_DUMP);
-  size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
+  size_t bytes = memory->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
   if (bytes % sizeof(uintptr_t) != 0) {
     // This should never happen, but just in case.
     ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
@@ -199,8 +179,8 @@
     // into a readable map. Only requires one extra read because a map has
     // to contain at least one page, and the total number of bytes to dump
     // is smaller than a page.
-    size_t bytes2 = backtrace->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
-                                    sizeof(data) - bytes - start);
+    size_t bytes2 = memory->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+                                 sizeof(data) - bytes - start);
     bytes += bytes2;
     if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
       // This should never happen, but we'll try and continue any way.
@@ -264,3 +244,169 @@
   }
   strcpy(buf, default_value);
 }
+
+void drop_capabilities() {
+  __user_cap_header_struct capheader;
+  memset(&capheader, 0, sizeof(capheader));
+  capheader.version = _LINUX_CAPABILITY_VERSION_3;
+  capheader.pid = 0;
+
+  __user_cap_data_struct capdata[2];
+  memset(&capdata, 0, sizeof(capdata));
+
+  if (capset(&capheader, &capdata[0]) == -1) {
+    PLOG(FATAL) << "failed to drop capabilities";
+  }
+
+  if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
+    PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS";
+  }
+}
+
+bool signal_has_si_addr(int si_signo, int si_code) {
+  // Manually sent signals won't have si_addr.
+  if (si_code == SI_USER || si_code == SI_QUEUE || si_code == SI_TKILL) {
+    return false;
+  }
+
+  switch (si_signo) {
+    case SIGBUS:
+    case SIGFPE:
+    case SIGILL:
+    case SIGSEGV:
+    case SIGTRAP:
+      return true;
+    default:
+      return false;
+  }
+}
+
+const char* get_signame(int sig) {
+  switch (sig) {
+    case SIGABRT: return "SIGABRT";
+    case SIGBUS: return "SIGBUS";
+    case SIGFPE: return "SIGFPE";
+    case SIGILL: return "SIGILL";
+    case SIGSEGV: return "SIGSEGV";
+#if defined(SIGSTKFLT)
+    case SIGSTKFLT: return "SIGSTKFLT";
+#endif
+    case SIGSTOP: return "SIGSTOP";
+    case SIGSYS: return "SIGSYS";
+    case SIGTRAP: return "SIGTRAP";
+    case DEBUGGER_SIGNAL: return "<debuggerd signal>";
+    default: return "?";
+  }
+}
+
+const char* get_sigcode(int signo, int code) {
+  // Try the signal-specific codes...
+  switch (signo) {
+    case SIGILL:
+      switch (code) {
+        case ILL_ILLOPC: return "ILL_ILLOPC";
+        case ILL_ILLOPN: return "ILL_ILLOPN";
+        case ILL_ILLADR: return "ILL_ILLADR";
+        case ILL_ILLTRP: return "ILL_ILLTRP";
+        case ILL_PRVOPC: return "ILL_PRVOPC";
+        case ILL_PRVREG: return "ILL_PRVREG";
+        case ILL_COPROC: return "ILL_COPROC";
+        case ILL_BADSTK: return "ILL_BADSTK";
+      }
+      static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
+      break;
+    case SIGBUS:
+      switch (code) {
+        case BUS_ADRALN: return "BUS_ADRALN";
+        case BUS_ADRERR: return "BUS_ADRERR";
+        case BUS_OBJERR: return "BUS_OBJERR";
+        case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
+        case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
+      }
+      static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
+      break;
+    case SIGFPE:
+      switch (code) {
+        case FPE_INTDIV: return "FPE_INTDIV";
+        case FPE_INTOVF: return "FPE_INTOVF";
+        case FPE_FLTDIV: return "FPE_FLTDIV";
+        case FPE_FLTOVF: return "FPE_FLTOVF";
+        case FPE_FLTUND: return "FPE_FLTUND";
+        case FPE_FLTRES: return "FPE_FLTRES";
+        case FPE_FLTINV: return "FPE_FLTINV";
+        case FPE_FLTSUB: return "FPE_FLTSUB";
+      }
+      static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
+      break;
+    case SIGSEGV:
+      switch (code) {
+        case SEGV_MAPERR: return "SEGV_MAPERR";
+        case SEGV_ACCERR: return "SEGV_ACCERR";
+#if defined(SEGV_BNDERR)
+        case SEGV_BNDERR: return "SEGV_BNDERR";
+#endif
+#if defined(SEGV_PKUERR)
+        case SEGV_PKUERR: return "SEGV_PKUERR";
+#endif
+      }
+#if defined(SEGV_PKUERR)
+      static_assert(NSIGSEGV == SEGV_PKUERR, "missing SEGV_* si_code");
+#elif defined(SEGV_BNDERR)
+      static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
+#else
+      static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
+#endif
+      break;
+#if defined(SYS_SECCOMP) // Our glibc is too old, and we build this for the host too.
+    case SIGSYS:
+      switch (code) {
+        case SYS_SECCOMP: return "SYS_SECCOMP";
+      }
+      static_assert(NSIGSYS == SYS_SECCOMP, "missing SYS_* si_code");
+      break;
+#endif
+    case SIGTRAP:
+      switch (code) {
+        case TRAP_BRKPT: return "TRAP_BRKPT";
+        case TRAP_TRACE: return "TRAP_TRACE";
+        case TRAP_BRANCH: return "TRAP_BRANCH";
+        case TRAP_HWBKPT: return "TRAP_HWBKPT";
+      }
+      if ((code & 0xff) == SIGTRAP) {
+        switch ((code >> 8) & 0xff) {
+          case PTRACE_EVENT_FORK:
+            return "PTRACE_EVENT_FORK";
+          case PTRACE_EVENT_VFORK:
+            return "PTRACE_EVENT_VFORK";
+          case PTRACE_EVENT_CLONE:
+            return "PTRACE_EVENT_CLONE";
+          case PTRACE_EVENT_EXEC:
+            return "PTRACE_EVENT_EXEC";
+          case PTRACE_EVENT_VFORK_DONE:
+            return "PTRACE_EVENT_VFORK_DONE";
+          case PTRACE_EVENT_EXIT:
+            return "PTRACE_EVENT_EXIT";
+          case PTRACE_EVENT_SECCOMP:
+            return "PTRACE_EVENT_SECCOMP";
+          case PTRACE_EVENT_STOP:
+            return "PTRACE_EVENT_STOP";
+        }
+      }
+      static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
+      break;
+  }
+  // Then the other codes...
+  switch (code) {
+    case SI_USER: return "SI_USER";
+    case SI_KERNEL: return "SI_KERNEL";
+    case SI_QUEUE: return "SI_QUEUE";
+    case SI_TIMER: return "SI_TIMER";
+    case SI_MESGQ: return "SI_MESGQ";
+    case SI_ASYNCIO: return "SI_ASYNCIO";
+    case SI_SIGIO: return "SI_SIGIO";
+    case SI_TKILL: return "SI_TKILL";
+    case SI_DETHREAD: return "SI_DETHREAD";
+  }
+  // Then give up...
+  return "?";
+}