#include "Unix.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/ManagedStatic.h"
}
static void RegisterHandlers() {
+ // We need to dereference the signals mutex during handler registration so
+ // that we force its construction. This is to prevent the first use being
+ // during handling an actual signal because you can't safely call new in a
+ // signal handler.
+ *SignalsMutex;
+
// If the handlers are already registered, we're done.
if (NumRegisteredSignals != 0) return;
/// NB: This must be an async signal safe function. It cannot allocate or free
/// memory, even in debug builds.
static void RemoveFilesToRemove() {
+ // Avoid constructing ManagedStatic in the signal handler.
+ // If FilesToRemove is not constructed, there are no files to remove.
+ if (!FilesToRemove.isConstructed())
+ return;
+
// We avoid iterators in case of debug iterators that allocate or release
// memory.
std::vector<std::string>& FilesToRemoveRef = *FilesToRemove;
}
// Otherwise if it is a fault (like SEGV) run any handler.
- std::vector<std::pair<void (*)(void *), void *>>& CallBacksToRunRef =
- *CallBacksToRun;
- for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
- CallBacksToRunRef[i].first(CallBacksToRunRef[i].second);
+ if (CallBacksToRun.isConstructed()) {
+ auto &CallBacksToRunRef = *CallBacksToRun;
+ for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
+ CallBacksToRunRef[i].first(CallBacksToRunRef[i].second);
+ }
#ifdef __s390__
// On S/390, certain signals are delivered with PSW Address pointing to
RegisterHandlers();
}
+#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
+
#if HAVE_LINK_H && (defined(__linux__) || defined(__FreeBSD__) || \
defined(__FreeBSD_kernel__) || defined(__NetBSD__))
struct DlIteratePhdrData {
}
#endif
-#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
-static bool printSymbolizedStackTrace(void **StackTrace, int Depth, FILE *FD) {
+static bool printSymbolizedStackTrace(void **StackTrace, int Depth,
+ llvm::raw_ostream &OS) {
// FIXME: Subtract necessary number from StackTrace entries to turn return addresses
// into actual instruction addresses.
// Use llvm-symbolizer tool to symbolize the stack traces.
- std::string LLVMSymbolizerPath = sys::FindProgramByName("llvm-symbolizer");
- if (LLVMSymbolizerPath.empty())
+ ErrorOr<std::string> LLVMSymbolizerPathOrErr =
+ sys::findProgramByName("llvm-symbolizer");
+ if (!LLVMSymbolizerPathOrErr)
return false;
+ const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr;
// We don't know argv0 or the address of main() at this point, but try
// to guess it anyway (it's possible on some platforms).
std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr);
sys::fs::createTemporaryFile("symbolizer-output", "", OutputFile);
FileRemover InputRemover(InputFile.c_str());
FileRemover OutputRemover(OutputFile.c_str());
- std::vector<const StringRef *> Redirects(3, nullptr);
- StringRef InputFileStr(InputFile);
- StringRef OutputFileStr(OutputFile);
- StringRef StderrFileStr;
- Redirects[0] = &InputFileStr;
- Redirects[1] = &OutputFileStr;
- Redirects[2] = &StderrFileStr;
{
raw_fd_ostream Input(InputFD, true);
}
}
+ StringRef InputFileStr(InputFile);
+ StringRef OutputFileStr(OutputFile);
+ StringRef StderrFileStr;
+ const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr,
+ &StderrFileStr};
const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
"--demangle", nullptr};
int RunResult =
- sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects.data());
+ sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects);
if (RunResult != 0)
return false;
int frame_no = 0;
for (int i = 0; i < Depth; i++) {
if (!Modules[i]) {
- fprintf(FD, "#%d %p\n", frame_no++, StackTrace[i]);
+ OS << format("#%d %p\n", frame_no++, StackTrace[i]);
continue;
}
// Read pairs of lines (function name and file/line info) until we
StringRef FunctionName = *CurLine++;
if (FunctionName.empty())
break;
- fprintf(FD, "#%d %p ", frame_no++, StackTrace[i]);
+ OS << format("#%d %p ", frame_no++, StackTrace[i]);
if (!FunctionName.startswith("??"))
- fprintf(FD, "%s ", FunctionName.str().c_str());
+ OS << format("%s ", FunctionName.str().c_str());
if (CurLine == Lines.end())
return false;
StringRef FileLineInfo = *CurLine++;
if (!FileLineInfo.startswith("??"))
- fprintf(FD, "%s", FileLineInfo.str().c_str());
+ OS << format("%s", FileLineInfo.str().c_str());
else
- fprintf(FD, "(%s+%p)", Modules[i], (void *)Offsets[i]);
- fprintf(FD, "\n");
+ OS << format("(%s+%p)", Modules[i], (void *)Offsets[i]);
+ OS << "\n";
}
}
return true;
}
-#endif
+#endif // defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
// PrintStackTrace - In the case of a program crash or fault, print out a stack
// trace so that the user has an indication of why and where we died.
//
// On glibc systems we have the 'backtrace' function, which works nicely, but
// doesn't demangle symbols.
-void llvm::sys::PrintStackTrace(FILE *FD) {
+void llvm::sys::PrintStackTrace(raw_ostream &OS) {
#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES)
static void* StackTrace[256];
// Use backtrace() to output a backtrace on Linux systems with glibc.
int depth = backtrace(StackTrace,
static_cast<int>(array_lengthof(StackTrace)));
- if (printSymbolizedStackTrace(StackTrace, depth, FD))
+ if (printSymbolizedStackTrace(StackTrace, depth, OS))
return;
#if HAVE_DLFCN_H && __GNUG__
int width = 0;
Dl_info dlinfo;
dladdr(StackTrace[i], &dlinfo);
- fprintf(FD, "%-2d", i);
+ OS << format("%-2d", i);
const char* name = strrchr(dlinfo.dli_fname, '/');
- if (!name) fprintf(FD, " %-*s", width, dlinfo.dli_fname);
- else fprintf(FD, " %-*s", width, name+1);
+ if (!name) OS << format(" %-*s", width, dlinfo.dli_fname);
+ else OS << format(" %-*s", width, name+1);
- fprintf(FD, " %#0*lx",
- (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]);
+ OS << format(" %#0*lx", (int)(sizeof(void*) * 2) + 2,
+ (unsigned long)StackTrace[i]);
if (dlinfo.dli_sname != nullptr) {
- fputc(' ', FD);
+ OS << ' ';
# if HAVE_CXXABI_H
int res;
char* d = abi::__cxa_demangle(dlinfo.dli_sname, nullptr, nullptr, &res);
# else
char* d = NULL;
# endif
- if (!d) fputs(dlinfo.dli_sname, FD);
- else fputs(d, FD);
+ if (!d) OS << dlinfo.dli_sname;
+ else OS << d;
free(d);
// FIXME: When we move to C++11, use %t length modifier. It's not in
// C++03 and causes gcc to issue warnings. Losing the upper 32 bits of
// the stack offset for a stack dump isn't likely to cause any problems.
- fprintf(FD, " + %u",(unsigned)((char*)StackTrace[i]-
- (char*)dlinfo.dli_saddr));
+ OS << format(" + %u",(unsigned)((char*)StackTrace[i]-
+ (char*)dlinfo.dli_saddr));
}
- fputc('\n', FD);
+ OS << '\n';
}
#else
backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
}
static void PrintStackTraceSignalHandler(void *) {
- PrintStackTrace(stderr);
+ PrintStackTrace(llvm::errs());
}
+void llvm::sys::DisableSystemDialogsOnCrash() {}
+
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIGABRT or
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
-void llvm::sys::PrintStackTraceOnErrorSignal() {
+void llvm::sys::PrintStackTraceOnErrorSignal(bool DisableCrashReporting) {
AddSignalHandler(PrintStackTraceSignalHandler, nullptr);
#if defined(__APPLE__) && defined(ENABLE_CRASH_OVERRIDES)
// Environment variable to disable any kind of crash dialog.
- if (getenv("LLVM_DISABLE_CRASH_REPORT")) {
+ if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) {
mach_port_t self = mach_task_self();
exception_mask_t mask = EXC_MASK_CRASH;