1//===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines some helpful functions for dealing with the possibility of
11// Unix signals occurring while your program is running.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/Config/config.h"     // Get autoconf configuration settings
16#include "llvm/Support/PrettyStackTrace.h"
17#include "llvm/Support/raw_ostream.h"
18#include "llvm/Support/Signals.h"
19#include "llvm/Support/ThreadLocal.h"
20#include "llvm/ADT/SmallString.h"
21
22#ifdef HAVE_CRASHREPORTERCLIENT_H
23#include <CrashReporterClient.h>
24#endif
25
26using namespace llvm;
27
28namespace llvm {
29  bool DisablePrettyStackTrace = false;
30}
31
32// FIXME: This should be thread local when llvm supports threads.
33static sys::ThreadLocal<const PrettyStackTraceEntry> PrettyStackTraceHead;
34
35static unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){
36  unsigned NextID = 0;
37  if (Entry->getNextEntry())
38    NextID = PrintStack(Entry->getNextEntry(), OS);
39  OS << NextID << ".\t";
40  Entry->print(OS);
41
42  return NextID+1;
43}
44
45/// PrintCurStackTrace - Print the current stack trace to the specified stream.
46static void PrintCurStackTrace(raw_ostream &OS) {
47  // Don't print an empty trace.
48  if (PrettyStackTraceHead.get() == 0) return;
49
50  // If there are pretty stack frames registered, walk and emit them.
51  OS << "Stack dump:\n";
52
53  PrintStack(PrettyStackTraceHead.get(), OS);
54  OS.flush();
55}
56
57// Integrate with crash reporter libraries.
58#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H
59//  If any clients of llvm try to link to libCrashReporterClient.a themselves,
60//  only one crash info struct will be used.
61extern "C" {
62CRASH_REPORTER_CLIENT_HIDDEN
63struct crashreporter_annotations_t gCRAnnotations
64        __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
65        = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
66}
67#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO
68static const char *__crashreporter_info__ = 0;
69asm(".desc ___crashreporter_info__, 0x10");
70#endif
71
72
73/// CrashHandler - This callback is run if a fatal signal is delivered to the
74/// process, it prints the pretty stack trace.
75static void CrashHandler(void *) {
76#ifndef __APPLE__
77  // On non-apple systems, just emit the crash stack trace to stderr.
78  PrintCurStackTrace(errs());
79#else
80  // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also
81  // put it into __crashreporter_info__.
82  SmallString<2048> TmpStr;
83  {
84    raw_svector_ostream Stream(TmpStr);
85    PrintCurStackTrace(Stream);
86  }
87
88  if (!TmpStr.empty()) {
89#ifdef HAVE_CRASHREPORTERCLIENT_H
90    // Cast to void to avoid warning.
91    (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str());
92#elif HAVE_CRASHREPORTER_INFO
93    __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str());
94#endif
95    errs() << TmpStr.str();
96  }
97
98#endif
99}
100
101static bool RegisterCrashPrinter() {
102  if (!DisablePrettyStackTrace)
103    sys::AddSignalHandler(CrashHandler, 0);
104  return false;
105}
106
107PrettyStackTraceEntry::PrettyStackTraceEntry() {
108  // The first time this is called, we register the crash printer.
109  static bool HandlerRegistered = RegisterCrashPrinter();
110  (void)HandlerRegistered;
111
112  // Link ourselves.
113  NextEntry = PrettyStackTraceHead.get();
114  PrettyStackTraceHead.set(this);
115}
116
117PrettyStackTraceEntry::~PrettyStackTraceEntry() {
118  assert(PrettyStackTraceHead.get() == this &&
119         "Pretty stack trace entry destruction is out of order");
120  PrettyStackTraceHead.set(getNextEntry());
121}
122
123void PrettyStackTraceString::print(raw_ostream &OS) const {
124  OS << Str << "\n";
125}
126
127void PrettyStackTraceProgram::print(raw_ostream &OS) const {
128  OS << "Program arguments: ";
129  // Print the argument list.
130  for (unsigned i = 0, e = ArgC; i != e; ++i)
131    OS << ArgV[i] << ' ';
132  OS << '\n';
133}
134