diff options
Diffstat (limited to 'lib/Support/PrettyStackTrace.cpp')
-rw-r--r-- | lib/Support/PrettyStackTrace.cpp | 92 |
1 files changed, 75 insertions, 17 deletions
diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index 206de91ae239..aec00baec0e3 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -1,9 +1,8 @@ //===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -15,12 +14,14 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm-c/ErrorHandling.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Watchdog.h" #include "llvm/Support/raw_ostream.h" +#include <atomic> #include <cstdarg> #include <cstdio> #include <tuple> @@ -34,7 +35,7 @@ using namespace llvm; // If backtrace support is not enabled, compile out support for pretty stack // traces. This has the secondary effect of not requiring thread local storage // when backtrace support is disabled. -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES // We need a thread local pointer to manage the stack of our stack trace // objects, but we *really* cannot tolerate destructors running and do not want @@ -42,6 +43,22 @@ using namespace llvm; // thread-local variable. static LLVM_THREAD_LOCAL PrettyStackTraceEntry *PrettyStackTraceHead = nullptr; +// The use of 'volatile' here is to ensure that any particular thread always +// reloads the value of the counter. The 'std::atomic' allows us to specify that +// this variable is accessed in an unsychronized way (it's not actually +// synchronizing). This does technically mean that the value may not appear to +// be the same across threads running simultaneously on different CPUs, but in +// practice the worst that will happen is that we won't print a stack trace when +// we could have. +// +// This is initialized to 1 because 0 is used as a sentinel for "not enabled on +// the current thread". If the user happens to overflow an 'unsigned' with +// SIGINFO requests, it's possible that some threads will stop responding to it, +// but the program won't crash. +static volatile std::atomic<unsigned> GlobalSigInfoGenerationCounter = + ATOMIC_VAR_INIT(1); +static LLVM_THREAD_LOCAL unsigned ThreadLocalSigInfoGenerationCounter = 0; + namespace llvm { PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *Head) { PrettyStackTraceEntry *Prev = nullptr; @@ -57,8 +74,9 @@ static void PrintStack(raw_ostream &OS) { // to fail if we crashed due to stack overflow), we do an up-front pass to // reverse the stack, then print it, then reverse it again. unsigned ID = 0; - PrettyStackTraceEntry *ReversedStack = - llvm::ReverseStackTrace(PrettyStackTraceHead); + SaveAndRestore<PrettyStackTraceEntry *> SavedStack{PrettyStackTraceHead, + nullptr}; + PrettyStackTraceEntry *ReversedStack = ReverseStackTrace(SavedStack.get()); for (const PrettyStackTraceEntry *Entry = ReversedStack; Entry; Entry = Entry->getNextEntry()) { OS << ID++ << ".\t"; @@ -68,7 +86,10 @@ static void PrintStack(raw_ostream &OS) { llvm::ReverseStackTrace(ReversedStack); } -/// PrintCurStackTrace - Print the current stack trace to the specified stream. +/// Print the current stack trace to the specified stream. +/// +/// Marked NOINLINE so it can be called from debuggers. +LLVM_ATTRIBUTE_NOINLINE static void PrintCurStackTrace(raw_ostream &OS) { // Don't print an empty trace. if (!PrettyStackTraceHead) return; @@ -128,11 +149,24 @@ static void CrashHandler(void *) { #endif } -// defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES -#endif +static void printForSigInfoIfNeeded() { + unsigned CurrentSigInfoGeneration = + GlobalSigInfoGenerationCounter.load(std::memory_order_relaxed); + if (ThreadLocalSigInfoGenerationCounter == 0 || + ThreadLocalSigInfoGenerationCounter == CurrentSigInfoGeneration) { + return; + } + + PrintCurStackTrace(errs()); + ThreadLocalSigInfoGenerationCounter = CurrentSigInfoGeneration; +} + +#endif // ENABLE_BACKTRACES PrettyStackTraceEntry::PrettyStackTraceEntry() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES + // Handle SIGINFO first, because we haven't finished constructing yet. + printForSigInfoIfNeeded(); // Link ourselves. NextEntry = PrettyStackTraceHead; PrettyStackTraceHead = this; @@ -140,10 +174,12 @@ PrettyStackTraceEntry::PrettyStackTraceEntry() { } PrettyStackTraceEntry::~PrettyStackTraceEntry() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES assert(PrettyStackTraceHead == this && "Pretty stack trace entry destruction is out of order"); PrettyStackTraceHead = NextEntry; + // Handle SIGINFO first, because we already started destructing. + printForSigInfoIfNeeded(); #endif } @@ -175,7 +211,7 @@ void PrettyStackTraceProgram::print(raw_ostream &OS) const { OS << '\n'; } -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES static bool RegisterCrashPrinter() { sys::AddSignalHandler(CrashHandler, nullptr); return false; @@ -183,15 +219,37 @@ static bool RegisterCrashPrinter() { #endif void llvm::EnablePrettyStackTrace() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES // The first time this is called, we register the crash printer. static bool HandlerRegistered = RegisterCrashPrinter(); (void)HandlerRegistered; #endif } +void llvm::EnablePrettyStackTraceOnSigInfoForThisThread(bool ShouldEnable) { +#if ENABLE_BACKTRACES + if (!ShouldEnable) { + ThreadLocalSigInfoGenerationCounter = 0; + return; + } + + // The first time this is called, we register the SIGINFO handler. + static bool HandlerRegistered = []{ + sys::SetInfoSignalFunction([]{ + GlobalSigInfoGenerationCounter.fetch_add(1, std::memory_order_relaxed); + }); + return false; + }(); + (void)HandlerRegistered; + + // Next, enable it for the current thread. + ThreadLocalSigInfoGenerationCounter = + GlobalSigInfoGenerationCounter.load(std::memory_order_relaxed); +#endif +} + const void *llvm::SavePrettyStackState() { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES return PrettyStackTraceHead; #else return nullptr; @@ -199,7 +257,7 @@ const void *llvm::SavePrettyStackState() { } void llvm::RestorePrettyStackState(const void *Top) { -#if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES +#if ENABLE_BACKTRACES PrettyStackTraceHead = static_cast<PrettyStackTraceEntry *>(const_cast<void *>(Top)); #endif |