Improve stack unwinder robustness.

Keep track of whether memory maps are readable.  Use the information
in try_get_word to try to avoid accidentally dereferencing an invalid
pointer within the current process.  (Note that I haven't ever
seen that happen during normal unwinding, but it pays to be
a little more careful.)

Refactored try_get_word a little to make it easier to pass it the
needed state for validation checks by way of a little memory_t struct.

Improved how the memory map for the current process is cached.  This is
important because we need up to date information about readable maps.
Use a 5 second cache expiration.

Improved the PC -> LR fallback logic in the unwinder so we can
eke out an extra frame sometimes.

Fixed a bug reading ELF program headers.  The phnum & phentsize
fields are half-words.  We were incorrectly interpreting
phnum as a whole word.

Used android_atomic_* operations carefully in the unwinder
to prevent possible memory races between the dumper and the dumpee.
This was highly unlikely (or even impossible due to the presence
of other barriers along the way) but the code is clearer now about
its invariants.

Fixed a bug in debuggerd where the pid was being passed to have
its stack dump taken instead of the tid, resulting in short
stacks because ptrace couldn't read the data if pid != tid.
Did a full sweep to ensure that we use pid / tid correctly everywhere.

Ported old code from debuggerd to rewind the program counter back
one instruction so that it points to the branch instruction itself
instead of the return address.

Change-Id: Icc4eb08320052975a4ae7f0f5f0ac9308a2d33d7
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
index 6bed2ae..cf9a5ab 100644
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ b/libcorkscrew/arch-arm/backtrace-arm.c
@@ -120,35 +120,31 @@
     return place + (((int32_t)(prel_offset << 1)) >> 1);
 }
 
