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[] = {SIGHUP, SIGINT, SIGTERM, SIGUSR2};
215 static const int KillSigs[] = {SIGILL,
241 static const int InfoSigs[] = {SIGUSR1
251 static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0);
255 } RegisteredSignalInfo[NumSigs];
257 #if defined(HAVE_SIGALTSTACK)
262 static stack_t OldAltStack;
265 static void CreateSigAltStack() {
266 const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;
272 if (sigaltstack(
nullptr, &OldAltStack) != 0 ||
273 OldAltStack.ss_flags & SS_ONSTACK ||
274 (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))
277 stack_t AltStack = {};
278 AltStack.ss_sp =
static_cast<char *
>(
safe_malloc(AltStackSize));
279 NewAltStackPointer = AltStack.ss_sp;
280 AltStack.ss_size = AltStackSize;
281 if (sigaltstack(&AltStack, &OldAltStack) != 0)
282 free(AltStack.ss_sp);
285 static void CreateSigAltStack() {}
288 static void RegisterHandlers() {
296 if (NumRegisteredSignals.load() != 0)
303 enum class SignalKind { IsKill, IsInfo };
304 auto registerHandler = [&](
int Signal, SignalKind
Kind) {
305 unsigned Index = NumRegisteredSignals.load();
307 "Out of space for signal handlers!");
309 struct sigaction NewHandler;
312 case SignalKind::IsKill:
313 NewHandler.sa_handler = SignalHandler;
314 NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
316 case SignalKind::IsInfo:
317 NewHandler.sa_handler = InfoSignalHandler;
318 NewHandler.sa_flags = SA_ONSTACK;
321 sigemptyset(&NewHandler.sa_mask);
324 sigaction(Signal, &NewHandler, &RegisteredSignalInfo[
Index].SA);
325 RegisteredSignalInfo[
Index].SigNo = Signal;
326 ++NumRegisteredSignals;
329 for (
auto S : IntSigs)
330 registerHandler(
S, SignalKind::IsKill);
331 for (
auto S : KillSigs)
332 registerHandler(
S, SignalKind::IsKill);
333 if (OneShotPipeSignalFunction)
334 registerHandler(SIGPIPE, SignalKind::IsKill);
335 for (
auto S : InfoSigs)
336 registerHandler(
S, SignalKind::IsInfo);
341 for (
unsigned i = 0,
e = NumRegisteredSignals.load();
i !=
e; ++
i) {
342 sigaction(RegisteredSignalInfo[
i].SigNo, &RegisteredSignalInfo[
i].SA,
344 --NumRegisteredSignals;
349 static void RemoveFilesToRemove() {
350 FileToRemoveList::removeAllFiles(FilesToRemove);
357 InfoSignalHandler(Sig);
361 RemoveFilesToRemove();
370 static void SignalHandler(
int Sig) {
379 sigfillset(&SigMask);
380 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
383 RemoveFilesToRemove();
386 if (
auto OldOneShotPipeFunction =
387 OneShotPipeSignalFunction.exchange(
nullptr))
388 return OldOneShotPipeFunction();
392 if (
auto OldInterruptFunction = InterruptFunction.exchange(
nullptr))
393 return OldInterruptFunction();
395 if (Sig == SIGPIPE || IsIntSig) {
409 if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
414 static void InfoSignalHandler(
int Sig) {
416 if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
417 CurrentInfoFunction();
423 InterruptFunction.exchange(
IF);
428 InfoSignalFunction.exchange(Handler);
433 OneShotPipeSignalFunction.exchange(Handler);
446 *FilesToRemoveCleanup;
447 FileToRemoveList::insert(FilesToRemove,
Filename.str());
454 FileToRemoveList::erase(FilesToRemove,
Filename.str());
466 #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && HAVE_LINK_H && \
467 (defined(__linux__) || defined(__FreeBSD__) || \
468 defined(__FreeBSD_kernel__) || defined(__NetBSD__))
469 struct DlIteratePhdrData {
473 const char **modules;
475 const char *main_exec_name;
478 static int dl_iterate_phdr_cb(dl_phdr_info *
info,
size_t size,
void *arg) {
479 DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
480 const char *
name = data->first ? data->main_exec_name :
info->dlpi_name;
482 for (
int i = 0;
i <
info->dlpi_phnum;
i++) {
483 const auto *phdr = &
info->dlpi_phdr[
i];
488 for (
int j = 0;
j < data->depth;
j++) {
489 if (data->modules[
j])
492 if (beg <= addr && addr <
end) {
493 data->modules[
j] =
name;
494 data->offsets[
j] = addr -
info->dlpi_addr;
505 const char *MainExecutableName,
507 DlIteratePhdrData data = {StackTrace,
Depth,
true,
508 Modules,
Offsets, MainExecutableName};
509 dl_iterate_phdr(dl_iterate_phdr_cb, &data);
517 const char *MainExecutableName,
521 #endif // defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && ...
523 #if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)
524 static int unwindBacktrace(
void **StackTrace,
int MaxEntries) {
531 auto HandleFrame = [&](_Unwind_Context *
Context) -> _Unwind_Reason_Code {
533 void *IP = (
void *)_Unwind_GetIP(
Context);
535 return _URC_END_OF_STACK;
537 assert(Entries < MaxEntries &&
"recursively called after END_OF_STACK?");
539 StackTrace[Entries] = IP;
541 if (++Entries == MaxEntries)
542 return _URC_END_OF_STACK;
543 return _URC_NO_REASON;
547 [](_Unwind_Context *
Context,
void *Handler) {
548 return (*
static_cast<decltype(HandleFrame) *
>(Handler))(
Context);
550 static_cast<void *
>(&HandleFrame));
561 #if ENABLE_BACKTRACES
562 static void *StackTrace[256];
564 #if defined(HAVE_BACKTRACE)
567 depth = backtrace(StackTrace,
static_cast<int>(
std::size(StackTrace)));
569 #if defined(HAVE__UNWIND_BACKTRACE)
573 unwindBacktrace(StackTrace,
static_cast<int>(
std::size(StackTrace)));
583 OS <<
"Stack dump without symbol names (ensure you have llvm-symbolizer in "
584 "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point "
586 #if HAVE_DLFCN_H && HAVE_DLADDR
588 for (
int i = 0;
i < depth; ++
i) {
590 dladdr(StackTrace[
i], &dlinfo);
591 const char *
name = strrchr(dlinfo.dli_fname,
'/');
595 nwidth = strlen(dlinfo.dli_fname);
597 nwidth = strlen(
name) - 1;
603 for (
int i = 0;
i < depth; ++
i) {
605 dladdr(StackTrace[
i], &dlinfo);
609 const char *
name = strrchr(dlinfo.dli_fname,
'/');
611 OS <<
format(
" %-*s", width, dlinfo.dli_fname);
615 OS <<
format(
" %#0*lx", (
int)(
sizeof(
void *) * 2) + 2,
616 (
unsigned long)StackTrace[
i]);
618 if (dlinfo.dli_sname !=
nullptr) {
623 OS << dlinfo.dli_sname;
628 OS <<
format(
" + %tu", (
static_cast<const char *
>(StackTrace[
i]) -
629 static_cast<const char *
>(dlinfo.dli_saddr)));
633 #elif defined(HAVE_BACKTRACE)
634 backtrace_symbols_fd(StackTrace,
Depth, STDERR_FILENO);
639 static void PrintStackTraceSignalHandler(
void *) {
648 bool DisableCrashReporting) {
653 #if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES
655 if (DisableCrashReporting || getenv(
"LLVM_DISABLE_CRASH_REPORT")) {
656 mach_port_t
self = mach_task_self();
658 exception_mask_t
mask = EXC_MASK_CRASH;
660 kern_return_t
ret = task_set_exception_ports(
661 self,
mask, MACH_PORT_NULL,
662 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);