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/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);
+    }
+}