libunwind: Fix unw_step() for ARM EHABI.
This commit fixes the unw_step() for ARM EHABI. However, this commit
also changes the implementation details for ARM EHABI.
The first change is that the personality function should call
__gnu_unwind_frame() for default (or de facto) frame unwinding based on
the ARM-defined unwind opcode. The function __gnu_unwind_frame() will
in turn calls unw_step() which actually unwinds the frame.
The second change is that the implementation _Unwind_Backtrace() should
no longer calls unw_step() to unwind the frame; since according to ARM
EHABI, the personality function should unwind the frame for us.
Special thanks to Anton for helpful suggestion on the initial version of
this patch.
llvm-svn: 238560
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 7fab97f364d2e2f0beb7fffa3e42885db72982d5
diff --git a/src/Unwind-EHABI.cpp b/src/Unwind-EHABI.cpp
index 8a6bfc0..eb641e3 100644
--- a/src/Unwind-EHABI.cpp
+++ b/src/Unwind-EHABI.cpp
@@ -168,25 +168,22 @@
assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry");
Descriptor::Format format =
static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24);
- size_t len = 0;
- size_t off = 0;
- unwindingData = decode_eht_entry(unwindingData, &off, &len);
- if (unwindingData == nullptr) {
- return _URC_FAILURE;
- }
+
+ const char *lsda =
+ reinterpret_cast<const char *>(_Unwind_GetLanguageSpecificData(context));
// Handle descriptors before unwinding so they are processed in the context
// of the correct stack frame.
_Unwind_Reason_Code result =
- ProcessDescriptors(
- state, ucbp, context, format,
- reinterpret_cast<const char*>(ucbp->pr_cache.ehtp) + len,
- ucbp->pr_cache.additional);
+ ProcessDescriptors(state, ucbp, context, format, lsda,
+ ucbp->pr_cache.additional);
if (result != _URC_CONTINUE_UNWIND)
return result;
- return _Unwind_VRS_Interpret(context, unwindingData, off, len);
+ if (unw_step(reinterpret_cast<unw_cursor_t*>(context)) != UNW_STEP_SUCCESS)
+ return _URC_FAILURE;
+ return _URC_CONTINUE_UNWIND;
}
// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE /
@@ -213,26 +210,37 @@
*/
extern "C" const uint32_t*
decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
- assert((*data & 0x80000000) != 0 &&
- "decode_eht_entry() does not support user-defined personality");
-
- // 6.3: ARM Compact Model
- // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
- // by format:
- Descriptor::Format format =
- static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
- switch (format) {
- case Descriptor::SU16:
- *len = 4;
- *off = 1;
- break;
- case Descriptor::LU16:
- case Descriptor::LU32:
- *len = 4 + 4 * ((*data & 0x00ff0000) >> 16);
- *off = 2;
- break;
- default:
- return nullptr;
+ if ((*data & 0x80000000) == 0) {
+ // 6.2: Generic Model
+ //
+ // EHT entry is a prel31 pointing to the PR, followed by data understood
+ // only by the personality routine. Fortunately, all existing assembler
+ // implementations, including GNU assembler, LLVM integrated assembler,
+ // and ARM assembler, assume that the unwind opcodes come after the
+ // personality rountine address.
+ *off = 1; // First byte is size data.
+ *len = (((data[1] >> 24) & 0xff) + 1) * 4;
+ data++; // Skip the first word, which is the prel31 offset.
+ } else {
+ // 6.3: ARM Compact Model
+ //
+ // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
+ // by format:
+ Descriptor::Format format =
+ static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
+ switch (format) {
+ case Descriptor::SU16:
+ *len = 4;
+ *off = 1;
+ break;
+ case Descriptor::LU16:
+ case Descriptor::LU32:
+ *len = 4 + 4 * ((*data & 0x00ff0000) >> 16);
+ *off = 2;
+ break;
+ default:
+ return nullptr;
+ }
}
return data;
}
@@ -443,6 +451,7 @@
// Walk each frame looking for a place to stop.
for (bool handlerNotFound = true; handlerNotFound;) {
+#if !LIBCXXABI_ARM_EHABI
// Ask libuwind to get next frame (skip over first which is
// _Unwind_RaiseException).
int stepResult = unw_step(&cursor1);
@@ -457,6 +466,7 @@
static_cast<void *>(exception_object));
return _URC_FATAL_PHASE1_ERROR;
}
+#endif
// See if frame has code to run (has personality routine).
unw_proc_info_t frameInfo;
@@ -575,6 +585,7 @@
resume = false;
}
+#if !LIBCXXABI_ARM_EHABI
int stepResult = unw_step(&cursor2);
if (stepResult == 0) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
@@ -587,6 +598,7 @@
static_cast<void *>(exception_object));
return _URC_FATAL_PHASE2_ERROR;
}
+#endif
// Get info about this frame.
unw_word_t sp;
@@ -752,11 +764,6 @@
_LIBUNWIND_TRACE_API(
"_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx\n",
static_cast<void *>(context), (long long)result);
- if (result != 0) {
- if (*((uint8_t *)result) != 0xFF)
- _LIBUNWIND_DEBUG_LOG("lsda at 0x%llx does not start with 0xFF\n",
- (long long)result);
- }
return result;
}
@@ -990,4 +997,13 @@
exception_object);
}
+_LIBUNWIND_EXPORT extern "C" _Unwind_Reason_Code
+__gnu_unwind_frame(_Unwind_Exception *exception_object,
+ struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ if (unw_step(cursor) != UNW_STEP_SUCCESS)
+ return _URC_FAILURE;
+ return _URC_OK;
+}
+
#endif // LIBCXXABI_ARM_EHABI
diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp
index b4d413f..7703af9 100644
--- a/src/UnwindCursor.hpp
+++ b/src/UnwindCursor.hpp
@@ -440,6 +440,20 @@
#if LIBCXXABI_ARM_EHABI
bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections §s);
+
+ int stepWithEHABI() {
+ size_t len = 0;
+ size_t off = 0;
+ // FIXME: Calling decode_eht_entry() here is violating the libunwind
+ // abstraction layer.
+ const uint32_t *ehtp =
+ decode_eht_entry(reinterpret_cast<const uint32_t *>(_info.unwind_info),
+ &off, &len);
+ if (_Unwind_VRS_Interpret((_Unwind_Context *)this, ehtp, off, len) !=
+ _URC_CONTINUE_UNWIND)
+ return UNW_STEP_END;
+ return UNW_STEP_SUCCESS;
+ }
#endif
#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
@@ -731,7 +745,7 @@
// isSingleWordEHT -- whether the entry is in the index.
unw_word_t personalityRoutine = 0xbadf00d;
bool scope32 = false;
- uintptr_t lsda = 0xbadf00d;
+ uintptr_t lsda;
// If the high bit in the exception handling table entry is set, the entry is
// in compact form (section 6.3 EHABI).
@@ -744,16 +758,19 @@
personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0;
extraWords = 0;
scope32 = false;
+ lsda = isSingleWordEHT ? 0 : (exceptionTableAddr + 4);
break;
case 1:
personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1;
extraWords = (exceptionTableData & 0x00ff0000) >> 16;
scope32 = false;
+ lsda = exceptionTableAddr + (extraWords + 1) * 4;
break;
case 2:
personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2;
extraWords = (exceptionTableData & 0x00ff0000) >> 16;
scope32 = true;
+ lsda = exceptionTableAddr + (extraWords + 1) * 4;
break;
default:
_LIBUNWIND_ABORT("unknown personality routine");
@@ -1281,7 +1298,7 @@
#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
result = this->stepWithDwarfFDE();
#elif LIBCXXABI_ARM_EHABI
- result = UNW_STEP_SUCCESS;
+ result = this->stepWithEHABI();
#else
#error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \
_LIBUNWIND_SUPPORT_DWARF_UNWIND or \
diff --git a/src/UnwindLevel1-gcc-ext.c b/src/UnwindLevel1-gcc-ext.c
index b1e3f77..2a8b24c 100644
--- a/src/UnwindLevel1-gcc-ext.c
+++ b/src/UnwindLevel1-gcc-ext.c
@@ -15,6 +15,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "config.h"
#include "libunwind_ext.h"
@@ -110,10 +111,18 @@
_LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n",
(void *)(uintptr_t)callback);
+#if LIBCXXABI_ARM_EHABI
+ // Create a mock exception object for force unwinding.
+ _Unwind_Exception ex;
+ memset(&ex, '\0', sizeof(ex));
+ ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
+#endif
+
// walk each frame
while (true) {
_Unwind_Reason_Code result;
+#if !LIBCXXABI_ARM_EHABI
// ask libuwind to get next frame (skip over first frame which is
// _Unwind_Backtrace())
if (unw_step(&cursor) <= 0) {
@@ -122,48 +131,28 @@
_URC_END_OF_STACK);
return _URC_END_OF_STACK;
}
-
-#if LIBCXXABI_ARM_EHABI
+#else
// Get the information for this frame.
unw_proc_info_t frameInfo;
if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
return _URC_END_OF_STACK;
}
- struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
+ // Update the pr_cache in the mock exception object.
const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
- if ((*unwindInfo & 0x80000000) == 0) {
- // 6.2: Generic Model
- // EHT entry is a prel31 pointing to the PR, followed by data understood
- // only by the personality routine. Since EHABI doesn't guarantee the
- // location or availability of the unwind opcodes in the generic model,
- // we have to call personality functions with (_US_VIRTUAL_UNWIND_FRAME |
- // _US_FORCE_UNWIND) state.
+ ex.pr_cache.fnstart = frameInfo.start_ip;
+ ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
+ ex.pr_cache.additional= frameInfo.flags;
- // Create a mock exception object for force unwinding.
- _Unwind_Exception ex;
- ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
- ex.pr_cache.fnstart = frameInfo.start_ip;
- ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
- ex.pr_cache.additional= frameInfo.flags;
-
- // Get and call the personality function to unwind the frame.
- __personality_routine pr = (__personality_routine) readPrel31(unwindInfo);
- if (pr(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
- _URC_CONTINUE_UNWIND) {
- return _URC_END_OF_STACK;
- }
- } else {
- size_t off, len;
- unwindInfo = decode_eht_entry(unwindInfo, &off, &len);
- if (unwindInfo == NULL) {
- return _URC_FAILURE;
- }
-
- result = _Unwind_VRS_Interpret(context, unwindInfo, off, len);
- if (result != _URC_CONTINUE_UNWIND) {
- return _URC_END_OF_STACK;
- }
+ struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
+ // Get and call the personality function to unwind the frame.
+ __personality_routine handler = (__personality_routine) frameInfo.handler;
+ if (handler == NULL) {
+ return _URC_END_OF_STACK;
+ }
+ if (handler(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
+ _URC_CONTINUE_UNWIND) {
+ return _URC_END_OF_STACK;
}
#endif // LIBCXXABI_ARM_EHABI