[libcxx-commits] [PATCH] D126869: [libunwind] Don't store a predecremented SP when using SEH

Martin Storsjö via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 2 02:43:00 PDT 2022

mstorsjo created this revision.
mstorsjo added reviewers: MaskRay, efriedma, zzheng, cdavis5x.
Herald added subscribers: jsji, StephenFan, pengfei, kristof.beyls.
Herald added projects: libunwind, All.
Herald added a reviewer: libunwind.
mstorsjo requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

This fixes unwinding in boundary cases on ARM with SEH.

In the case of ARM/Thumb, disp->ControlPc points at the following
instruction, with the thumb bit set. Thus by decrementing 1,
it still points at the next instruction. To achieve the desired
effect of pointing at the previous instruction, one first has to strip
out the thumb bit, then do the decrement by 1 to reach the previous

When libcxxabi looks for call site ranges, it already does
`_Unwind_GetIP(context) - 1` (in `scan_eh_tab` in
libcxxabi/src/cxa_personality.cpp) we shouldn't do the corresponding
`- 1` multiple times.

In the case of libcxxabi on Thumb, `funcStart` (still in `scan_eh_tab`)
may have the thumb bit set. If the program counter address is
decremented both in libunwind (first removing the thumb bit, then
decremented), and then libcxxabi decrements it further, and compares
with a `funcStart` with the thumb bit set, it could point to one byte
before the start of the call site.

Thus: This modification makes libunwind with SEH work with libcxxabi
on Thumb, in settings where libunwind and libcxxabi worked fine with
Dwarf before.

For existing cases with libunwind with SEH (on x86_64 and aarch64),
this modification doesn't break any of my testcases.

  rG LLVM Github Monorepo



Index: libunwind/src/UnwindCursor.hpp
--- libunwind/src/UnwindCursor.hpp
+++ libunwind/src/UnwindCursor.hpp
@@ -518,6 +518,14 @@
   pint_t getLastPC() const { return _dispContext.ControlPc; }
   void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; }
   RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+#ifdef __arm__
+    // Remove the thumb bit; FunctionEntry ranges don't include the thumb bit.
+    pc &= ~1U;
+    // If pc points exactly at the end of the range, we might resolve the
+    // next function instead. Decrement pc by 1 to fit inside the current
+    // function.
+    pc -= 1;
     _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc,
Index: libunwind/src/Unwind-seh.cpp
--- libunwind/src/Unwind-seh.cpp
+++ libunwind/src/Unwind-seh.cpp
@@ -104,7 +104,7 @@
   if (!ctx) {
     __unw_init_seh(&cursor, disp->ContextRecord);
     __unw_seh_set_disp_ctx(&cursor, disp);
-    __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1);
+    __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc);
     ctx = (struct _Unwind_Context *)&cursor;
     if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {

-------------- next part --------------
A non-text attachment was scrubbed...
Name: D126869.433703.patch
Type: text/x-patch
Size: 1438 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20220602/ca14648b/attachment-0001.bin>

More information about the libcxx-commits mailing list