[libunwind] [SEH] Implement parsing of ARM pdata/xdata (#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.
This commit is contained in:
Martin Storsjö 2025-05-09 16:04:14 +03:00 committed by GitHub
parent 89822ff5a8
commit fc83aaea06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -83,6 +83,22 @@ struct UNWIND_INFO {
uint16_t UnwindCodes[2];
};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
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;
};
};
#pragma clang diagnostic pop
extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
int, _Unwind_Action, uint64_t, _Unwind_Exception *,
struct _Unwind_Context *);
@ -2018,9 +2034,18 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
_info.handler = 0;
}
}
#elif defined(_LIBUNWIND_TARGET_AARCH64)
#elif defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_ARM)
#if defined(_LIBUNWIND_TARGET_AARCH64)
#define FUNC_LENGTH_UNIT 4
#define XDATA_TYPE IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY_XDATA
#else
#define FUNC_LENGTH_UNIT 2
#define XDATA_TYPE UNWIND_INFO_ARM
#endif
if (unwindEntry->Flag != 0) { // Packed unwind info
_info.end_ip = _info.start_ip + unwindEntry->FunctionLength * 4;
_info.end_ip =
_info.start_ip + unwindEntry->FunctionLength * FUNC_LENGTH_UNIT;
// Only fill in the handler and LSDA if they're stale.
if (pc != getLastPC()) {
// Packed unwind info doesn't have an exception handler.
@ -2028,10 +2053,9 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
_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;
XDATA_TYPE *xdata =
reinterpret_cast<XDATA_TYPE *>(base + unwindEntry->UnwindData);
_info.end_ip = _info.start_ip + xdata->FunctionLength * FUNC_LENGTH_UNIT;
// Only fill in the handler and LSDA if they're stale.
if (pc != getLastPC()) {
if (xdata->ExceptionDataPresent) {
@ -2039,6 +2063,7 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
uint32_t codeWords = xdata->CodeWords;
uint32_t epilogScopes = xdata->EpilogCount;
if (xdata->EpilogCount == 0 && xdata->CodeWords == 0) {
// The extension word has got the same layout for both ARM and ARM64
uint32_t extensionWord = reinterpret_cast<uint32_t *>(xdata)[1];
codeWords = (extensionWord >> 16) & 0xff;
epilogScopes = extensionWord & 0xffff;