This is an archive of the discontinued LLVM Phabricator instance.

[libunwind] Don't store a predecremented PC when using SEH
ClosedPublic

Authored by mstorsjo on Jun 2 2022, 2:42 AM.

Details

Summary

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
instruction.

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.

Diff Detail

Event Timeline

mstorsjo created this revision.Jun 2 2022, 2:42 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptJun 2 2022, 2:42 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript
mstorsjo requested review of this revision.Jun 2 2022, 2:42 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 2 2022, 2:42 AM
mstorsjo retitled this revision from [libunwind] Don't store a predecremented SP when using SEH to [libunwind] Don't store a predecremented PC when using SEH.Jun 2 2022, 2:43 AM
cdavis5x accepted this revision.Jun 2 2022, 1:17 PM
MaskRay accepted this revision.EditedJun 5 2022, 11:02 AM

I don't have an environment to verify and don't know much about SEH, but I assume that this is similar to UnwindCursor<A, R>::setInfoBasedOnIPRegister and you or @cdavis5x has verified the correctness.

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.

libgcc _Unwind_GetIPInfo sets ip_before_insn to 0 so libsupc++ from libstdc++ does an the - 1 subtraction. I assume that libc++abi is similar.

This revision is now accepted and ready to land.Jun 5 2022, 11:02 AM
manojgupta added subscribers: danielkiss, manojgupta.

@danielkiss can you please review?

I don't have an environment to verify and don't know much about SEH, but I assume that this is similar to UnwindCursor<A, R>::setInfoBasedOnIPRegister and you or @cdavis5x has verified the correctness.

Yeah I've tested it as far as I can, and @cdavis5x was the one who implemented the SEH parts in libunwind originally.

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.

libgcc _Unwind_GetIPInfo sets ip_before_insn to 0 so libsupc++ from libstdc++ does an the - 1 subtraction. I assume that libc++abi is similar.

Thanks for the further context on that issue! Yeah, although libc++abi doesn't call such a function, but seems to unconditionally do the -1 subtraction. libunwind's _Unwind_GetIPInfo uses UnwindCursor::isSignalFrame(), and the SEH version of that always returns false currently. So this makes those things more consistent too.