brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.8 KiB · eff9947 Raw
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