PrettyStackTrace.cpp revision 226633
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
15210299Sed#include "llvm/Config/config.h"     // Get autoconf configuration settings
16193323Sed#include "llvm/Support/PrettyStackTrace.h"
17193323Sed#include "llvm/Support/raw_ostream.h"
18218893Sdim#include "llvm/Support/Signals.h"
19218893Sdim#include "llvm/Support/ThreadLocal.h"
20193323Sed#include "llvm/ADT/SmallString.h"
21210299Sed
22210299Sed#ifdef HAVE_CRASHREPORTERCLIENT_H
23210299Sed#include <CrashReporterClient.h>
24210299Sed#endif
25210299Sed
26193323Sedusing namespace llvm;
27193323Sed
28198090Srdivackynamespace llvm {
29198090Srdivacky  bool DisablePrettyStackTrace = false;
30198090Srdivacky}
31198090Srdivacky
32193323Sed// FIXME: This should be thread local when llvm supports threads.
33195098Sedstatic sys::ThreadLocal<const PrettyStackTraceEntry> PrettyStackTraceHead;
34193323Sed
35193323Sedstatic unsigned PrintStack(const PrettyStackTraceEntry *Entry, raw_ostream &OS){
36193323Sed  unsigned NextID = 0;
37193323Sed  if (Entry->getNextEntry())
38193323Sed    NextID = PrintStack(Entry->getNextEntry(), OS);
39193323Sed  OS << NextID << ".\t";
40193323Sed  Entry->print(OS);
41193323Sed
42193323Sed  return NextID+1;
43193323Sed}
44193323Sed
45193323Sed/// PrintCurStackTrace - Print the current stack trace to the specified stream.
46193323Sedstatic void PrintCurStackTrace(raw_ostream &OS) {
47193323Sed  // Don't print an empty trace.
48195098Sed  if (PrettyStackTraceHead.get() == 0) return;
49193323Sed
50193323Sed  // If there are pretty stack frames registered, walk and emit them.
51193323Sed  OS << "Stack dump:\n";
52193323Sed
53195098Sed  PrintStack(PrettyStackTraceHead.get(), OS);
54193323Sed  OS.flush();
55193323Sed}
56193323Sed
57210299Sed// Integrate with crash reporter libraries.
58218893Sdim#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H
59210299Sed//  If any clients of llvm try to link to libCrashReporterClient.a themselves,
60210299Sed//  only one crash info struct will be used.
61210299Sedextern "C" {
62210299SedCRASH_REPORTER_CLIENT_HIDDEN
63210299Sedstruct crashreporter_annotations_t gCRAnnotations
64210299Sed        __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
65226633Sdim        = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
66210299Sed}
67218893Sdim#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO
68208599Srdivackystatic const char *__crashreporter_info__ = 0;
69208599Srdivackyasm(".desc ___crashreporter_info__, 0x10");
70193323Sed#endif
71193323Sed
72193323Sed
73193323Sed/// CrashHandler - This callback is run if a fatal signal is delivered to the
74193323Sed/// process, it prints the pretty stack trace.
75212904Sdimstatic void CrashHandler(void *) {
76193323Sed#ifndef __APPLE__
77193323Sed  // On non-apple systems, just emit the crash stack trace to stderr.
78193323Sed  PrintCurStackTrace(errs());
79193323Sed#else
80193323Sed  // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also
81193323Sed  // put it into __crashreporter_info__.
82193323Sed  SmallString<2048> TmpStr;
83193323Sed  {
84193323Sed    raw_svector_ostream Stream(TmpStr);
85193323Sed    PrintCurStackTrace(Stream);
86193323Sed  }
87193323Sed
88193323Sed  if (!TmpStr.empty()) {
89218893Sdim#ifdef HAVE_CRASHREPORTERCLIENT_H
90212904Sdim    // Cast to void to avoid warning.
91212904Sdim    (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str());
92218893Sdim#elif HAVE_CRASHREPORTER_INFO
93218893Sdim    __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str());
94210299Sed#endif
95198090Srdivacky    errs() << TmpStr.str();
96193323Sed  }
97193323Sed
98193323Sed#endif
99193323Sed}
100193323Sed
101193323Sedstatic bool RegisterCrashPrinter() {
102198090Srdivacky  if (!DisablePrettyStackTrace)
103198090Srdivacky    sys::AddSignalHandler(CrashHandler, 0);
104193323Sed  return false;
105193323Sed}
106193323Sed
107193323SedPrettyStackTraceEntry::PrettyStackTraceEntry() {
108193323Sed  // The first time this is called, we register the crash printer.
109193323Sed  static bool HandlerRegistered = RegisterCrashPrinter();
110218893Sdim  (void)HandlerRegistered;
111193323Sed
112193323Sed  // Link ourselves.
113195098Sed  NextEntry = PrettyStackTraceHead.get();
114195098Sed  PrettyStackTraceHead.set(this);
115193323Sed}
116193323Sed
117193323SedPrettyStackTraceEntry::~PrettyStackTraceEntry() {
118195098Sed  assert(PrettyStackTraceHead.get() == this &&
119193323Sed         "Pretty stack trace entry destruction is out of order");
120195098Sed  PrettyStackTraceHead.set(getNextEntry());
121193323Sed}
122193323Sed
123193323Sedvoid PrettyStackTraceString::print(raw_ostream &OS) const {
124193323Sed  OS << Str << "\n";
125193323Sed}
126193323Sed
127193323Sedvoid PrettyStackTraceProgram::print(raw_ostream &OS) const {
128193323Sed  OS << "Program arguments: ";
129193323Sed  // Print the argument list.
130193323Sed  for (unsigned i = 0, e = ArgC; i != e; ++i)
131193323Sed    OS << ArgV[i] << ' ';
132193323Sed  OS << '\n';
133193323Sed}
134