@ -32,54 +32,10 @@
#include < iostream >
#include "absl/base/attributes.h"
#include "absl/debugging/internal/address_is_readable.h"
#include "absl/debugging/internal/vdso_support.h"
#include "absl/debugging/stacktrace.h"
static const uintptr_t kUnknownFrameSize = 0;
#if defined(__linux__)
// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
static const unsigned char *GetKernelRtSigreturnAddress() {
constexpr uintptr_t kImpossibleAddress = 0;
ABSL_CONST_INIT static std::atomic< uintptr_t > memoized(kImpossibleAddress);
uintptr_t address = memoized.load(std::memory_order_relaxed);
if (address != kImpossibleAddress) {
return reinterpret_cast< const unsigned char * > (address);
}
address = reinterpret_cast< uintptr_t > (nullptr);
#if ABSL_HAVE_VDSO_SUPPORT
absl::debugging_internal::VDSOSupport vdso;
if (vdso.IsPresent()) {
absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
// Symbol versioning pulled from arch/riscv/kernel/vdso/vdso.lds at v5.10.
auto lookup = [& ](int type) {
return vdso.LookupSymbol("__vdso_rt_sigreturn", "LINUX_4.15", type,
&symbol_info);
};
if ((!lookup(STT_FUNC) & & !lookup(STT_NOTYPE)) ||
symbol_info.address == nullptr) {
// Unexpected: VDSO is present, yet the expected symbol is missing or
// null.
assert(false & & "VDSO is present, but doesn't have expected symbol");
} else {
if (reinterpret_cast< uintptr_t > (symbol_info.address) !=
kImpossibleAddress) {
address = reinterpret_cast< uintptr_t > (symbol_info.address);
} else {
assert(false & & "VDSO returned invalid address");
}
}
}
#endif
memoized.store(address, std::memory_order_relaxed);
return reinterpret_cast< const unsigned char * > (address);
}
#endif // __linux__
// Compute the size of a stack frame in [low..high). We assume that low < high.
// Return size of kUnknownFrameSize.
template < typename T >
@ -115,40 +71,23 @@ static void ** NextStackFrame(void **old_frame_pointer, const void *uc,
// $sp ->| ... |
// +----------------+
void **new_frame_pointer = reinterpret_cast< void * * > (old_frame_pointer[-2]);
uintptr_t frame_pointer = reinterpret_cast< uintptr_t > (new_frame_pointer);
// The RISCV ELF psABI mandates that the stack pointer is always 16-byte
// aligned.
// TODO(#1236) this doesn't hold for ILP32E which only mandates a 4-byte
// alignment.
if ((reinterpret_cast< uintptr_t > (new_ frame_pointer) & 15) != 0 )
if (frame_pointer & 15)
return nullptr;
#if defined(__linux__)
if (WITH_CONTEXT & & uc != nullptr) {
// Check to see if next frame's return address is __kernel_rt_sigreturn.
if (old_frame_pointer[-1] == GetKernelRtSigreturnAddress()) {
const ucontext_t *ucv = static_cast< const ucontext_t * > (uc);
// old_frame_pointer is not suitable for unwinding, look at ucontext to
// discover frame pointer before signal.
//
// If the new frame pointer matches the signal context, avoid terminating
// early to deal with alternate signal stacks.
if (WITH_CONTEXT)
if (const ucontext_t *ucv = static_cast< const ucontext_t * > (uc))
// RISCV ELF psABI has the frame pointer at x8/fp/s0.
// -- RISCV psABI Table 18.2
void **const pre_signal_frame_pointer =
reinterpret_cast< void * * > (ucv->uc_mcontext.__gregs[8]);
// Check the alleged frame pointer is actually readable. This is to
// prevent "double fault" in case we hit the first fault due to stack
// corruption.
if (!absl::debugging_internal::AddressIsReadable(
pre_signal_frame_pointer))
return nullptr;
// Alleged frame pointer is readable, use it for further unwinding.
new_frame_pointer = pre_signal_frame_pointer;
}
return new_frame_pointer;
}
#endif
if (ucv->uc_mcontext.__gregs[8] == frame_pointer)
return new_frame_pointer;
// Check frame size. In strict mode, we assume frames to be under 100,000
// bytes. In non-strict mode, we relax the limit to 1MB.
@ -165,6 +104,7 @@ static void ** NextStackFrame(void **old_frame_pointer, const void *uc,
reinterpret_cast< uintptr_t > (new_frame_pointer) > range.second)
return nullptr;
}
if (frame_size > max_size)
return nullptr;