diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp index 87dbba3d9..5e8a40103 100644 --- a/libc/bionic/debug_stacktrace.cpp +++ b/libc/bionic/debug_stacktrace.cpp @@ -91,6 +91,27 @@ static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) return _URC_NO_REASON; } +#ifdef __arm__ + /* + * The instruction pointer is pointing at the instruction after the bl(x), and + * the _Unwind_Backtrace routine already masks the Thumb mode indicator (LSB + * in PC). So 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. + */ + if (ip != 0) { + short* ptr = reinterpret_cast(ip); + // Thumb BLX(2) + + // FIXME - GCC 4.7 seems to have a bug as without the unnecessary cast to + // short the test will never pass. + if ((*(ptr-1) & 0xff80) == (short) 0x4780) { + ip -= 2; + } else { + ip -= 4; + } + } +#endif + state->frames[state->frame_count++] = ip; return (state->frame_count >= state->max_depth) ? _URC_END_OF_STACK : _URC_NO_REASON; }