1f22ef01cSRoman Divacky //===- PrettyStackTrace.cpp - Pretty Crash Handling -----------------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky // The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10f22ef01cSRoman Divacky // This file defines some helpful functions for dealing with the possibility of
113b0f4066SDimitry Andric // Unix signals occurring while your program is running.
12f22ef01cSRoman Divacky //
13f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
14f22ef01cSRoman Divacky
15f22ef01cSRoman Divacky #include "llvm/Support/PrettyStackTrace.h"
167d523365SDimitry Andric #include "llvm-c/ErrorHandling.h"
17139f7f9bSDimitry Andric #include "llvm/ADT/SmallString.h"
18139f7f9bSDimitry Andric #include "llvm/Config/config.h" // Get autoconf configuration settings
19ff0cc061SDimitry Andric #include "llvm/Support/Compiler.h"
202754fe60SDimitry Andric #include "llvm/Support/Signals.h"
21139f7f9bSDimitry Andric #include "llvm/Support/Watchdog.h"
22139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h"
23ffd1746dSEd Schouten
24d88c1a5aSDimitry Andric #include <cstdarg>
25f37b6182SDimitry Andric #include <cstdio>
263ca95b02SDimitry Andric #include <tuple>
273ca95b02SDimitry Andric
28ffd1746dSEd Schouten #ifdef HAVE_CRASHREPORTERCLIENT_H
29ffd1746dSEd Schouten #include <CrashReporterClient.h>
30ffd1746dSEd Schouten #endif
31ffd1746dSEd Schouten
32f22ef01cSRoman Divacky using namespace llvm;
33f22ef01cSRoman Divacky
34ff0cc061SDimitry Andric // If backtrace support is not enabled, compile out support for pretty stack
35ff0cc061SDimitry Andric // traces. This has the secondary effect of not requiring thread local storage
36ff0cc061SDimitry Andric // when backtrace support is disabled.
37d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
38ff0cc061SDimitry Andric
39ff0cc061SDimitry Andric // We need a thread local pointer to manage the stack of our stack trace
40ff0cc061SDimitry Andric // objects, but we *really* cannot tolerate destructors running and do not want
41ff0cc061SDimitry Andric // to pay any overhead of synchronizing. As a consequence, we use a raw
42ff0cc061SDimitry Andric // thread-local variable.
433ca95b02SDimitry Andric static LLVM_THREAD_LOCAL PrettyStackTraceEntry *PrettyStackTraceHead = nullptr;
44f22ef01cSRoman Divacky
453ca95b02SDimitry Andric namespace llvm {
ReverseStackTrace(PrettyStackTraceEntry * Head)463ca95b02SDimitry Andric PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *Head) {
473ca95b02SDimitry Andric PrettyStackTraceEntry *Prev = nullptr;
483ca95b02SDimitry Andric while (Head)
493ca95b02SDimitry Andric std::tie(Prev, Head, Head->NextEntry) =
503ca95b02SDimitry Andric std::make_tuple(Head, Head->NextEntry, Prev);
513ca95b02SDimitry Andric return Prev;
523ca95b02SDimitry Andric }
533ca95b02SDimitry Andric }
543ca95b02SDimitry Andric
PrintStack(raw_ostream & OS)553ca95b02SDimitry Andric static void PrintStack(raw_ostream &OS) {
563ca95b02SDimitry Andric // Print out the stack in reverse order. To avoid recursion (which is likely
573ca95b02SDimitry Andric // to fail if we crashed due to stack overflow), we do an up-front pass to
583ca95b02SDimitry Andric // reverse the stack, then print it, then reverse it again.
593ca95b02SDimitry Andric unsigned ID = 0;
603ca95b02SDimitry Andric PrettyStackTraceEntry *ReversedStack =
613ca95b02SDimitry Andric llvm::ReverseStackTrace(PrettyStackTraceHead);
623ca95b02SDimitry Andric for (const PrettyStackTraceEntry *Entry = ReversedStack; Entry;
633ca95b02SDimitry Andric Entry = Entry->getNextEntry()) {
643ca95b02SDimitry Andric OS << ID++ << ".\t";
65139f7f9bSDimitry Andric sys::Watchdog W(5);
66f22ef01cSRoman Divacky Entry->print(OS);
67139f7f9bSDimitry Andric }
683ca95b02SDimitry Andric llvm::ReverseStackTrace(ReversedStack);
69f22ef01cSRoman Divacky }
70f22ef01cSRoman Divacky
71f22ef01cSRoman Divacky /// PrintCurStackTrace - Print the current stack trace to the specified stream.
PrintCurStackTrace(raw_ostream & OS)72f22ef01cSRoman Divacky static void PrintCurStackTrace(raw_ostream &OS) {
73f22ef01cSRoman Divacky // Don't print an empty trace.
74ff0cc061SDimitry Andric if (!PrettyStackTraceHead) return;
75f22ef01cSRoman Divacky
76f22ef01cSRoman Divacky // If there are pretty stack frames registered, walk and emit them.
77f22ef01cSRoman Divacky OS << "Stack dump:\n";
78f22ef01cSRoman Divacky
793ca95b02SDimitry Andric PrintStack(OS);
80f22ef01cSRoman Divacky OS.flush();
81f22ef01cSRoman Divacky }
82f22ef01cSRoman Divacky
83ffd1746dSEd Schouten // Integrate with crash reporter libraries.
84d88c1a5aSDimitry Andric #if defined (__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H)
85ffd1746dSEd Schouten // If any clients of llvm try to link to libCrashReporterClient.a themselves,
86ffd1746dSEd Schouten // only one crash info struct will be used.
87ffd1746dSEd Schouten extern "C" {
88ffd1746dSEd Schouten CRASH_REPORTER_CLIENT_HIDDEN
89ffd1746dSEd Schouten struct crashreporter_annotations_t gCRAnnotations
90ffd1746dSEd Schouten __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
91*4ba319b5SDimitry Andric #if CRASHREPORTER_ANNOTATIONS_VERSION < 5
926122f3e6SDimitry Andric = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
93*4ba319b5SDimitry Andric #else
94*4ba319b5SDimitry Andric = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0, 0 };
95*4ba319b5SDimitry Andric #endif
96ffd1746dSEd Schouten }
972754fe60SDimitry Andric #elif defined(__APPLE__) && HAVE_CRASHREPORTER_INFO
98d88c1a5aSDimitry Andric extern "C" const char *__crashreporter_info__
99d88c1a5aSDimitry Andric __attribute__((visibility("hidden"))) = 0;
100f22ef01cSRoman Divacky asm(".desc ___crashreporter_info__, 0x10");
101f22ef01cSRoman Divacky #endif
102f22ef01cSRoman Divacky
103f22ef01cSRoman Divacky /// CrashHandler - This callback is run if a fatal signal is delivered to the
104f22ef01cSRoman Divacky /// process, it prints the pretty stack trace.
CrashHandler(void *)105e580952dSDimitry Andric static void CrashHandler(void *) {
106f22ef01cSRoman Divacky #ifndef __APPLE__
107f22ef01cSRoman Divacky // On non-apple systems, just emit the crash stack trace to stderr.
108f22ef01cSRoman Divacky PrintCurStackTrace(errs());
109f22ef01cSRoman Divacky #else
110f22ef01cSRoman Divacky // Otherwise, emit to a smallvector of chars, send *that* to stderr, but also
111f22ef01cSRoman Divacky // put it into __crashreporter_info__.
112f22ef01cSRoman Divacky SmallString<2048> TmpStr;
113f22ef01cSRoman Divacky {
114f22ef01cSRoman Divacky raw_svector_ostream Stream(TmpStr);
115f22ef01cSRoman Divacky PrintCurStackTrace(Stream);
116f22ef01cSRoman Divacky }
117f22ef01cSRoman Divacky
118f22ef01cSRoman Divacky if (!TmpStr.empty()) {
1192754fe60SDimitry Andric #ifdef HAVE_CRASHREPORTERCLIENT_H
120e580952dSDimitry Andric // Cast to void to avoid warning.
121*4ba319b5SDimitry Andric (void)CRSetCrashLogMessage(TmpStr.c_str());
1222754fe60SDimitry Andric #elif HAVE_CRASHREPORTER_INFO
123*4ba319b5SDimitry Andric __crashreporter_info__ = strdup(TmpStr.c_str());
124ffd1746dSEd Schouten #endif
125f22ef01cSRoman Divacky errs() << TmpStr.str();
126f22ef01cSRoman Divacky }
127f22ef01cSRoman Divacky
128f22ef01cSRoman Divacky #endif
129f22ef01cSRoman Divacky }
130f22ef01cSRoman Divacky
131d88c1a5aSDimitry Andric // defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
132ff0cc061SDimitry Andric #endif
133ff0cc061SDimitry Andric
PrettyStackTraceEntry()134f22ef01cSRoman Divacky PrettyStackTraceEntry::PrettyStackTraceEntry() {
135d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
136f22ef01cSRoman Divacky // Link ourselves.
137ff0cc061SDimitry Andric NextEntry = PrettyStackTraceHead;
138ff0cc061SDimitry Andric PrettyStackTraceHead = this;
139ff0cc061SDimitry Andric #endif
140f22ef01cSRoman Divacky }
141f22ef01cSRoman Divacky
~PrettyStackTraceEntry()142f22ef01cSRoman Divacky PrettyStackTraceEntry::~PrettyStackTraceEntry() {
143d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
144ff0cc061SDimitry Andric assert(PrettyStackTraceHead == this &&
145f22ef01cSRoman Divacky "Pretty stack trace entry destruction is out of order");
1463ca95b02SDimitry Andric PrettyStackTraceHead = NextEntry;
147ff0cc061SDimitry Andric #endif
148f22ef01cSRoman Divacky }
149f22ef01cSRoman Divacky
print(raw_ostream & OS) const150d88c1a5aSDimitry Andric void PrettyStackTraceString::print(raw_ostream &OS) const { OS << Str << "\n"; }
151d88c1a5aSDimitry Andric
PrettyStackTraceFormat(const char * Format,...)152d88c1a5aSDimitry Andric PrettyStackTraceFormat::PrettyStackTraceFormat(const char *Format, ...) {
153d88c1a5aSDimitry Andric va_list AP;
154d88c1a5aSDimitry Andric va_start(AP, Format);
155d88c1a5aSDimitry Andric const int SizeOrError = vsnprintf(nullptr, 0, Format, AP);
156d88c1a5aSDimitry Andric va_end(AP);
157d88c1a5aSDimitry Andric if (SizeOrError < 0) {
158d88c1a5aSDimitry Andric return;
159f22ef01cSRoman Divacky }
160f22ef01cSRoman Divacky
161d88c1a5aSDimitry Andric const int Size = SizeOrError + 1; // '\0'
162d88c1a5aSDimitry Andric Str.resize(Size);
163d88c1a5aSDimitry Andric va_start(AP, Format);
164d88c1a5aSDimitry Andric vsnprintf(Str.data(), Size, Format, AP);
165d88c1a5aSDimitry Andric va_end(AP);
166d88c1a5aSDimitry Andric }
167d88c1a5aSDimitry Andric
print(raw_ostream & OS) const168d88c1a5aSDimitry Andric void PrettyStackTraceFormat::print(raw_ostream &OS) const { OS << Str << "\n"; }
169d88c1a5aSDimitry Andric
print(raw_ostream & OS) const170f22ef01cSRoman Divacky void PrettyStackTraceProgram::print(raw_ostream &OS) const {
171f22ef01cSRoman Divacky OS << "Program arguments: ";
172f22ef01cSRoman Divacky // Print the argument list.
173f22ef01cSRoman Divacky for (unsigned i = 0, e = ArgC; i != e; ++i)
174f22ef01cSRoman Divacky OS << ArgV[i] << ' ';
175f22ef01cSRoman Divacky OS << '\n';
176f22ef01cSRoman Divacky }
177f785676fSDimitry Andric
178d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
RegisterCrashPrinter()179f785676fSDimitry Andric static bool RegisterCrashPrinter() {
18091bc56edSDimitry Andric sys::AddSignalHandler(CrashHandler, nullptr);
181f785676fSDimitry Andric return false;
182f785676fSDimitry Andric }
183ff0cc061SDimitry Andric #endif
184f785676fSDimitry Andric
EnablePrettyStackTrace()185f785676fSDimitry Andric void llvm::EnablePrettyStackTrace() {
186d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
187f785676fSDimitry Andric // The first time this is called, we register the crash printer.
188f785676fSDimitry Andric static bool HandlerRegistered = RegisterCrashPrinter();
189f785676fSDimitry Andric (void)HandlerRegistered;
190ff0cc061SDimitry Andric #endif
191f785676fSDimitry Andric }
192f785676fSDimitry Andric
SavePrettyStackState()1937d523365SDimitry Andric const void *llvm::SavePrettyStackState() {
194d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
1957d523365SDimitry Andric return PrettyStackTraceHead;
1967d523365SDimitry Andric #else
1977d523365SDimitry Andric return nullptr;
1987d523365SDimitry Andric #endif
1997d523365SDimitry Andric }
2007d523365SDimitry Andric
RestorePrettyStackState(const void * Top)2017d523365SDimitry Andric void llvm::RestorePrettyStackState(const void *Top) {
202d88c1a5aSDimitry Andric #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES
2033ca95b02SDimitry Andric PrettyStackTraceHead =
2043ca95b02SDimitry Andric static_cast<PrettyStackTraceEntry *>(const_cast<void *>(Top));
2057d523365SDimitry Andric #endif
2067d523365SDimitry Andric }
2077d523365SDimitry Andric
LLVMEnablePrettyStackTrace()208f785676fSDimitry Andric void LLVMEnablePrettyStackTrace() {
209f785676fSDimitry Andric EnablePrettyStackTrace();
210f785676fSDimitry Andric }
211