debuggerd: a few generic improvements

This one makes dump_memory reasonably architecture-agnostic so it is
possible to share the code between architectures.

It also includes a few small improvements in tombstone.cpp.

Change-Id: Ib8a9599bfa420b41e80207988e87aee1b9d79541
Signed-off-by: Kévin PETIT <kevin.petit@arm.com>
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 3fba6db..fd2f69b 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -38,65 +38,6 @@
 #endif
 #endif
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
-  char code_buffer[64];       // actual 8+1+((8+1)*4) + 1 == 45
-  char ascii_buffer[32];      // actual 16 + 1 == 17
-  uintptr_t p, end;
-
-  p = addr & ~3;
-  p -= 32;
-  if (p > addr) {
-    // catch underflow
-    p = 0;
-  }
-  // Dump more memory content for the crashing thread.
-  end = p + 256;
-  // catch overflow; 'end - p' has to be multiples of 16
-  while (end < p)
-    end -= 16;
-
-  // Dump the code around PC as:
-  //  addr     contents                             ascii
-  //  00008d34 ef000000 e8bd0090 e1b00000 512fff1e  ............../Q
-  //  00008d44 ea00b1f9 e92d0090 e3a070fc ef000000  ......-..p......
-  while (p < end) {
-    char* asc_out = ascii_buffer;
-
-    sprintf(code_buffer, "%08x ", p);
-
-    int i;
-    for (i = 0; i < 4; i++) {
-      // If we see (data == -1 && errno != 0), we know that the ptrace
-      // call failed, probably because we're dumping memory in an
-      // unmapped or inaccessible page.  I don't know if there's
-      // value in making that explicit in the output -- it likely
-      // just complicates parsing and clarifies nothing for the
-      // enlightened reader.
-      long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL);
-      sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
-      // Enable the following code blob to dump ASCII values
-#if 0
-      int j;
-      for (j = 0; j < 4; j++) {
-        // Our isprint() allows high-ASCII characters that display
-        // differently (often badly) in different viewers, so we
-        // just use a simpler test.
-        char val = (data >> (j*8)) & 0xff;
-        if (val >= 0x20 && val < 0x7f) {
-          *asc_out++ = val;
-        } else {
-          *asc_out++ = '.';
-        }
-      }
-#endif
-      p += 4;
-    }
-    *asc_out = '\0';
-    _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
-  }
-}
-
 // If configured to do so, dump memory around *all* registers
 // for the crashing thread.
 void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index d1a7f2d..7b4e29e 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -34,61 +34,6 @@
 
 #define R(x) (static_cast<unsigned int>(x))
 
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
-  char code_buffer[64];       // actual 8+1+((8+1)*4) + 1 == 45
-  char ascii_buffer[32];      // actual 16 + 1 == 17
-  uintptr_t p, end;
-
-  p = addr & ~3;
-  p -= 32;
-  if (p > addr) {
-    // catch underflow
-    p = 0;
-  }
-  end = p + 80;
-  // catch overflow; 'end - p' has to be multiples of 16
-  while (end < p)
-    end -= 16;
-
-  // Dump the code around PC as:
-  //  addr     contents                             ascii
-  //  00008d34 ef000000 e8bd0090 e1b00000 512fff1e  ............../Q
-  //  00008d44 ea00b1f9 e92d0090 e3a070fc ef000000  ......-..p......
-  while (p < end) {
-    char* asc_out = ascii_buffer;
-
-    sprintf(code_buffer, "%08x ", p);
-
-    int i;
-    for (i = 0; i < 4; i++) {
-      // If we see (data == -1 && errno != 0), we know that the ptrace
-      // call failed, probably because we're dumping memory in an
-      // unmapped or inaccessible page.  I don't know if there's
-      // value in making that explicit in the output -- it likely
-      // just complicates parsing and clarifies nothing for the
-      // enlightened reader.
-      long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
-      sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
-      int j;
-      for (j = 0; j < 4; j++) {
-        // Our isprint() allows high-ASCII characters that display
-        // differently (often badly) in different viewers, so we
-        // just use a simpler test.
-        char val = (data >> (j*8)) & 0xff;
-        if (val >= 0x20 && val < 0x7f) {
-          *asc_out++ = val;
-        } else {
-          *asc_out++ = '.';
-        }
-      }
-      p += 4;
-    }
-    *asc_out = '\0';
-    _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
-  }
-}
-
 // If configured to do so, dump memory around *all* registers
 // for the crashing thread.
 void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 11e9af5..7bda5c5 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
 #include <sys/ptrace.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
