diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index 29a070fa3e043..48ef1866d6e11 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -34,7 +34,7 @@ class DwarfInstructions { typedef typename A::sint_t sint_t; static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, - R ®isters); + R ®isters, bool &isSignalFrame); private: @@ -150,7 +150,8 @@ v128 DwarfInstructions::getSavedVectorRegister( template int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, - pint_t fdeStart, R ®isters) { + pint_t fdeStart, R ®isters, + bool &isSignalFrame) { FDE_Info fdeInfo; CIE_Info cieInfo; if (CFI_Parser::decodeFDE(addressSpace, fdeStart, &fdeInfo, @@ -196,6 +197,8 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, // restoring SP means setting it to CFA. newRegisters.setSP(cfa); + isSignalFrame = cieInfo.isSignalFrame; + #if defined(_LIBUNWIND_TARGET_AARCH64) // If the target is aarch64 then the return address may have been signed // using the v8.3 pointer authentication extensions. The original diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index b4d44e111a65c..4c18614b33d27 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -929,7 +929,7 @@ class UnwindCursor : public AbstractUnwindCursor{ return DwarfInstructions::stepWithDwarf(_addressSpace, (pint_t)this->getReg(UNW_REG_IP), (pint_t)_info.unwind_info, - _registers); + _registers, _isSignalFrame); } #endif diff --git a/libunwind/src/UnwindLevel1-gcc-ext.c b/libunwind/src/UnwindLevel1-gcc-ext.c index 63e4083a45794..008df815665e6 100644 --- a/libunwind/src/UnwindLevel1-gcc-ext.c +++ b/libunwind/src/UnwindLevel1-gcc-ext.c @@ -221,7 +221,14 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, int *ipBefore) { _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context); - *ipBefore = 0; + int isSignalFrame = __unw_is_signal_frame((unw_cursor_t *)context); + // Negative means some kind of error (probably UNW_ENOINFO), but we have no + // good way to report that, and this maintains backward compatibility with the + // implementation that hard-coded zero in every case, even signal frames. + if (isSignalFrame <= 0) + *ipBefore = 0; + else + *ipBefore = 1; return _Unwind_GetIP(context); } diff --git a/libunwind/test/signal_frame.pass.cpp b/libunwind/test/signal_frame.pass.cpp new file mode 100644 index 0000000000000..b14e95a515286 --- /dev/null +++ b/libunwind/test/signal_frame.pass.cpp @@ -0,0 +1,25 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Ensure that functions marked as signal frames are reported as such. + +#include +#include +#include + +int main(void) { + asm(".cfi_signal_frame"); + unw_cursor_t cursor; + unw_context_t uc; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + assert(unw_step(&cursor) > 0); + assert(unw_is_signal_frame(&cursor)); + return 0; +}