From b72c9d80ab760eb2f33a6667b0f0acfb779d9439 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 25 Aug 2015 20:48:46 -0700 Subject: [PATCH] Fix the 16 bit/32 bit instruction check for arm. The current code only looks for a branch, instead make this more general. Change-Id: Ib442d6f2f04074e274b320ca0cf04734cc78e5d2 --- libc/bionic/debug_stacktrace.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp index 41009117b..b49a42ed5 100644 --- a/libc/bionic/debug_stacktrace.cpp +++ b/libc/bionic/debug_stacktrace.cpp @@ -90,15 +90,22 @@ static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) // Modify the pc to point at the real function. if (ip != 0) { #if defined(__arm__) - // We need to do a quick check here to find out if the previous - // instruction is a Thumb-mode BLX(2). If so subtract 2 otherwise - // 4 from PC. - short* ptr = reinterpret_cast(ip); - // Thumb BLX(2) - if ((*(ptr-1) & 0xff80) == 0x4780) { - ip -= 2; - } else { - ip -= 4; + // If the ip is suspiciously low, do nothing to avoid a segfault trying + // to access this memory. + if (ip >= 4096) { + // Check bits [15:11] of the first halfword assuming the instruction + // is 32 bits long. If the bits are any of these values, then our + // assumption was correct: + // b11101 + // b11110 + // b11111 + // Otherwise, this is a 16 bit instruction. + uint16_t value = (*reinterpret_cast(ip - 2)) >> 11; + if (value == 0x1f || value == 0x1e || value == 0x1d) { + ip -= 4; + } else { + ip -= 2; + } } #elif defined(__aarch64__) // All instructions are 4 bytes long, skip back one instruction.