1193323Sed//===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===// 2193323Sed// 3193323Sed// The LLVM Compiler Infrastructure 4193323Sed// 5193323Sed// This file is distributed under the University of Illinois Open Source 6193323Sed// License. See LICENSE.TXT for details. 7193323Sed// 8193323Sed//===----------------------------------------------------------------------===// 9193323Sed// 10193323Sed// This file defines some helpful functions for dealing with the possibility of 11221345Sdim// Unix signals occurring while your program is running. 12193323Sed// 13193323Sed//===----------------------------------------------------------------------===// 14193323Sed 15249423Sdim#include "llvm/Support/PrettyStackTrace.h" 16249423Sdim#include "llvm/ADT/SmallString.h" 17210299Sed#include "llvm/Config/config.h" // Get autoconf configuration settings 18263508Sdim#include "llvm/Support/ManagedStatic.h" 19218893Sdim#include "llvm/Support/Signals.h" 20218893Sdim#include "llvm/Support/ThreadLocal.h" 21249423Sdim#include "llvm/Support/Watchdog.h" 22249423Sdim#include "llvm/Support/raw_ostream.h" 23263508Sdim#include "llvm-c/Core.h" 24210299Sed 25210299Sed#ifdef HAVE_CRASHREPORTERCLIENT_H 26210299Sed#include <CrashReporterClient.h> 27210299Sed#endif 28210299Sed 29193323Sedusing namespace llvm; 30193323Sed 31263508Sdimstatic ManagedStatic<sys::ThreadLocal<const PrettyStackTraceEntry> > PrettyStackTraceHead; 32198090Srdivacky 33193323Sedstatic unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){ 34193323Sed unsigned NextID = 0; 35193323Sed if (Entry->getNextEntry()) 36193323Sed NextID = PrintStack(Entry->getNextEntry(), OS); 37193323Sed OS << NextID << ".\t"; 38249423Sdim { 39249423Sdim sys::Watchdog W(5); 40249423Sdim Entry->print(OS); 41249423Sdim } 42193323Sed 43193323Sed return NextID+1; 44193323Sed} 45193323Sed 46193323Sed/// PrintCurStackTrace - Print the current stack trace to the specified stream. 47193323Sedstatic void PrintCurStackTrace(raw_ostream &OS) { 48193323Sed // Don't print an empty trace. 49263508Sdim if (PrettyStackTraceHead->get() == 0) return; 50193323Sed 51193323Sed // If there are pretty stack frames registered, walk and emit them. 52193323Sed OS << "Stack dump:\n"; 53193323Sed 54263508Sdim PrintStack(PrettyStackTraceHead->get(), OS); 55193323Sed OS.flush(); 56193323Sed} 57193323Sed 58210299Sed// Integrate with crash reporter libraries. 59218893Sdim#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H 60210299Sed// If any clients of llvm try to link to libCrashReporterClient.a themselves, 61210299Sed// only one crash info struct will be used. 62210299Sedextern "C" { 63210299SedCRASH_REPORTER_CLIENT_HIDDEN 64210299Sedstruct crashreporter_annotations_t gCRAnnotations 65210299Sed __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) 66226633Sdim = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 }; 67210299Sed} 68218893Sdim#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO 69208599Srdivackystatic const char *__crashreporter_info__ = 0; 70208599Srdivackyasm(".desc ___crashreporter_info__, 0x10"); 71193323Sed#endif 72193323Sed 73193323Sed 74193323Sed/// CrashHandler - This callback is run if a fatal signal is delivered to the 75193323Sed/// process, it prints the pretty stack trace. 76212904Sdimstatic void CrashHandler(void *) { 77193323Sed#ifndef __APPLE__ 78193323Sed // On non-apple systems, just emit the crash stack trace to stderr. 79193323Sed PrintCurStackTrace(errs()); 80193323Sed#else 81193323Sed // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also 82193323Sed // put it into __crashreporter_info__. 83193323Sed SmallString<2048> TmpStr; 84193323Sed { 85193323Sed raw_svector_ostream Stream(TmpStr); 86193323Sed PrintCurStackTrace(Stream); 87193323Sed } 88193323Sed 89193323Sed if (!TmpStr.empty()) { 90218893Sdim#ifdef HAVE_CRASHREPORTERCLIENT_H 91212904Sdim // Cast to void to avoid warning. 92212904Sdim (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); 93218893Sdim#elif HAVE_CRASHREPORTER_INFO 94218893Sdim __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); 95210299Sed#endif 96198090Srdivacky errs() << TmpStr.str(); 97193323Sed } 98193323Sed 99193323Sed#endif 100193323Sed} 101193323Sed 102193323SedPrettyStackTraceEntry::PrettyStackTraceEntry() { 103193323Sed // Link ourselves. 104263508Sdim NextEntry = PrettyStackTraceHead->get(); 105263508Sdim PrettyStackTraceHead->set(this); 106193323Sed} 107193323Sed 108193323SedPrettyStackTraceEntry::~PrettyStackTraceEntry() { 109263508Sdim // Do nothing if PrettyStackTraceHead is uninitialized. This can only happen 110263508Sdim // if a shutdown occurred after we created the PrettyStackTraceEntry. That 111263508Sdim // does occur in the following idiom: 112263508Sdim // 113263508Sdim // PrettyStackTraceProgram X(...); 114263508Sdim // llvm_shutdown_obj Y; 115263508Sdim // 116263508Sdim // Without this check, we may end up removing ourselves from the stack trace 117263508Sdim // after PrettyStackTraceHead has already been destroyed. 118263508Sdim if (!PrettyStackTraceHead.isConstructed()) 119263508Sdim return; 120263508Sdim 121263508Sdim assert(PrettyStackTraceHead->get() == this && 122193323Sed "Pretty stack trace entry destruction is out of order"); 123263508Sdim PrettyStackTraceHead->set(getNextEntry()); 124193323Sed} 125193323Sed 126193323Sedvoid PrettyStackTraceString::print(raw_ostream &OS) const { 127193323Sed OS << Str << "\n"; 128193323Sed} 129193323Sed 130193323Sedvoid PrettyStackTraceProgram::print(raw_ostream &OS) const { 131193323Sed OS << "Program arguments: "; 132193323Sed // Print the argument list. 133193323Sed for (unsigned i = 0, e = ArgC; i != e; ++i) 134193323Sed OS << ArgV[i] << ' '; 135193323Sed OS << '\n'; 136193323Sed} 137263508Sdim 138263508Sdimstatic bool RegisterCrashPrinter() { 139263508Sdim sys::AddSignalHandler(CrashHandler, 0); 140263508Sdim return false; 141263508Sdim} 142263508Sdim 143263508Sdimvoid llvm::EnablePrettyStackTrace() { 144263508Sdim // The first time this is called, we register the crash printer. 145263508Sdim static bool HandlerRegistered = RegisterCrashPrinter(); 146263508Sdim (void)HandlerRegistered; 147263508Sdim} 148263508Sdim 149263508Sdimvoid LLVMEnablePrettyStackTrace() { 150263508Sdim EnablePrettyStackTrace(); 151263508Sdim} 152