Adjust PC value in ARM stack trace.
-2 for Thumb BLX(2) or -4 for the rest.
Change-Id: I804fdabfa1db4709bede222d4b432e8d42d53167
diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp
index 87dbba3..5e8a401 100644
--- a/libc/bionic/debug_stacktrace.cpp
+++ b/libc/bionic/debug_stacktrace.cpp
@@ -91,6 +91,27 @@
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<short*>(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;
}