38 #include "llvm/Config/config.h" 52 # include BACKTRACE_HEADER // For backtrace(). 64 #include <mach/mach.h> 69 #ifdef HAVE__UNWIND_BACKTRACE 77 #undef HAVE__UNWIND_BACKTRACE 83 static RETSIGTYPE SignalHandler(
int Sig);
86 using InterruptFunctionType = void (*)();
87 static std::atomic<InterruptFunctionType> InterruptFunction =
88 ATOMIC_VAR_INIT(
nullptr);
95 class FileToRemoveList {
96 std::atomic<char *> Filename = ATOMIC_VAR_INIT(
nullptr);
97 std::atomic<FileToRemoveList *> Next = ATOMIC_VAR_INIT(
nullptr);
99 FileToRemoveList() =
default;
101 FileToRemoveList(
const std::string &str) : Filename(strdup(str.
c_str())) {}
105 ~FileToRemoveList() {
106 if (FileToRemoveList *
N = Next.exchange(
nullptr))
108 if (
char *
F = Filename.exchange(
nullptr))
113 static void insert(std::atomic<FileToRemoveList *> &Head,
114 const std::string &Filename) {
116 FileToRemoveList *NewHead =
new FileToRemoveList(Filename);
117 std::atomic<FileToRemoveList *> *InsertionPoint = &Head;
118 FileToRemoveList *OldHead =
nullptr;
119 while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {
120 InsertionPoint = &OldHead->Next;
126 static void erase(std::atomic<FileToRemoveList *> &Head,
127 const std::string &Filename) {
133 for (FileToRemoveList *Current = Head.load(); Current;
134 Current = Current->Next.load()) {
135 if (
char *OldFilename = Current->Filename.load()) {
136 if (OldFilename != Filename)
139 OldFilename = Current->Filename.exchange(
nullptr);
149 static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {
154 FileToRemoveList *OldHead = Head.exchange(
nullptr);
156 for (FileToRemoveList *currentFile = OldHead; currentFile;
157 currentFile = currentFile->Next.load()) {
160 if (
char *path = currentFile->Filename.exchange(
nullptr)) {
164 if (stat(path, &buf) != 0)
170 if (!S_ISREG(buf.st_mode))
178 currentFile->Filename.exchange(path);
183 Head.exchange(OldHead);
186 static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(
nullptr);
191 struct FilesToRemoveCleanup {
193 ~FilesToRemoveCleanup() {
194 FileToRemoveList *Head = FilesToRemove.exchange(
nullptr);
206 static const int IntSigs[] = {
207 SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
212 static const int KillSigs[] = {
213 SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT
228 static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0);
234 #if defined(HAVE_SIGALTSTACK) 239 static stack_t OldAltStack;
240 static void* NewAltStackPointer;
242 static void CreateSigAltStack() {
243 const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;
249 if (sigaltstack(
nullptr, &OldAltStack) != 0 ||
250 OldAltStack.ss_flags & SS_ONSTACK ||
251 (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))
254 stack_t AltStack = {};
255 AltStack.ss_sp =
static_cast<char *
>(
safe_malloc(AltStackSize));
256 NewAltStackPointer = AltStack.ss_sp;
257 AltStack.ss_size = AltStackSize;
258 if (sigaltstack(&AltStack, &OldAltStack) != 0)
259 free(AltStack.ss_sp);
262 static void CreateSigAltStack() {}
265 static void RegisterHandlers() {
273 if (NumRegisteredSignals.load() != 0)
280 auto registerHandler = [&](
int Signal) {
281 unsigned Index = NumRegisteredSignals.load();
283 "Out of space for signal handlers!");
285 struct sigaction NewHandler;
287 NewHandler.sa_handler = SignalHandler;
288 NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
289 sigemptyset(&NewHandler.sa_mask);
292 sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
293 RegisteredSignalInfo[
Index].SigNo = Signal;
294 ++NumRegisteredSignals;
297 for (
auto S : IntSigs)
299 for (
auto S : KillSigs)
303 static void UnregisterHandlers() {
305 for (
unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {
306 sigaction(RegisteredSignalInfo[i].SigNo,
307 &RegisteredSignalInfo[i].SA,
nullptr);
308 --NumRegisteredSignals;
313 static void RemoveFilesToRemove() {
314 FileToRemoveList::removeAllFiles(FilesToRemove);
318 static RETSIGTYPE SignalHandler(
int Sig) {
323 UnregisterHandlers();
327 sigfillset(&SigMask);
328 sigprocmask(SIG_UNBLOCK, &SigMask,
nullptr);
331 RemoveFilesToRemove();
335 if (
auto OldInterruptFunction = InterruptFunction.exchange(
nullptr))
336 return OldInterruptFunction();
355 if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
361 RemoveFilesToRemove();
365 InterruptFunction.exchange(
IF);
371 std::string* ErrMsg) {
374 *FilesToRemoveCleanup;
375 FileToRemoveList::insert(FilesToRemove, Filename.
str());
382 FileToRemoveList::erase(FilesToRemove, Filename.
str());
394 #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && HAVE_LINK_H && \ 395 (defined(__linux__) || defined(__FreeBSD__) || \ 396 defined(__FreeBSD_kernel__) || defined(__NetBSD__)) 397 struct DlIteratePhdrData {
401 const char **modules;
403 const char *main_exec_name;
406 static int dl_iterate_phdr_cb(dl_phdr_info *
info,
size_t size,
void *arg) {
407 DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
408 const char *
name = data->first ? data->main_exec_name : info->dlpi_name;
410 for (
int i = 0; i < info->dlpi_phnum; i++) {
411 const auto *phdr = &info->dlpi_phdr[i];
414 intptr_t beg = info->dlpi_addr + phdr->p_vaddr;
416 for (
int j = 0; j < data->depth; j++) {
417 if (data->modules[j])
420 if (beg <= addr && addr < end) {
421 data->modules[j] =
name;
422 data->offsets[j] = addr - info->dlpi_addr;
433 const char *MainExecutableName,
435 DlIteratePhdrData data = {StackTrace,
Depth,
true,
436 Modules,
Offsets, MainExecutableName};
437 dl_iterate_phdr(dl_iterate_phdr_cb, &data);
445 const char *MainExecutableName,
449 #endif // defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && ... 451 #if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE) 452 static int unwindBacktrace(
void **StackTrace,
int MaxEntries) {
459 auto HandleFrame = [&](_Unwind_Context *
Context) -> _Unwind_Reason_Code {
461 void *IP = (
void *)_Unwind_GetIP(
Context);
463 return _URC_END_OF_STACK;
465 assert(Entries < MaxEntries &&
"recursively called after END_OF_STACK?");
467 StackTrace[Entries] = IP;
469 if (++Entries == MaxEntries)
470 return _URC_END_OF_STACK;
471 return _URC_NO_REASON;
475 [](_Unwind_Context *
Context,
void *Handler) {
476 return (*
static_cast<decltype(HandleFrame) *
>(Handler))(Context);
478 static_cast<void *
>(&HandleFrame));
489 #if ENABLE_BACKTRACES 490 static void *StackTrace[256];
492 #if defined(HAVE_BACKTRACE) 495 depth = backtrace(StackTrace, static_cast<int>(
array_lengthof(StackTrace)));
497 #if defined(HAVE__UNWIND_BACKTRACE) 500 depth = unwindBacktrace(StackTrace,
508 #if HAVE_DLFCN_H && HAVE_DLADDR 510 for (
int i = 0; i < depth; ++i) {
512 dladdr(StackTrace[i], &dlinfo);
513 const char* name = strrchr(dlinfo.dli_fname,
'/');
516 if (!name) nwidth = strlen(dlinfo.dli_fname);
517 else nwidth = strlen(name) - 1;
519 if (nwidth > width) width = nwidth;
522 for (
int i = 0; i < depth; ++i) {
524 dladdr(StackTrace[i], &dlinfo);
528 const char* name = strrchr(dlinfo.dli_fname,
'/');
529 if (!name) OS <<
format(
" %-*s", width, dlinfo.dli_fname);
530 else OS <<
format(
" %-*s", width, name+1);
532 OS <<
format(
" %#0*lx", (
int)(
sizeof(
void*) * 2) + 2,
533 (
unsigned long)StackTrace[i]);
535 if (dlinfo.dli_sname !=
nullptr) {
539 if (!d) OS << dlinfo.dli_sname;
546 OS <<
format(
" + %u",(
unsigned)((
char*)StackTrace[i]-
547 (
char*)dlinfo.dli_saddr));
551 #elif defined(HAVE_BACKTRACE) 552 backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
557 static void PrintStackTraceSignalHandler(
void *) {
566 bool DisableCrashReporting) {
571 #if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES 573 if (DisableCrashReporting || getenv(
"LLVM_DISABLE_CRASH_REPORT")) {
574 mach_port_t
self = mach_task_self();
576 exception_mask_t mask = EXC_MASK_CRASH;
578 kern_return_t ret = task_set_exception_ports(
self,
581 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
const_iterator end(StringRef path)
Get end iterator over path.
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
char * itaniumDemangle(const char *mangled_name, char *buf, size_t *n, int *status)
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
This class represents lattice values for constants.
void(*)(void *) SignalHandlerCallback
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
void DisableSystemDialogsOnCrash()
Disable all system dialog boxes that appear when the process crashes.
static bool findModulesAndOffsets(void **StackTrace, int Depth, const char **Modules, intptr_t *Offsets, const char *MainExecutableName, StringSaver &StrPool)
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...
* if(!EatIfPresent(lltok::kw_thread_local)) return false
ParseOptionalThreadLocal := /*empty.
void PrintStackTrace(raw_ostream &OS)
Print the stack trace using the given raw_ostream object.
void RunInterruptHandlers()
This function runs all the registered interrupt handlers, including the removal of files registered b...
void DontRemoveFileOnSignal(StringRef Filename)
This function removes a file from the list of files to be removed on signal delivery.
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.
auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range))
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly...
LLVM_ATTRIBUTE_RETURNS_NONNULL void * safe_malloc(size_t Sz)
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
constexpr size_t array_lengthof(T(&)[N])
Find the length of an array.
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...
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer...
void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie)
Add a function to be called when an abort/kill signal is delivered to the process.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void insertSignalHandler(sys::SignalHandlerCallback FnPtr, void *Cookie)
This class implements an extremely fast bulk output stream that can only output to a stream...
StringRef - Represent a constant reference to a string, i.e.
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
void SetInterruptFunction(void(*IF)())
This function registers a function to be called when the user "interrupts" the program (typically by ...