37 #include "llvm/Config/config.h"
51 # include BACKTRACE_HEADER // For backtrace().
63 #include <mach/mach.h>
68 #ifdef HAVE__UNWIND_BACKTRACE
76 #undef HAVE__UNWIND_BACKTRACE
82 static void SignalHandler(
int Sig);
83 static void InfoSignalHandler(
int Sig);
85 using SignalHandlerFunctionType = void (*)();
87 static std::atomic<SignalHandlerFunctionType> InterruptFunction =
88 ATOMIC_VAR_INIT(
nullptr);
89 static std::atomic<SignalHandlerFunctionType> InfoSignalFunction =
90 ATOMIC_VAR_INIT(
nullptr);
92 static std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction =
93 ATOMIC_VAR_INIT(
nullptr);
100 class FileToRemoveList {
101 std::atomic<char *> Filename = ATOMIC_VAR_INIT(
nullptr);
102 std::atomic<FileToRemoveList *> Next = ATOMIC_VAR_INIT(
nullptr);
104 FileToRemoveList() =
default;
106 FileToRemoveList(
const std::string &str) : Filename(strdup(str.
c_str())) {}
110 ~FileToRemoveList() {
111 if (FileToRemoveList *
N = Next.exchange(
nullptr))
113 if (
char *
F = Filename.exchange(
nullptr))
118 static void insert(std::atomic<FileToRemoveList *> &Head,
119 const std::string &Filename) {
121 FileToRemoveList *NewHead =
new FileToRemoveList(Filename);
122 std::atomic<FileToRemoveList *> *InsertionPoint = &Head;
123 FileToRemoveList *OldHead =
nullptr;
124 while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {
125 InsertionPoint = &OldHead->Next;
131 static void erase(std::atomic<FileToRemoveList *> &Head,
132 const std::string &Filename) {
138 for (FileToRemoveList *Current = Head.load(); Current;
139 Current = Current->Next.load()) {
140 if (
char *OldFilename = Current->Filename.load()) {
141 if (OldFilename != Filename)
144 OldFilename = Current->Filename.exchange(
nullptr);
154 static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {
159 FileToRemoveList *OldHead = Head.exchange(
nullptr);
161 for (FileToRemoveList *currentFile = OldHead; currentFile;
162 currentFile = currentFile->Next.load()) {
165 if (
char *path = currentFile->Filename.exchange(
nullptr)) {
169 if (stat(path, &buf) != 0)
175 if (!S_ISREG(buf.st_mode))
183 currentFile->Filename.exchange(path);
188 Head.exchange(OldHead);
191 static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(
nullptr);
196 struct FilesToRemoveCleanup {
198 ~FilesToRemoveCleanup() {
199 FileToRemoveList *Head = FilesToRemove.exchange(
nullptr);
211 static const int IntSigs[] = {
212 SIGHUP, SIGINT, SIGTERM, SIGUSR2
217 static const int KillSigs[] = {
218 SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT
234 static const int InfoSigs[] = {
241 static const size_t NumSigs =
246 static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0);
250 } RegisteredSignalInfo[NumSigs];
252 #if defined(HAVE_SIGALTSTACK)
257 static stack_t OldAltStack;
260 static void CreateSigAltStack() {
261 const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;
267 if (sigaltstack(
nullptr, &OldAltStack) != 0 ||
268 OldAltStack.ss_flags & SS_ONSTACK ||
269 (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))
272 stack_t AltStack = {};
273 AltStack.ss_sp =
static_cast<char *
>(
safe_malloc(AltStackSize));
274 NewAltStackPointer = AltStack.ss_sp;
275 AltStack.ss_size = AltStackSize;
276 if (sigaltstack(&AltStack, &OldAltStack) != 0)
277 free(AltStack.ss_sp);
280 static void CreateSigAltStack() {}
283 static void RegisterHandlers() {
291 if (NumRegisteredSignals.load() != 0)
298 enum class SignalKind { IsKill, IsInfo };
299 auto registerHandler = [&](
int Signal, SignalKind
Kind) {
300 unsigned Index = NumRegisteredSignals.load();
302 "Out of space for signal handlers!");
304 struct sigaction NewHandler;
307 case SignalKind::IsKill:
308 NewHandler.sa_handler = SignalHandler;
309 NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
311 case SignalKind::IsInfo:
312 NewHandler.sa_handler = InfoSignalHandler;
313 NewHandler.sa_flags = SA_ONSTACK;
316 sigemptyset(&NewHandler.sa_mask);
319 sigaction(Signal, &NewHandler, &RegisteredSignalInfo[
Index].SA);
320 RegisteredSignalInfo[
Index].SigNo = Signal;
321 ++NumRegisteredSignals;
324 for (
auto S : IntSigs)
325 registerHandler(
S, SignalKind::IsKill);
326 for (
auto S : KillSigs)
327 registerHandler(
S, SignalKind::IsKill);
328 if (OneShotPipeSignalFunction)
329 registerHandler(SIGPIPE, SignalKind::IsKill);
330 for (
auto S : InfoSigs)
331 registerHandler(
S, SignalKind::IsInfo);
336 for (
unsigned i = 0,
e = NumRegisteredSignals.load();
i !=
e; ++
i) {
337 sigaction(RegisteredSignalInfo[
i].SigNo,
338 &RegisteredSignalInfo[
i].SA,
nullptr);
339 --NumRegisteredSignals;
344 static void RemoveFilesToRemove() {
345 FileToRemoveList::removeAllFiles(FilesToRemove);
352 InfoSignalHandler(Sig);
356 RemoveFilesToRemove();
365 static void SignalHandler(
int Sig) {
374 sigfillset(&SigMask);
375 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
378 RemoveFilesToRemove();
381 if (
auto OldOneShotPipeFunction =
382 OneShotPipeSignalFunction.exchange(
nullptr))
383 return OldOneShotPipeFunction();
387 if (
auto OldInterruptFunction = InterruptFunction.exchange(
nullptr))
388 return OldInterruptFunction();
390 if (Sig == SIGPIPE || IsIntSig) {
404 if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
409 static void InfoSignalHandler(
int Sig) {
411 if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
412 CurrentInfoFunction();
416 RemoveFilesToRemove();
420 InterruptFunction.exchange(
IF);
425 InfoSignalFunction.exchange(Handler);
430 OneShotPipeSignalFunction.exchange(Handler);
437 errs() <<
"error: write on a pipe with no reader\n";
445 std::string* ErrMsg) {
448 *FilesToRemoveCleanup;
449 FileToRemoveList::insert(FilesToRemove, Filename.
str());
456 FileToRemoveList::erase(FilesToRemove, Filename.
str());
468 #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && HAVE_LINK_H && \
469 (defined(__linux__) || defined(__FreeBSD__) || \
470 defined(__FreeBSD_kernel__) || defined(__NetBSD__))
471 struct DlIteratePhdrData {
475 const char **modules;
477 const char *main_exec_name;
480 static int dl_iterate_phdr_cb(dl_phdr_info *
info,
size_t size,
void *arg) {
481 DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
482 const char *
name = data->first ? data->main_exec_name :
info->dlpi_name;
484 for (
int i = 0;
i <
info->dlpi_phnum;
i++) {
485 const auto *phdr = &
info->dlpi_phdr[
i];
490 for (
int j = 0;
j < data->depth;
j++) {
491 if (data->modules[
j])
494 if (beg <= addr && addr <
end) {
495 data->modules[
j] =
name;
496 data->offsets[
j] = addr -
info->dlpi_addr;
507 const char *MainExecutableName,
509 DlIteratePhdrData data = {StackTrace,
Depth,
true,
510 Modules,
Offsets, MainExecutableName};
511 dl_iterate_phdr(dl_iterate_phdr_cb, &data);
519 const char *MainExecutableName,
523 #endif // defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && ...
525 #if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)
526 static int unwindBacktrace(
void **StackTrace,
int MaxEntries) {
533 auto HandleFrame = [&](_Unwind_Context *
Context) -> _Unwind_Reason_Code {
535 void *
IP = (
void *)_Unwind_GetIP(
Context);
537 return _URC_END_OF_STACK;
539 assert(Entries < MaxEntries &&
"recursively called after END_OF_STACK?");
541 StackTrace[Entries] =
IP;
543 if (++Entries == MaxEntries)
544 return _URC_END_OF_STACK;
545 return _URC_NO_REASON;
549 [](_Unwind_Context *
Context,
void *Handler) {
550 return (*
static_cast<decltype(HandleFrame) *
>(Handler))(
Context);
552 static_cast<void *
>(&HandleFrame));
563 #if ENABLE_BACKTRACES
564 static void *StackTrace[256];
566 #if defined(HAVE_BACKTRACE)
569 depth = backtrace(StackTrace,
static_cast<int>(
array_lengthof(StackTrace)));
571 #if defined(HAVE__UNWIND_BACKTRACE)
574 depth = unwindBacktrace(StackTrace,
585 OS <<
"Stack dump without symbol names (ensure you have llvm-symbolizer in "
586 "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point "
588 #if HAVE_DLFCN_H && HAVE_DLADDR
590 for (
int i = 0;
i < depth; ++
i) {
592 dladdr(StackTrace[
i], &dlinfo);
593 const char*
name = strrchr(dlinfo.dli_fname,
'/');
596 if (!
name) nwidth = strlen(dlinfo.dli_fname);
597 else nwidth = strlen(
name) - 1;
599 if (nwidth > width) width = nwidth;
602 for (
int i = 0;
i < depth; ++
i) {
604 dladdr(StackTrace[
i], &dlinfo);
608 const char*
name = strrchr(dlinfo.dli_fname,
'/');
609 if (!
name) OS <<
format(
" %-*s", width, dlinfo.dli_fname);
612 OS <<
format(
" %#0*lx", (
int)(
sizeof(
void*) * 2) + 2,
613 (
unsigned long)StackTrace[
i]);
615 if (dlinfo.dli_sname !=
nullptr) {
619 if (!
d) OS << dlinfo.dli_sname;
623 OS <<
format(
" + %tu", (
static_cast<const char*
>(StackTrace[
i])-
624 static_cast<const char*
>(dlinfo.dli_saddr)));
628 #elif defined(HAVE_BACKTRACE)
629 backtrace_symbols_fd(StackTrace,
Depth, STDERR_FILENO);
634 static void PrintStackTraceSignalHandler(
void *) {
643 bool DisableCrashReporting) {
648 #if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES
650 if (DisableCrashReporting || getenv(
"LLVM_DISABLE_CRASH_REPORT")) {
651 mach_port_t
self = mach_task_self();
653 exception_mask_t mask = EXC_MASK_CRASH;
655 kern_return_t
ret = task_set_exception_ports(
self,
658 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,