339 lines · cpp
1//===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines some helpful functions for dealing with the possibility of10// Unix signals occurring while your program is running.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Support/PrettyStackTrace.h"15#include "llvm-c/ErrorHandling.h"16#include "llvm/Config/config.h"17#include "llvm/Support/Compiler.h"18#include "llvm/Support/SaveAndRestore.h"19#include "llvm/Support/Signals.h"20#include "llvm/Support/Watchdog.h"21#include "llvm/Support/raw_ostream.h"22 23#ifdef __APPLE__24#include "llvm/ADT/SmallString.h"25#endif26 27#include <atomic>28#include <cassert>29#include <cstdarg>30#include <cstdio>31#include <cstring>32#include <tuple>33 34#ifdef HAVE_CRASHREPORTERCLIENT_H35#include <CrashReporterClient.h>36#endif37 38using namespace llvm;39 40static const char *BugReportMsg =41 "PLEASE submit a bug report to " BUG_REPORT_URL42 " and include the crash backtrace and instructions to reproduce the bug.\n";43 44// If backtrace support is not enabled, compile out support for pretty stack45// traces. This has the secondary effect of not requiring thread local storage46// when backtrace support is disabled.47#if ENABLE_BACKTRACES48 49// We need a thread local pointer to manage the stack of our stack trace50// objects, but we *really* cannot tolerate destructors running and do not want51// to pay any overhead of synchronizing. As a consequence, we use a raw52// thread-local variable.53static LLVM_THREAD_LOCAL PrettyStackTraceEntry *PrettyStackTraceHead = nullptr;54 55// The use of 'volatile' here is to ensure that any particular thread always56// reloads the value of the counter. The 'std::atomic' allows us to specify that57// this variable is accessed in an unsychronized way (it's not actually58// synchronizing). This does technically mean that the value may not appear to59// be the same across threads running simultaneously on different CPUs, but in60// practice the worst that will happen is that we won't print a stack trace when61// we could have.62//63// This is initialized to 1 because 0 is used as a sentinel for "not enabled on64// the current thread". If the user happens to overflow an 'unsigned' with65// SIGINFO requests, it's possible that some threads will stop responding to it,66// but the program won't crash.67static volatile std::atomic<unsigned> GlobalSigInfoGenerationCounter = 1;68static LLVM_THREAD_LOCAL unsigned ThreadLocalSigInfoGenerationCounter = 0;69 70namespace llvm {71PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *Head) {72 PrettyStackTraceEntry *Prev = nullptr;73 while (Head)74 std::tie(Prev, Head, Head->NextEntry) =75 std::make_tuple(Head, Head->NextEntry, Prev);76 return Prev;77}78} // namespace llvm79 80static void PrintStack(raw_ostream &OS) {81 // Print out the stack in reverse order. To avoid recursion (which is likely82 // to fail if we crashed due to stack overflow), we do an up-front pass to83 // reverse the stack, then print it, then reverse it again.84 unsigned ID = 0;85 SaveAndRestore<PrettyStackTraceEntry *> SavedStack{PrettyStackTraceHead,86 nullptr};87 PrettyStackTraceEntry *ReversedStack = ReverseStackTrace(SavedStack.get());88 for (const PrettyStackTraceEntry *Entry = ReversedStack; Entry;89 Entry = Entry->getNextEntry()) {90 OS << ID++ << ".\t";91 sys::Watchdog W(5);92 Entry->print(OS);93 }94 llvm::ReverseStackTrace(ReversedStack);95}96 97/// Print the current stack trace to the specified stream.98///99/// Marked NOINLINE so it can be called from debuggers.100LLVM_ATTRIBUTE_NOINLINE101static void PrintCurStackTrace(raw_ostream &OS) {102 // Don't print an empty trace.103 if (!PrettyStackTraceHead) return;104 105 // If there are pretty stack frames registered, walk and emit them.106 OS << "Stack dump:\n";107 108 PrintStack(OS);109 OS.flush();110}111 112// Integrate with crash reporter libraries.113#if defined (__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H)114// If any clients of llvm try to link to libCrashReporterClient.a themselves,115// only one crash info struct will be used.116extern "C" {117#ifdef CRASHREPORTER_ANNOTATIONS_INITIALIZER118// Should be available in CRASHREPORTER_ANNOTATIONS_VERSION > 5119CRASHREPORTER_ANNOTATIONS_INITIALIZER()120#else121// Older CrashReporter annotations layouts122CRASH_REPORTER_CLIENT_HIDDEN123struct crashreporter_annotations_t gCRAnnotations124 __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {125 CRASHREPORTER_ANNOTATIONS_VERSION,126 0,127 0,128 0,129 0,130 0,131 0,132#if CRASHREPORTER_ANNOTATIONS_VERSION > 4133 0134#endif // CRASHREPORTER_ANNOTATIONS_VERSION > 4135};136#endif // CRASHREPORTER_ANNOTATIONS_INITIALIZER137} // extern "C"138#elif defined(__APPLE__) && HAVE_CRASHREPORTER_INFO139extern "C" const char *__crashreporter_info__140 __attribute__((visibility("hidden"))) = 0;141asm(".desc ___crashreporter_info__, 0x10");142#endif143 144[[maybe_unused]] static void setCrashLogMessage(const char *msg);145static void setCrashLogMessage(const char *msg) {146#ifdef HAVE_CRASHREPORTERCLIENT_H147 (void)CRSetCrashLogMessage(msg);148#elif HAVE_CRASHREPORTER_INFO149 __crashreporter_info__ = msg;150#endif151 // Don't reorder subsequent operations: whatever comes after might crash and152 // we want the system crash handling to see the message we just set.153 std::atomic_signal_fence(std::memory_order_seq_cst);154}155 156#ifdef __APPLE__157using CrashHandlerString = SmallString<2048>;158using CrashHandlerStringStorage = std::byte[sizeof(CrashHandlerString)];159alignas(CrashHandlerString) static CrashHandlerStringStorage160 crashHandlerStringStorage;161#endif162 163/// This callback is run if a fatal signal is delivered to the process, it164/// prints the pretty stack trace.165static void CrashHandler(void *) {166 errs() << BugReportMsg ;167 168#ifndef __APPLE__169 // On non-apple systems, just emit the crash stack trace to stderr.170 PrintCurStackTrace(errs());171#else172 // Emit the crash stack trace to a SmallString, put it where the system crash173 // handling will find it, and also send it to stderr.174 //175 // The SmallString is fairly large in the hope that we don't allocate (we're176 // handling a fatal signal, something is already pretty wrong, allocation177 // might not work). Further, we don't use a magic static in case that's also178 // borked. We leak any allocation that does occur because the program is about179 // to die anyways. This is technically racy if we were handling two fatal180 // signals, however if we're in that situation a race is the least of our181 // worries.182 auto &crashHandlerString =183 *new (&crashHandlerStringStorage) CrashHandlerString;184 185 // If we crash while trying to print the stack trace, we still want the system186 // crash handling to have some partial information. That'll work out as long187 // as the SmallString doesn't allocate. If it does allocate then the system188 // crash handling will see some garbage because the inline buffer now contains189 // a pointer.190 setCrashLogMessage(crashHandlerString.c_str());191 192 {193 raw_svector_ostream Stream(crashHandlerString);194 PrintCurStackTrace(Stream);195 }196 197 if (!crashHandlerString.empty()) {198 setCrashLogMessage(crashHandlerString.c_str());199 errs() << crashHandlerString.str();200 } else {201 setCrashLogMessage("No crash information.");202 }203#endif204}205 206static void printForSigInfoIfNeeded() {207 unsigned CurrentSigInfoGeneration =208 GlobalSigInfoGenerationCounter.load(std::memory_order_relaxed);209 if (ThreadLocalSigInfoGenerationCounter == 0 ||210 ThreadLocalSigInfoGenerationCounter == CurrentSigInfoGeneration) {211 return;212 }213 214 PrintCurStackTrace(errs());215 ThreadLocalSigInfoGenerationCounter = CurrentSigInfoGeneration;216}217 218#endif // ENABLE_BACKTRACES219 220void llvm::setBugReportMsg(const char *Msg) {221 BugReportMsg = Msg;222}223 224const char *llvm::getBugReportMsg() {225 return BugReportMsg;226}227 228PrettyStackTraceEntry::PrettyStackTraceEntry() {229#if ENABLE_BACKTRACES230 // Handle SIGINFO first, because we haven't finished constructing yet.231 printForSigInfoIfNeeded();232 // Link ourselves.233 NextEntry = PrettyStackTraceHead;234 PrettyStackTraceHead = this;235#endif236}237 238PrettyStackTraceEntry::~PrettyStackTraceEntry() {239#if ENABLE_BACKTRACES240 assert(PrettyStackTraceHead == this &&241 "Pretty stack trace entry destruction is out of order");242 PrettyStackTraceHead = NextEntry;243 // Handle SIGINFO first, because we already started destructing.244 printForSigInfoIfNeeded();245#endif246}247 248void PrettyStackTraceString::print(raw_ostream &OS) const { OS << Str << "\n"; }249 250PrettyStackTraceFormat::PrettyStackTraceFormat(const char *Format, ...) {251 va_list AP;252 va_start(AP, Format);253 const int SizeOrError = vsnprintf(nullptr, 0, Format, AP);254 va_end(AP);255 if (SizeOrError < 0) {256 return;257 }258 259 const int Size = SizeOrError + 1; // '\0'260 Str.resize(Size);261 va_start(AP, Format);262 vsnprintf(Str.data(), Size, Format, AP);263 va_end(AP);264}265 266void PrettyStackTraceFormat::print(raw_ostream &OS) const { OS << Str << "\n"; }267 268void PrettyStackTraceProgram::print(raw_ostream &OS) const {269 OS << "Program arguments: ";270 // Print the argument list.271 for (int I = 0; I < ArgC; ++I) {272 const bool HaveSpace = ::strchr(ArgV[I], ' ');273 if (I)274 OS << ' ';275 if (HaveSpace)276 OS << '"';277 OS.write_escaped(ArgV[I]);278 if (HaveSpace)279 OS << '"';280 }281 OS << '\n';282}283 284#if ENABLE_BACKTRACES285static bool RegisterCrashPrinter() {286 sys::AddSignalHandler(CrashHandler, nullptr);287 return false;288}289#endif290 291void llvm::EnablePrettyStackTrace() {292#if ENABLE_BACKTRACES293 // The first time this is called, we register the crash printer.294 static bool HandlerRegistered = RegisterCrashPrinter();295 (void)HandlerRegistered;296#endif297}298 299void llvm::EnablePrettyStackTraceOnSigInfoForThisThread(bool ShouldEnable) {300#if ENABLE_BACKTRACES301 if (!ShouldEnable) {302 ThreadLocalSigInfoGenerationCounter = 0;303 return;304 }305 306 // The first time this is called, we register the SIGINFO handler.307 static bool HandlerRegistered = []{308 sys::SetInfoSignalFunction([]{309 GlobalSigInfoGenerationCounter.fetch_add(1, std::memory_order_relaxed);310 });311 return false;312 }();313 (void)HandlerRegistered;314 315 // Next, enable it for the current thread.316 ThreadLocalSigInfoGenerationCounter =317 GlobalSigInfoGenerationCounter.load(std::memory_order_relaxed);318#endif319}320 321const void *llvm::SavePrettyStackState() {322#if ENABLE_BACKTRACES323 return PrettyStackTraceHead;324#else325 return nullptr;326#endif327}328 329void llvm::RestorePrettyStackState(const void *Top) {330#if ENABLE_BACKTRACES331 PrettyStackTraceHead =332 static_cast<PrettyStackTraceEntry *>(const_cast<void *>(Top));333#endif334}335 336void LLVMEnablePrettyStackTrace() {337 EnablePrettyStackTrace();338}339