-#include <inttypes.h>
+#include <sys/un.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -36,9 +38,6 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <sys/socket.h>
-#include <linux/un.h>
-
 #include <selinux/android.h>
 
 #include <UniquePtr.h>
@@ -51,6 +50,7 @@
 
 #define MAX_TOMBSTONES  10
 #define TOMBSTONE_DIR   "/data/tombstones"
+#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
 
 // Must match the path defined in NativeCrashListener.java
 #define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
@@ -60,7 +60,6 @@
   typeof(y) __dummy2;     \
   (void)(&__dummy1 == &__dummy2); }
 
-
 static bool signal_has_address(int sig) {
   switch (sig) {
     case SIGILL:
@@ -675,7 +674,7 @@
   char path[128];
   int oldest = 0;
   for (int i = 0; i < MAX_TOMBSTONES; i++) {
-    snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
+    snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
 
     if (!stat(path, &sb)) {
       if (sb.st_mtime < mtime) {
@@ -696,7 +695,7 @@
   }
 
   // we didn't find an available file, so we clobber the oldest one
-  snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
+  snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
   *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
   if (*fd < 0) {
     LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
@@ -739,8 +738,13 @@
 char* engrave_tombstone(
     pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads,
     bool quiet, bool* detach_failed, int* total_sleep_time_usec) {
-  mkdir(TOMBSTONE_DIR, 0755);
-  chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
+  if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
+      LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+  }
+
+  if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
+      LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+  }
 
   if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) {
     *detach_failed = false;
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 35f061e..100324a 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -127,3 +127,77 @@
     *total_sleep_time_usec += sleep_time_usec;
   }
 }
+
+#if defined (__mips__)
+#define DUMP_MEMORY_AS_ASCII 1
+#else
+#define DUMP_MEMORY_AS_ASCII 0
+#endif
+
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+    char code_buffer[64];
+    char ascii_buffer[32];
+    uintptr_t p, end;
+
+    p = addr & ~(sizeof(long) - 1);
+    /* Dump 32 bytes before addr */
+    p -= 32;
+    if (p > addr) {
+        /* catch underflow */
+        p = 0;
+    }
+    /* Dump 256 bytes */
+    end = p + 256;
+    /* catch overflow; 'end - p' has to be multiples of 16 */
+    while (end < p) {
+        end -= 16;
+    }
+
+    /* Dump the code around PC as:
+     *  addr             contents                           ascii
+     *  0000000000008d34 ef000000e8bd0090 e1b00000512fff1e  ............../Q
+     *  0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000  ......-..p......
+     * On 32-bit machines, there are still 16 bytes per line but addresses and
+     * words are of course presented differently.
+     */
+    while (p < end) {
+        char* asc_out = ascii_buffer;
+
+        int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
+
+        for (size_t i = 0; i < 16/sizeof(long); i++) {
+            long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
+            if (data == -1 && errno != 0) {
+                // ptrace failed, probably because we're dumping memory in an
+                // unmapped or inaccessible page.
+#ifdef __LP64__
+                len += sprintf(code_buffer + len, "---------------- ");
+#else
+                len += sprintf(code_buffer + len, "-------- ");
+#endif
+            } else {
+                len += sprintf(code_buffer + len, "%" PRIPTR " ",
+                               static_cast<uintptr_t>(data));
+            }
+
+#if DUMP_MEMORY_AS_ASCII
+            for (size_t j = 0; j < sizeof(long); j++) {
+                /*
+                 * Our isprint() allows high-ASCII characters that display
+                 * differently (often badly) in different viewers, so we
+                 * just use a simpler test.
+                 */
+                char val = (data >> (j*8)) & 0xff;
+                if (val >= 0x20 && val < 0x7f) {
+                    *asc_out++ = val;
+                } else {
+                    *asc_out++ = '.';
+                }
+            }
+#endif
+            p += sizeof(long);
+        }
+        *asc_out = '\0';
+        _LOG(log, scope_flags, "    %s %s\n", code_buffer, ascii_buffer);
+    }
+}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 1f006ed..232b7bc 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -18,8 +18,9 @@
 #ifndef _DEBUGGERD_UTILITY_H
 #define _DEBUGGERD_UTILITY_H
 
-#include <stddef.h>
+#include <inttypes.h>
 #include <stdbool.h>
+#include <stddef.h>
 
 typedef struct {
     /* tombstone file descriptor */
@@ -60,7 +61,17 @@
 #define XLOG2(fmt...) do {} while(0)
 #endif
 
+#if __LP64__
+#define PRIPTR "016" PRIxPTR
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIxPTR
+typedef uint32_t word_t;
+#endif
+
 int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
 void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
 
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags);
+
 #endif // _DEBUGGERD_UTILITY_H