-static uintptr_t get_exception_handler(
-        const ptrace_context_t* context, pid_t tid, uintptr_t pc) {
+static uintptr_t get_exception_handler(const memory_t* memory,
+        const map_info_t* map_info_list, uintptr_t pc) {
+    if (!pc) {
+        ALOGV("get_exception_handler: pc is zero, no handler");
+        return 0;
+    }
+
     uintptr_t exidx_start;
     size_t exidx_size;
     const map_info_t* mi;
-    if (tid < 0) {
+    if (memory->tid < 0) {
         mi = NULL;
         exidx_start = find_exidx(pc, &exidx_size);
     } else {
-        mi = find_map_info(context->map_info_list, pc);
+        mi = find_map_info(map_info_list, pc);
         if (mi && mi->data) {
             const map_info_data_t* data = (const map_info_data_t*)mi->data;
             exidx_start = data->exidx_start;
-            exidx_size = data->exidx_size / 8;
+            exidx_size = data->exidx_size;
         } else {
             exidx_start = 0;
             exidx_size = 0;
         }
     }
 
-    // The PC points to the instruction following the branch.
-    // We want to find the exception handler entry that corresponds to the branch itself,
-    // so we offset the PC backwards into the previous instruction.
-    // ARM instructions are 4 bytes, Thumb are 2, so we just subtract two so we either
-    // end up in the middle (ARM) or at the beginning of the instruction (Thumb).
-    if (pc >= 2) {
-        pc -= 2;
-    }
-
     uintptr_t handler = 0;
     if (exidx_start) {
         uint32_t low = 0;
@@ -157,7 +153,7 @@
             uint32_t index = (low + high) / 2;
             uintptr_t entry = exidx_start + index * 8;
             uint32_t entry_prel_pc;
-            if (!try_get_word(tid, entry, &entry_prel_pc)) {
+            if (!try_get_word(memory, entry, &entry_prel_pc)) {
                 break;
             }
             uintptr_t entry_pc = prel_to_absolute(entry, entry_prel_pc);
@@ -168,7 +164,7 @@
             if (index + 1 < exidx_size) {
                 uintptr_t next_entry = entry + 8;
                 uint32_t next_entry_prel_pc;
-                if (!try_get_word(tid, next_entry, &next_entry_prel_pc)) {
+                if (!try_get_word(memory, next_entry, &next_entry_prel_pc)) {
                     break;
                 }
                 uintptr_t next_entry_pc = prel_to_absolute(next_entry, next_entry_prel_pc);
@@ -180,7 +176,7 @@
 
             uintptr_t entry_handler_ptr = entry + 4;
             uint32_t entry_handler;
-            if (!try_get_word(tid, entry_handler_ptr, &entry_handler)) {
+            if (!try_get_word(memory, entry_handler_ptr, &entry_handler)) {
                 break;
             }
             if (entry_handler & (1L << 31)) {
@@ -191,10 +187,15 @@
             break;
         }
     }
-    ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, "
-            "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x",
-            pc, mi ? mi->name : "<unknown>", mi ? mi->start : 0,
-            exidx_start, exidx_size, handler);
+    if (mi) {
+        ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, "
+                "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x",
+                pc, mi->name, mi->start, exidx_start, exidx_size, handler);
+    } else {
+        ALOGV("get_exception_handler: pc=0x%08x, "
+                "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x",
+                pc, exidx_start, exidx_size, handler);
+    }
     return handler;
 }
 
@@ -203,11 +204,11 @@
     uint32_t word;
 } byte_stream_t;
 
-static bool try_next_byte(pid_t tid, byte_stream_t* stream, uint8_t* out_value) {
+static bool try_next_byte(const memory_t* memory, byte_stream_t* stream, uint8_t* out_value) {
     uint8_t result;
     switch (stream->ptr & 3) {
     case 0:
-        if (!try_get_word(tid, stream->ptr, &stream->word)) {
+        if (!try_get_word(memory, stream->ptr, &stream->word)) {
             *out_value = 0;
             return false;
         }
@@ -237,13 +238,13 @@
     state->gregs[reg] = value;
 }
 
-static bool try_pop_registers(pid_t tid, unwind_state_t* state, uint32_t mask) {
+static bool try_pop_registers(const memory_t* memory, unwind_state_t* state, uint32_t mask) {
     uint32_t sp = state->gregs[R_SP];
     bool sp_updated = false;
     for (int i = 0; i < 16; i++) {
         if (mask & (1 << i)) {
             uint32_t value;
-            if (!try_get_word(tid, sp, &value)) {
+            if (!try_get_word(memory, sp, &value)) {
                 return false;
             }
             if (i == R_SP) {
@@ -272,8 +273,8 @@
  * virtual register state (including the stack pointer) such that
  * the call frame is unwound and the PC register points to the call site.
  */
-static bool execute_personality_routine(pid_t tid, unwind_state_t* state,
-        byte_stream_t* stream, int pr_index) {
+static bool execute_personality_routine(const memory_t* memory,
+        unwind_state_t* state, byte_stream_t* stream, int pr_index) {
     size_t size;
     switch (pr_index) {
     case 0: // Personality routine #0, short frame, descriptors have 16-bit scope.
@@ -282,7 +283,7 @@
     case 1: // Personality routine #1, long frame, descriptors have 16-bit scope.
     case 2: { // Personality routine #2, long frame, descriptors have 32-bit scope.
         uint8_t size_byte;
-        if (!try_next_byte(tid, stream, &size_byte)) {
+        if (!try_next_byte(memory, stream, &size_byte)) {
             return false;
         }
         size = (uint32_t)size_byte * sizeof(uint32_t) + 2;
@@ -295,7 +296,7 @@
     bool pc_was_set = false;
     while (size--) {
         uint8_t op;
-        if (!try_next_byte(tid, stream, &op)) {
+        if (!try_next_byte(memory, stream, &op)) {
             return false;
         }
         if ((op & 0xc0) == 0x00) {
@@ -306,13 +307,13 @@
             set_reg(state, R_SP, state->gregs[R_SP] - ((op & 0x3f) << 2) - 4);
         } else if ((op & 0xf0) == 0x80) {
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             uint32_t mask = (((uint32_t)op & 0x0f) << 12) | ((uint32_t)op2 << 4);
             if (mask) {
                 // "Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}"
-                if (!try_pop_registers(tid, state, mask)) {
+                if (!try_pop_registers(memory, state, mask)) {
                     return false;
                 }
                 if (mask & (1 << R_PC)) {
@@ -334,13 +335,13 @@
         } else if ((op & 0xf8) == 0xa0) {
             // "Pop r4-r[4+nnn]"
             uint32_t mask = (0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0;
-            if (!try_pop_registers(tid, state, mask)) {
+            if (!try_pop_registers(memory, state, mask)) {
                 return false;
             }
         } else if ((op & 0xf8) == 0xa8) {
             // "Pop r4-r[4+nnn], r14"
             uint32_t mask = ((0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0) | 0x4000;
-            if (!try_pop_registers(tid, state, mask)) {
+            if (!try_pop_registers(memory, state, mask)) {
                 return false;
             }
         } else if (op == 0xb0) {
@@ -348,12 +349,12 @@
             break;
         } else if (op == 0xb1) {
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
                 // "Pop integer registers under mask {r3, r2, r1, r0}"
-                if (!try_pop_registers(tid, state, op2)) {
+                if (!try_pop_registers(memory, state, op2)) {
                     return false;
                 }
             } else {
@@ -366,7 +367,7 @@
             uint32_t shift = 0;
             uint8_t op2;
             do {
-                if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+                if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                     return false;
                 }
                 value |= (op2 & 0x7f) << shift;
@@ -376,7 +377,7 @@
         } else if (op == 0xb3) {
             // "Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDX"
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 12);
@@ -389,13 +390,13 @@
         } else if (op == 0xc6) {
             // "Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]"
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
         } else if (op == 0xc7) {
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
@@ -409,14 +410,14 @@
             // "Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc]
             // saved (as if) by FSTMFD"
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
         } else if (op == 0xc9) {
             // "Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDD"
             uint8_t op2;
-            if (!(size--) || !try_next_byte(tid, stream, &op2)) {
+            if (!(size--) || !try_next_byte(memory, stream, &op2)) {
                 return false;
             }
             set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
@@ -434,52 +435,86 @@
     return true;
 }
 
-static ssize_t unwind_backtrace_common(pid_t tid, const ptrace_context_t* context,
+static bool try_get_half_word(const memory_t* memory, uint32_t pc, uint16_t* out_value) {
+    uint32_t word;
+    if (try_get_word(memory, pc & ~2, &word)) {
+        *out_value = pc & 2 ? word >> 16 : word & 0xffff;
+        return true;
+    }
+    return false;
+}
+
+uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
+    if (pc & 1) {
+        /* Thumb mode - need to check whether the bl(x) has long offset or not.
+         * Examples:
+         *
+         * arm blx in the middle of thumb:
+         * 187ae:       2300            movs    r3, #0
+         * 187b0:       f7fe ee1c       blx     173ec
+         * 187b4:       2c00            cmp     r4, #0
+         *
+         * arm bl in the middle of thumb:
+         * 187d8:       1c20            adds    r0, r4, #0
+         * 187da:       f136 fd15       bl      14f208
+         * 187de:       2800            cmp     r0, #0
+         *
+         * pure thumb:
+         * 18894:       189b            adds    r3, r3, r2
+         * 18896:       4798            blx     r3
+         * 18898:       b001            add     sp, #4
+         */
+        pc &= ~1;
+        uint16_t prev1, prev2;
+        if (try_get_half_word(memory, pc - 4, &prev1)
+            && ((prev1 & 0xf000) == 0xf000)
+            && try_get_half_word(memory, pc - 2, &prev2)
+            && ((prev2 & 0xe000) == 0xe000)) {
+            pc -= 4; // long offset
+        } else {
+            pc -= 2;
+        }
+    } else {
+        /* ARM mode, all instructions are 32bit.  Yay! */
+        pc -= 4;
+    }
+    return pc;
+}
+
+static ssize_t unwind_backtrace_common(const memory_t* memory,
+        const map_info_t* map_info_list,
         unwind_state_t* state, backtrace_frame_t* backtrace,
         size_t ignore_depth, size_t max_depth) {
     size_t ignored_frames = 0;
     size_t returned_frames = 0;
 
-    uintptr_t handler = get_exception_handler(context, tid, state->gregs[R_PC]);
-    if (!handler) {
-        // If there is no handler for the PC, the program may have branched to
-        // an invalid address.  Check whether we have a handler for the LR
-        // where we came from and use that instead.
-        backtrace_frame_t* frame = add_backtrace_entry(state->gregs[R_PC], backtrace,
-                ignore_depth, max_depth, &ignored_frames, &returned_frames);
+    for (size_t index = 0; returned_frames < max_depth; index++) {
+        uintptr_t pc = index ? rewind_pc_arch(memory, state->gregs[R_PC])
+                : state->gregs[R_PC];
+        backtrace_frame_t* frame = add_backtrace_entry(pc,
+                backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
         if (frame) {
             frame->stack_top = state->gregs[R_SP];
         }
 
-        handler = get_exception_handler(context, tid, state->gregs[R_LR]);
+        uintptr_t handler = get_exception_handler(memory, map_info_list, pc);
         if (!handler) {
-            // We don't have a handler here either.  Unwinding will not be possible.
-            // Return the PC and LR (if it looks sane) and call it good.
-            if (state->gregs[R_LR] && state->gregs[R_LR] != state->gregs[R_PC]) {
-                // Don't return the SP for this second frame because we don't
-                // know how big the first one is so we don't know where this
-                // one starts.
-                add_backtrace_entry(state->gregs[R_LR], backtrace,
-                        ignore_depth, max_depth, &ignored_frames, &returned_frames);
+            // If there is no handler for the PC and this is the first frame,
+            // then the program may have branched to an invalid address.
+            // Try starting from the LR instead, otherwise stop unwinding.
+            if (index == 0 && state->gregs[R_LR]
+                    && state->gregs[R_LR] != state->gregs[R_PC]) {
+                set_reg(state, R_PC, state->gregs[R_LR]);
+                continue;
+            } else {
+                break;
             }
-            return returned_frames;
-        }
-
-        // Ok, continue from the LR.
-        set_reg(state, R_PC, state->gregs[R_LR]);
-    }
-
-    while (handler && returned_frames < max_depth) {
-        backtrace_frame_t* frame = add_backtrace_entry(state->gregs[R_PC], backtrace,
-                ignore_depth, max_depth, &ignored_frames, &returned_frames);
-        if (frame) {
-            frame->stack_top = state->gregs[R_SP];
         }
 
         byte_stream_t stream;
         stream.ptr = handler;
         uint8_t pr;
-        if (!try_next_byte(tid, &stream, &pr)) {
+        if (!try_next_byte(memory, &stream, &pr)) {
             break;
         }
         if ((pr & 0xf0) != 0x80) {
@@ -490,19 +525,33 @@
 
         // The first byte indicates the personality routine to execute.
         // Following bytes provide instructions to the personality routine.
-        if (!execute_personality_routine(tid, state, &stream, pr & 0x0f)) {
+        if (!execute_personality_routine(memory, state, &stream, pr & 0x0f)) {
             break;
         }
         if (frame && state->gregs[R_SP] > frame->stack_top) {
             frame->stack_size = state->gregs[R_SP] - frame->stack_top;
         }
+        if (!state->gregs[R_PC]) {
+            break;
+        }
+    }
 
-        handler = get_exception_handler(context, tid, state->gregs[R_PC]);
+    // Ran out of frames that we could unwind using handlers.
+    // Add a final entry for the LR if it looks sane and call it good.
+    if (returned_frames < max_depth
+            && state->gregs[R_LR]
+            && state->gregs[R_LR] != state->gregs[R_PC]
+            && is_executable_map(map_info_list, state->gregs[R_LR])) {
+        // We don't know where the stack for this extra frame starts so we
+        // don't return any stack information for it.
+        add_backtrace_entry(rewind_pc_arch(memory, state->gregs[R_LR]),
+                backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
     }
     return returned_frames;
 }
 
 ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
+        const map_info_t* map_info_list,
         backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
     const ucontext_t* uc = (const ucontext_t*)sigcontext;
 
@@ -511,7 +560,10 @@
         state.gregs[i] = uc->uc_mcontext.gregs[i];
     }
 
-    return unwind_backtrace_common(-1, NULL, &state, backtrace, ignore_depth, max_depth);
+    memory_t memory;
+    init_memory(&memory, map_info_list);
+    return unwind_backtrace_common(&memory, map_info_list, &state,
+            backtrace, ignore_depth, max_depth);
 }
 
 ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
@@ -526,5 +578,8 @@
         state.gregs[i] = regs.uregs[i];
     }
 
-    return unwind_backtrace_common(tid, context, &state, backtrace, ignore_depth, max_depth);
+    memory_t memory;
+    init_memory_ptrace(&memory, tid);
+    return unwind_backtrace_common(&memory, context->map_info_list, &state,
+            backtrace, ignore_depth, max_depth);
 }
diff --git a/libcorkscrew/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c
index fd15505..868230c 100644
--- a/libcorkscrew/arch-arm/ptrace-arm.c
+++ b/libcorkscrew/arch-arm/ptrace-arm.c
@@ -29,26 +29,31 @@
 static void load_exidx_header(pid_t pid, map_info_t* mi,
         uintptr_t* out_exidx_start, size_t* out_exidx_size) {
     uint32_t elf_phoff;
-    uint32_t elf_phnum;
-    if (try_get_word(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
-            && try_get_word(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum), &elf_phnum)) {
+    uint32_t elf_phentsize_phnum;
+    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
+            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
+                    &elf_phentsize_phnum)) {
+        uint32_t elf_phentsize = elf_phentsize_phnum >> 16;
+        uint32_t elf_phnum = elf_phentsize_phnum & 0xffff;
         for (uint32_t i = 0; i < elf_phnum; i++) {
-            uintptr_t elf_phdr = mi->start + elf_phoff + i * sizeof(Elf32_Phdr);
+            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
             uint32_t elf_phdr_type;
-            if (!try_get_word(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
+            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
                 break;
             }
             if (elf_phdr_type == PT_ARM_EXIDX) {
                 uint32_t elf_phdr_offset;
                 uint32_t elf_phdr_filesz;
-                if (!try_get_word(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
+                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
                         &elf_phdr_offset)
-                        || !try_get_word(pid, elf_phdr + offsetof(Elf32_Phdr, p_filesz),
+                        || !try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_filesz),
                                 &elf_phdr_filesz)) {
                     break;
                 }
                 *out_exidx_start = mi->start + elf_phdr_offset;
-                *out_exidx_size = elf_phdr_filesz;
+                *out_exidx_size = elf_phdr_filesz / 8;
+                ALOGV("Parsed EXIDX header info for %s: start=0x%08x, size=%d", mi->name,
+                        *out_exidx_start, *out_exidx_size);
                 return;
             }
         }