https://github.com/mstorsjo created https://github.com/llvm/llvm-project/pull/137950
This is generally very similar to the aarch64 case. Contrary to aarch64, the public headers don't contain any definition of a struct for interpreting this data, so we provide our own. From 8a03c40961c30bc7a73d4bb841e1811722d2f23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <mar...@martin.st> Date: Tue, 18 Apr 2023 15:02:54 +0300 Subject: [PATCH 1/2] [libunwind] [SEH] Implement parsing of aarch64 pdata/xdata This is needed for forced unwind. This adds an aarch64 case for extracting the LanguageHandler and HandlerData fields from unwind info, in UnwindCursor::getInfoFromSEH, corresponding to the existing case for x86_64. This uses the struct IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA; this only became available in WinSDK 10.0.19041.0 and mingw-w64 v11.0 (or a mingw-w64 git snapshot after April 2023). (This is only a build-time requirement though; the format for the unwind data has been fixed since the start of Windows 10 on ARM64, so this doesn't impose any runtime requirement.) --- libunwind/src/UnwindCursor.hpp | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index ca9927edc9990..5c1d77ebeddaf 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -2018,6 +2018,52 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) { _info.handler = 0; } } +#elif defined(_LIBUNWIND_TARGET_AARCH64) + if (unwindEntry->Flag != 0) { // Packed unwind info + _info.end_ip = _info.start_ip + unwindEntry->FunctionLength * 4; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + // Packed unwind info doesn't have an exception handler. + _info.lsda = 0; + _info.handler = 0; + } + } else { + IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA *xdata = + reinterpret_cast<IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA *>( + base + unwindEntry->UnwindData); + _info.end_ip = _info.start_ip + xdata->FunctionLength * 4; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + if (xdata->ExceptionDataPresent) { + uint32_t offset = 1; // The main xdata + uint32_t codeWords = xdata->CodeWords; + uint32_t epilogScopes = xdata->EpilogCount; + if (xdata->EpilogCount == 0 && xdata->CodeWords == 0) { + uint32_t extensionWord = reinterpret_cast<uint32_t *>(xdata)[1]; + codeWords = (extensionWord >> 16) & 0xff; + epilogScopes = extensionWord & 0xffff; + offset++; + } + if (!xdata->EpilogInHeader) + offset += epilogScopes; + offset += codeWords; + uint32_t *exceptionHandlerInfo = + reinterpret_cast<uint32_t *>(xdata) + offset; + _dispContext.HandlerData = &exceptionHandlerInfo[1]; + _dispContext.LanguageHandler = reinterpret_cast<EXCEPTION_ROUTINE *>( + base + exceptionHandlerInfo[0]); + _info.lsda = reinterpret_cast<unw_word_t>(_dispContext.HandlerData); + if (_dispContext.LanguageHandler) + _info.handler = + reinterpret_cast<unw_word_t>(__libunwind_seh_personality); + else + _info.handler = 0; + } else { + _info.lsda = 0; + _info.handler = 0; + } + } + } #endif setLastPC(pc); return true; From 7254f7c4d8b07420c873b6729fac273f71efe38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <mar...@martin.st> Date: Tue, 18 Apr 2023 23:28:20 +0300 Subject: [PATCH 2/2] [libunwind] [SEH] Implement parsing of ARM pdata/xdata This is generally very similar to the aarch64 case. Contrary to aarch64, the public headers don't contain any definition of a struct for interpreting this data, so we provide our own. --- libunwind/src/UnwindCursor.hpp | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 5c1d77ebeddaf..1cbed2d6f93b9 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -83,6 +83,19 @@ struct UNWIND_INFO { uint16_t UnwindCodes[2]; }; +union UNWIND_INFO_ARM { + DWORD HeaderData; + struct { + DWORD FunctionLength : 18; + DWORD Version : 2; + DWORD ExceptionDataPresent : 1; + DWORD EpilogInHeader : 1; + DWORD FunctionFragment : 1; + DWORD EpilogCount : 5; + DWORD CodeWords : 4; + } s; +}; + extern "C" _Unwind_Reason_Code __libunwind_seh_personality( int, _Unwind_Action, uint64_t, _Unwind_Exception *, struct _Unwind_Context *); @@ -2064,6 +2077,51 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) { } } } +#elif defined(_LIBUNWIND_TARGET_ARM) + if (unwindEntry->Flag != 0) { // Packed unwind info + _info.end_ip = _info.start_ip + unwindEntry->FunctionLength * 2; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + // Packed unwind info doesn't have an exception handler. + _info.lsda = 0; + _info.handler = 0; + } + } else { + UNWIND_INFO_ARM *xdata = + reinterpret_cast<UNWIND_INFO_ARM *>(base + unwindEntry->UnwindData); + _info.end_ip = _info.start_ip + xdata->s.FunctionLength * 2; + // Only fill in the handler and LSDA if they're stale. + if (pc != getLastPC()) { + if (xdata->s.ExceptionDataPresent) { + uint32_t offset = 1; // The main xdata + uint32_t codeWords = xdata->s.CodeWords; + uint32_t epilogScopes = xdata->s.EpilogCount; + if (xdata->s.EpilogCount == 0 && xdata->s.CodeWords == 0) { + uint32_t extensionWord = reinterpret_cast<uint32_t *>(xdata)[1]; + codeWords = (extensionWord >> 16) & 0xff; + epilogScopes = extensionWord & 0xffff; + offset++; + } + if (!xdata->s.EpilogInHeader) + offset += epilogScopes; + offset += codeWords; + uint32_t *exceptionHandlerInfo = + reinterpret_cast<uint32_t *>(xdata) + offset; + _dispContext.HandlerData = &exceptionHandlerInfo[1]; + _dispContext.LanguageHandler = reinterpret_cast<EXCEPTION_ROUTINE *>( + base + exceptionHandlerInfo[0]); + _info.lsda = reinterpret_cast<unw_word_t>(_dispContext.HandlerData); + if (_dispContext.LanguageHandler) + _info.handler = + reinterpret_cast<unw_word_t>(__libunwind_seh_personality); + else + _info.handler = 0; + } else { + _info.lsda = 0; + _info.handler = 0; + } + } + } #endif setLastPC(pc); return true; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits