[libc++abi][AIX] Enable calculating addresses with DW_EH_PE_datarel
Summary:
This patch enables calculating relative addresses with the DW_EH_PE_datarel encoding using a 'base' for AIX. After setting registers for jumping to the user code in gxx_personality_v0(), 'base' is cached in exception_header member catchTemp for use in __cxa_call_unexpected if ttypeIndex is less than 0 (exception spec).
Reviewed by: MaskRay, sfertile, compnerd, libc++abi
Differential Revision: https://reviews.llvm.org/D101298
GitOrigin-RevId: afd3607c8f369a4f1989387cb1eed35976968c89
diff --git a/src/cxa_personality.cpp b/src/cxa_personality.cpp
index 7f91951..a4f81d7 100644
--- a/src/cxa_personality.cpp
+++ b/src/cxa_personality.cpp
@@ -245,7 +245,7 @@
/// @returns decoded value
static
uintptr_t
-readEncodedPointer(const uint8_t** data, uint8_t encoding, uintptr_t /*base*/ = 0)
+readEncodedPointer(const uint8_t** data, uint8_t encoding, uintptr_t base = 0)
{
uintptr_t result = 0;
if (encoding == DW_EH_PE_omit)
@@ -296,8 +296,12 @@
if (result)
result += (uintptr_t)(*data);
break;
- case DW_EH_PE_textrel:
case DW_EH_PE_datarel:
+ assert((base != 0) && "DW_EH_PE_datarel is invalid with a base of 0");
+ if (result)
+ result += base;
+ break;
+ case DW_EH_PE_textrel:
case DW_EH_PE_funcrel:
case DW_EH_PE_aligned:
default:
@@ -349,7 +353,7 @@
static const __shim_type_info*
get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
uint8_t ttypeEncoding, bool native_exception,
- _Unwind_Exception* unwind_exception, uintptr_t base = 0)
+ _Unwind_Exception* unwind_exception, uintptr_t /*base*/ = 0)
{
if (classInfo == 0)
{
@@ -421,7 +425,7 @@
exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
uint8_t ttypeEncoding, const __shim_type_info* excpType,
void* adjustedPtr, _Unwind_Exception* unwind_exception,
- uintptr_t base = 0)
+ uintptr_t /*base*/ = 0)
{
if (classInfo == 0)
{
@@ -536,6 +540,9 @@
{
#if defined(__USING_SJLJ_EXCEPTIONS__)
#define __builtin_eh_return_data_regno(regno) regno
+#elif defined(__ibmxl__)
+// IBM xlclang++ compiler does not support __builtin_eh_return_data_regno.
+#define __builtin_eh_return_data_regno(regno) regno + 3
#endif
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
reinterpret_cast<uintptr_t>(unwind_exception));
@@ -615,7 +622,11 @@
return;
}
results.languageSpecificData = lsda;
+#if defined(_AIX)
+ uintptr_t base = _Unwind_GetDataRelBase(context);
+#else
uintptr_t base = 0;
+#endif
// Get the current instruction pointer and offset it before next
// instruction in the current frame which threw the exception.
uintptr_t ip = _Unwind_GetIP(context) - 1;
@@ -640,7 +651,8 @@
// dwarf emission
// Parse LSDA header.
uint8_t lpStartEncoding = *lsda++;
- const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
+ const uint8_t* lpStart =
+ (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
if (lpStart == 0)
lpStart = (const uint8_t*)funcStart;
uint8_t ttypeEncoding = *lsda++;
@@ -919,6 +931,15 @@
// Jump to the handler.
set_registers(unwind_exception, context, results);
+ // Cache base for calculating the address of ttype in
+ // __cxa_call_unexpected.
+ if (results.ttypeIndex < 0) {
+#if defined(_AIX)
+ exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context);
+#else
+ exception_header->catchTemp = 0;
+#endif
+ }
return _URC_INSTALL_CONTEXT;
}
@@ -948,6 +969,16 @@
assert(actions & _UA_CLEANUP_PHASE);
assert(results.reason == _URC_HANDLER_FOUND);
set_registers(unwind_exception, context, results);
+ // Cache base for calculating the address of ttype in __cxa_call_unexpected.
+ if (results.ttypeIndex < 0) {
+ __cxa_exception* exception_header =
+ (__cxa_exception*)(unwind_exception + 1) - 1;
+#if defined(_AIX)
+ exception_header->catchTemp = (void *)_Unwind_GetDataRelBase(context);
+#else
+ exception_header->catchTemp = 0;
+#endif
+ }
return _URC_INSTALL_CONTEXT;
}
@@ -1137,6 +1168,7 @@
#else
ttypeIndex = old_exception_header->handlerSwitchValue;
lsda = old_exception_header->languageSpecificData;
+ base = (uintptr_t)old_exception_header->catchTemp;
#endif
}
else
@@ -1160,11 +1192,13 @@
// Have:
// old_exception_header->languageSpecificData
// old_exception_header->actionRecord
+ // old_exception_header->catchTemp, base for calculating ttype
// Need
// const uint8_t* classInfo
// uint8_t ttypeEncoding
uint8_t lpStartEncoding = *lsda++;
- const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
+ const uint8_t* lpStart =
+ (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
(void)lpStart; // purposefully unused. Just needed to increment lsda.
uint8_t ttypeEncoding = *lsda++;
if (ttypeEncoding == DW_EH_PE_omit)
@@ -1238,6 +1272,15 @@
std::__terminate(t_handler);
}
+#if defined(_AIX)
+// Personality routine for EH using the range table. Make it an alias of
+// __gxx_personality_v0().
+_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
+ int version, _Unwind_Action actions, uint64_t exceptionClass,
+ _Unwind_Exception* unwind_exception, _Unwind_Context* context)
+ __attribute__((__alias__("__gxx_personality_v0")));
+#endif
+
} // extern "C"
} // __cxxabiv1