37#include "llvm/Config/config.h"
51#include BACKTRACE_HEADER
66#include <mach-o/dyld.h>
71#ifdef HAVE__UNWIND_BACKTRACE
79#undef HAVE__UNWIND_BACKTRACE
85static void SignalHandler(
int Sig);
86static void InfoSignalHandler(
int Sig);
88using SignalHandlerFunctionType = void (*)();
90static std::atomic<SignalHandlerFunctionType> InterruptFunction =
nullptr;
91static std::atomic<SignalHandlerFunctionType> InfoSignalFunction =
nullptr;
93static std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction =
101class FileToRemoveList {
102 std::atomic<char *>
Filename =
nullptr;
103 std::atomic<FileToRemoveList *> Next =
nullptr;
105 FileToRemoveList() =
default;
107 FileToRemoveList(
const std::string &str) :
Filename(strdup(str.
c_str())) {}
111 ~FileToRemoveList() {
112 if (FileToRemoveList *
N = Next.exchange(
nullptr))
114 if (
char *
F =
Filename.exchange(
nullptr))
119 static void insert(std::atomic<FileToRemoveList *> &Head,
120 const std::string &Filename) {
122 FileToRemoveList *NewHead =
new FileToRemoveList(Filename);
123 std::atomic<FileToRemoveList *> *InsertionPoint = &Head;
124 FileToRemoveList *OldHead =
nullptr;
125 while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {
126 InsertionPoint = &OldHead->Next;
132 static void erase(std::atomic<FileToRemoveList *> &Head,
133 const std::string &Filename) {
139 for (FileToRemoveList *Current = Head.load(); Current;
140 Current = Current->Next.load()) {
141 if (
char *OldFilename = Current->Filename.load()) {
142 if (OldFilename != Filename)
145 OldFilename = Current->Filename.exchange(
nullptr);
155 static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {
160 FileToRemoveList *OldHead = Head.exchange(
nullptr);
162 for (FileToRemoveList *currentFile = OldHead; currentFile;
163 currentFile = currentFile->Next.load()) {
166 if (
char *path = currentFile->Filename.exchange(
nullptr)) {
170 if (stat(path, &buf) != 0)
176 if (!S_ISREG(buf.st_mode))
184 currentFile->Filename.exchange(path);
189 Head.exchange(OldHead);
192static std::atomic<FileToRemoveList *> FilesToRemove =
nullptr;
197struct FilesToRemoveCleanup {
199 ~FilesToRemoveCleanup() {
200 FileToRemoveList *Head = FilesToRemove.exchange(
nullptr);
212static const int IntSigs[] = {SIGHUP, SIGINT, SIGTERM, SIGUSR2};
216static const int KillSigs[] = {SIGILL,
242static const int InfoSigs[] = {SIGUSR1
249static const size_t NumSigs = std::size(IntSigs) + std::size(KillSigs) +
250 std::size(InfoSigs) + 1 ;
252static std::atomic<unsigned> NumRegisteredSignals = 0;
256} RegisteredSignalInfo[NumSigs];
258#if defined(HAVE_SIGALTSTACK)
263static stack_t OldAltStack;
266static void CreateSigAltStack() {
267 const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;
273 if (sigaltstack(
nullptr, &OldAltStack) != 0 ||
274 OldAltStack.ss_flags & SS_ONSTACK ||
275 (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))
278 stack_t AltStack = {};
279 AltStack.ss_sp =
static_cast<char *
>(
safe_malloc(AltStackSize));
280 NewAltStackPointer = AltStack.ss_sp;
281 AltStack.ss_size = AltStackSize;
282 if (sigaltstack(&AltStack, &OldAltStack) != 0)
283 free(AltStack.ss_sp);
286static void CreateSigAltStack() {}
289static void RegisterHandlers() {
297 if (NumRegisteredSignals.load() != 0)
304 enum class SignalKind { IsKill, IsInfo };
305 auto registerHandler = [&](
int Signal, SignalKind
Kind) {
306 unsigned Index = NumRegisteredSignals.load();
308 "Out of space for signal handlers!");
310 struct sigaction NewHandler;
313 case SignalKind::IsKill:
314 NewHandler.sa_handler = SignalHandler;
315 NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
317 case SignalKind::IsInfo:
318 NewHandler.sa_handler = InfoSignalHandler;
319 NewHandler.sa_flags = SA_ONSTACK;
322 sigemptyset(&NewHandler.sa_mask);
325 sigaction(Signal, &NewHandler, &RegisteredSignalInfo[
Index].SA);
326 RegisteredSignalInfo[
Index].SigNo = Signal;
327 ++NumRegisteredSignals;
330 for (
auto S : IntSigs)
331 registerHandler(S, SignalKind::IsKill);
332 for (
auto S : KillSigs)
333 registerHandler(S, SignalKind::IsKill);
334 if (OneShotPipeSignalFunction)
335 registerHandler(SIGPIPE, SignalKind::IsKill);
336 for (
auto S : InfoSigs)
337 registerHandler(S, SignalKind::IsInfo);
340void sys::unregisterHandlers() {
342 for (
unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {
343 sigaction(RegisteredSignalInfo[i].SigNo, &RegisteredSignalInfo[i].SA,
345 --NumRegisteredSignals;
350static void RemoveFilesToRemove() {
351 FileToRemoveList::removeAllFiles(FilesToRemove);
354void sys::CleanupOnSignal(uintptr_t Context) {
355 int Sig = (int)Context;
358 InfoSignalHandler(Sig);
362 RemoveFilesToRemove();
371static void SignalHandler(
int Sig) {
376 sys::unregisterHandlers();
380 sigfillset(&SigMask);
381 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
384 RemoveFilesToRemove();
387 if (
auto OldOneShotPipeFunction =
388 OneShotPipeSignalFunction.exchange(
nullptr))
389 return OldOneShotPipeFunction();
393 if (
auto OldInterruptFunction = InterruptFunction.exchange(
nullptr))
394 return OldInterruptFunction();
396 if (Sig == SIGPIPE || IsIntSig) {
410 if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
415static void InfoSignalHandler(
int Sig) {
417 if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
418 CurrentInfoFunction();
424 InterruptFunction.exchange(IF);
429 InfoSignalFunction.exchange(Handler);
434 OneShotPipeSignalFunction.exchange(Handler);
447 *FilesToRemoveCleanup;
448 FileToRemoveList::insert(FilesToRemove,
Filename.str());
455 FileToRemoveList::erase(FilesToRemove,
Filename.str());
467#if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) && HAVE_LINK_H && \
468 (defined(__linux__) || defined(__FreeBSD__) || \
469 defined(__FreeBSD_kernel__) || defined(__NetBSD__))
470struct DlIteratePhdrData {
474 const char **modules;
476 const char *main_exec_name;
479static int dl_iterate_phdr_cb(dl_phdr_info *
info,
size_t size,
void *arg) {
480 DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
481 const char *
name = data->first ? data->main_exec_name :
info->dlpi_name;
483 for (
int i = 0; i <
info->dlpi_phnum; i++) {
484 const auto *phdr = &
info->dlpi_phdr[i];
485 if (phdr->p_type != PT_LOAD)
487 intptr_t beg =
info->dlpi_addr + phdr->p_vaddr;
488 intptr_t
end = beg + phdr->p_memsz;
489 for (
int j = 0;
j < data->depth;
j++) {
490 if (data->modules[j])
492 intptr_t addr = (intptr_t)data->StackTrace[j];
493 if (beg <= addr && addr < end) {
494 data->modules[
j] =
name;
495 data->offsets[
j] = addr -
info->dlpi_addr;
505 const char **Modules, intptr_t *Offsets,
506 const char *MainExecutableName,
508 DlIteratePhdrData data = {StackTrace,
Depth,
true,
509 Modules,
Offsets, MainExecutableName};
510 dl_iterate_phdr(dl_iterate_phdr_cb, &data);
513#elif ENABLE_BACKTRACES && defined(__APPLE__) && defined(__LP64__)
515 const char **Modules, intptr_t *Offsets,
516 const char *MainExecutableName,
518 uint32_t NumImgs = _dyld_image_count();
519 for (
uint32_t ImageIndex = 0; ImageIndex < NumImgs; ImageIndex++) {
520 const char *
Name = _dyld_get_image_name(ImageIndex);
521 intptr_t Slide = _dyld_get_image_vmaddr_slide(ImageIndex);
523 (
const struct mach_header_64 *)_dyld_get_image_header(ImageIndex);
526 auto Cmd = (
const struct load_command *)(&Header[1]);
527 for (
uint32_t CmdNum = 0; CmdNum < Header->ncmds; ++CmdNum) {
528 uint32_t BaseCmd = Cmd->cmd & ~LC_REQ_DYLD;
529 if (BaseCmd == LC_SEGMENT_64) {
530 auto CmdSeg64 = (
const struct segment_command_64 *)Cmd;
531 for (
int j = 0;
j <
Depth;
j++) {
534 intptr_t
Addr = (intptr_t)StackTrace[j];
535 if ((intptr_t)CmdSeg64->vmaddr + Slide <=
Addr &&
536 Addr < intptr_t(CmdSeg64->vmaddr + CmdSeg64->vmsize + Slide)) {
542 Cmd = (
const load_command *)(((
const char *)Cmd) + (Cmd->cmdsize));
551 const char **Modules, intptr_t *Offsets,
552 const char *MainExecutableName,
558#if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)
559static int unwindBacktrace(
void **StackTrace,
int MaxEntries) {
566 auto HandleFrame = [&](_Unwind_Context *
Context) -> _Unwind_Reason_Code {
568 void *IP = (
void *)_Unwind_GetIP(Context);
570 return _URC_END_OF_STACK;
572 assert(Entries < MaxEntries &&
"recursively called after END_OF_STACK?");
574 StackTrace[Entries] = IP;
576 if (++Entries == MaxEntries)
577 return _URC_END_OF_STACK;
578 return _URC_NO_REASON;
582 [](_Unwind_Context *Context,
void *Handler) {
583 return (*
static_cast<decltype(HandleFrame) *
>(Handler))(Context);
585 static_cast<void *
>(&HandleFrame));
586 return std::max(Entries, 0);
597 static void *StackTrace[256];
599#if defined(HAVE_BACKTRACE)
602 depth = backtrace(StackTrace,
static_cast<int>(std::size(StackTrace)));
604#if defined(HAVE__UNWIND_BACKTRACE)
608 unwindBacktrace(StackTrace,
static_cast<int>(std::size(StackTrace)));
618 OS <<
"Stack dump without symbol names (ensure you have llvm-symbolizer in "
619 "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point "
621#if HAVE_DLFCN_H && HAVE_DLADDR
623 for (
int i = 0; i < depth; ++i) {
625 dladdr(StackTrace[i], &dlinfo);
626 const char *
name = strrchr(dlinfo.dli_fname,
'/');
630 nwidth = strlen(dlinfo.dli_fname);
632 nwidth = strlen(
name) - 1;
638 for (
int i = 0; i < depth; ++i) {
640 dladdr(StackTrace[i], &dlinfo);
644 const char *
name = strrchr(dlinfo.dli_fname,
'/');
646 OS <<
format(
" %-*s", width, dlinfo.dli_fname);
650 OS <<
format(
" %#0*lx", (
int)(
sizeof(
void *) * 2) + 2,
651 (
unsigned long)StackTrace[i]);
653 if (dlinfo.dli_sname !=
nullptr) {
659 OS << dlinfo.dli_sname;
662 OS <<
format(
" + %tu", (
static_cast<const char *
>(StackTrace[i]) -
663 static_cast<const char *
>(dlinfo.dli_saddr)));
667#elif defined(HAVE_BACKTRACE)
668 backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO);
673static void PrintStackTraceSignalHandler(
void *) {
682 bool DisableCrashReporting) {
687#if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES
689 if (DisableCrashReporting || getenv(
"LLVM_DISABLE_CRASH_REPORT")) {
690 mach_port_t
self = mach_task_self();
692 exception_mask_t
mask = EXC_MASK_CRASH;
694 kern_return_t ret = task_set_exception_ports(
695 self, mask, MACH_PORT_NULL,
696 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
#define LLVM_ATTRIBUTE_USED
This file contains definitions of exit codes for exit() function.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file provides utility classes that use RAII to save and restore values.
static LLVM_ATTRIBUTE_USED bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, int Depth, llvm::raw_ostream &OS)
Helper that launches llvm-symbolizer and symbolizes a backtrace.
static bool findModulesAndOffsets(void **StackTrace, int Depth, const char **Modules, intptr_t *Offsets, const char *MainExecutableName, StringSaver &StrPool)
static void insertSignalHandler(sys::SignalHandlerCallback FnPtr, void *Cookie)
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
StringRef - Represent a constant reference to a string, i.e.
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer.
This class implements an extremely fast bulk output stream that can only output to a stream.
const_iterator end(StringRef path)
Get end iterator over path.
void SetInterruptFunction(void(*IF)())
This function registers a function to be called when the user "interrupts" the program (typically by ...
void PrintStackTrace(raw_ostream &OS, int Depth=0)
Print the stack trace using the given raw_ostream object.
void DisableSystemDialogsOnCrash()
Disable all system dialog boxes that appear when the process crashes.
void SetOneShotPipeSignalFunction(void(*Handler)())
Registers a function to be called in a "one-shot" manner when a pipe signal is delivered to the proce...
void DontRemoveFileOnSignal(StringRef Filename)
This function removes a file from the list of files to be removed on signal delivery.
void DefaultOneShotPipeSignalHandler()
On Unix systems and Windows, this function exits with an "IO error" exit code.
std::lock_guard< SmartMutex< mt_only > > SmartScopedLock
void(*)(void *) SignalHandlerCallback
void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie)
Add a function to be called when an abort/kill signal is delivered to the process.
void SetInfoSignalFunction(void(*Handler)())
Registers a function to be called when an "info" signal is delivered to the process.
void PrintStackTraceOnErrorSignal(StringRef Argv0, bool DisableCrashReporting=false)
When an error signal (such as SIGABRT or SIGSEGV) is delivered to the process, print a stack trace an...
void RunInterruptHandlers()
This function runs all the registered interrupt handlers, including the removal of files registered b...
bool RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg=nullptr)
This function registers signal handlers to ensure that if a signal gets delivered that the named file...
This is an optimization pass for GlobalISel generic memory operations.
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
LLVM_ATTRIBUTE_RETURNS_NONNULL void * safe_malloc(size_t Sz)
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
char * itaniumDemangle(const char *mangled_name)
Returns a non-NULL pointer to a NUL-terminated C style string that should be explicitly freed,...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
auto mask(ShuffFunc S, unsigned Length, OptArgs... args) -> MaskT
A utility class that uses RAII to save and restore the value of a variable.