Skip to content

[libunwind] [SEH] Implement parsing of ARM pdata/xdata #137950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2025

Conversation

mstorsjo
Copy link
Member

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.

@mstorsjo mstorsjo requested a review from a team as a code owner April 30, 2025 10:49
@mstorsjo
Copy link
Member Author

This goes on top of #137949.

@llvmbot
Copy link
Member

llvmbot commented Apr 30, 2025

@llvm/pr-subscribers-libunwind

Author: Martin Storsjö (mstorsjo)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/137950.diff

1 Files Affected:

  • (modified) libunwind/src/UnwindCursor.hpp (+104)
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index ca9927edc9990..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 *);
@@ -2018,6 +2031,97 @@ 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;
+      }
+    }
+  }
+#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;

@mstorsjo mstorsjo force-pushed the libunwind-arm-xdata branch from c027e4f to b5ed499 Compare May 2, 2025 12:15
Copy link
Contributor

@cjacek cjacek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mstorsjo
Copy link
Member Author

mstorsjo commented May 5, 2025

@MaskRay Can you give the necessary @reviewers-libunwind approval here, given @cjacek's review?

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.
@mstorsjo mstorsjo force-pushed the libunwind-arm-xdata branch from b5ed499 to fb51e2b Compare May 9, 2025 08:09
@mstorsjo mstorsjo merged commit fc83aae into llvm:main May 9, 2025
150 of 154 checks passed
@mstorsjo mstorsjo deleted the libunwind-arm-xdata branch May 9, 2025 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants