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