LCOV - code coverage report
Current view: top level - lib/Support/Unix - Signals.inc (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 97 146 66.4 %
Date: 2018-07-13 00:08:38 Functions: 18 25 72.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file defines some helpful functions for dealing with the possibility of
      11             : // Unix signals occurring while your program is running.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : //
      15             : // This file is extremely careful to only do signal-safe things while in a
      16             : // signal handler. In particular, memory allocation and acquiring a mutex
      17             : // while in a signal handler should never occur. ManagedStatic isn't usable from
      18             : // a signal handler for 2 reasons:
      19             : //
      20             : //  1. Creating a new one allocates.
      21             : //  2. The signal handler could fire while llvm_shutdown is being processed, in
      22             : //     which case the ManagedStatic is in an unknown state because it could
      23             : //     already have been destroyed, or be in the process of being destroyed.
      24             : //
      25             : // Modifying the behavior of the signal handlers (such as registering new ones)
      26             : // can acquire a mutex, but all this guarantees is that the signal handler
      27             : // behavior is only modified by one thread at a time. A signal handler can still
      28             : // fire while this occurs!
      29             : //
      30             : // Adding work to a signal handler requires lock-freedom (and assume atomics are
      31             : // always lock-free) because the signal handler could fire while new work is
      32             : // being added.
      33             : //
      34             : //===----------------------------------------------------------------------===//
      35             : 
      36             : #include "Unix.h"
      37             : #include "llvm/ADT/STLExtras.h"
      38             : #include "llvm/Config/config.h"
      39             : #include "llvm/Demangle/Demangle.h"
      40             : #include "llvm/Support/FileSystem.h"
      41             : #include "llvm/Support/FileUtilities.h"
      42             : #include "llvm/Support/Format.h"
      43             : #include "llvm/Support/MemoryBuffer.h"
      44             : #include "llvm/Support/Mutex.h"
      45             : #include "llvm/Support/Program.h"
      46             : #include "llvm/Support/UniqueLock.h"
      47             : #include "llvm/Support/raw_ostream.h"
      48             : #include <algorithm>
      49             : #include <string>
      50             : #ifdef HAVE_BACKTRACE
      51             : # include BACKTRACE_HEADER         // For backtrace().
      52             : #endif
      53             : #if HAVE_SIGNAL_H
      54             : #include <signal.h>
      55             : #endif
      56             : #if HAVE_SYS_STAT_H
      57             : #include <sys/stat.h>
      58             : #endif
      59             : #if HAVE_DLFCN_H
      60             : #include <dlfcn.h>
      61             : #endif
      62             : #if HAVE_MACH_MACH_H
      63             : #include <mach/mach.h>
      64             : #endif
      65             : #if HAVE_LINK_H
      66             : #include <link.h>
      67             : #endif
      68             : #ifdef HAVE__UNWIND_BACKTRACE
      69             : // FIXME: We should be able to use <unwind.h> for any target that has an
      70             : // _Unwind_Backtrace function, but on FreeBSD the configure test passes
      71             : // despite the function not existing, and on Android, <unwind.h> conflicts
      72             : // with <link.h>.
      73             : #ifdef __GLIBC__
      74             : #include <unwind.h>
      75             : #else
      76             : #undef HAVE__UNWIND_BACKTRACE
      77             : #endif
      78             : #endif
      79             : 
      80             : using namespace llvm;
      81             : 
      82             : static RETSIGTYPE SignalHandler(int Sig);  // defined below.
      83             : 
      84             : /// The function to call if ctrl-c is pressed.
      85             : using InterruptFunctionType = void (*)();
      86             : static std::atomic<InterruptFunctionType> InterruptFunction =
      87             :     ATOMIC_VAR_INIT(nullptr);
      88             : 
      89             : namespace {
      90             : /// Signal-safe removal of files.
      91             : /// Inserting and erasing from the list isn't signal-safe, but removal of files
      92             : /// themselves is signal-safe. Memory is freed when the head is freed, deletion
      93             : /// is therefore not signal-safe either.
      94             : class FileToRemoveList {
      95             :   std::atomic<char *> Filename = ATOMIC_VAR_INIT(nullptr);
      96             :   std::atomic<FileToRemoveList *> Next = ATOMIC_VAR_INIT(nullptr);
      97             : 
      98             :   FileToRemoveList() = default;
      99             :   // Not signal-safe.
     100       47850 :   FileToRemoveList(const std::string &str) : Filename(strdup(str.c_str())) {}
     101             : 
     102             : public:
     103             :   // Not signal-safe.
     104       47370 :   ~FileToRemoveList() {
     105       23685 :     if (FileToRemoveList *N = Next.exchange(nullptr))
     106        4079 :       delete N;
     107       23685 :     if (char *F = Filename.exchange(nullptr))
     108       11911 :       free(F);
     109       23685 :   }
     110             : 
     111             :   // Not signal-safe.
     112       23925 :   static void insert(std::atomic<FileToRemoveList *> &Head,
     113             :                      const std::string &Filename) {
     114             :     // Insert the new file at the end of the list.
     115       23925 :     FileToRemoveList *NewHead = new FileToRemoveList(Filename);
     116             :     std::atomic<FileToRemoveList *> *InsertionPoint = &Head;
     117             :     FileToRemoveList *OldHead = nullptr;
     118       39381 :     while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {
     119        7728 :       InsertionPoint = &OldHead->Next;
     120             :       OldHead = nullptr;
     121             :     }
     122       23925 :   }
     123             : 
     124             :   // Not signal-safe.
     125       11997 :   static void erase(std::atomic<FileToRemoveList *> &Head,
     126             :                     const std::string &Filename) {
     127             :     // Use a lock to avoid concurrent erase: the comparison would access
     128             :     // free'd memory.
     129       11997 :     static ManagedStatic<sys::SmartMutex<true>> Lock;
     130       11997 :     sys::SmartScopedLock<true> Writer(*Lock);
     131             : 
     132       52235 :     for (FileToRemoveList *Current = Head.load(); Current;
     133             :          Current = Current->Next.load()) {
     134       20119 :       if (char *OldFilename = Current->Filename.load()) {
     135       13134 :         if (OldFilename != Filename)
     136        1152 :           continue;
     137             :         // Leave an empty filename.
     138             :         OldFilename = Current->Filename.exchange(nullptr);
     139             :         // The filename might have become null between the time we
     140             :         // compared it and we exchanged it.
     141       11982 :         if (OldFilename)
     142       11982 :           free(OldFilename);
     143             :       }
     144             :     }
     145       11997 :   }
     146             : 
     147             :   // Signal-safe.
     148         330 :   static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {
     149             :     // If cleanup were to occur while we're removing files we'd have a bad time.
     150             :     // Make sure we're OK by preventing cleanup from doing anything while we're
     151             :     // removing files. If cleanup races with us and we win we'll have a leak,
     152             :     // but we won't crash.
     153             :     FileToRemoveList *OldHead = Head.exchange(nullptr);
     154             : 
     155         394 :     for (FileToRemoveList *currentFile = OldHead; currentFile;
     156             :          currentFile = currentFile->Next.load()) {
     157             :       // If erasing was occuring while we're trying to remove files we'd look
     158             :       // at free'd data. Take away the path and put it back when done.
     159          32 :       if (char *path = currentFile->Filename.exchange(nullptr)) {
     160             :         // Get the status so we can determine if it's a file or directory. If we
     161             :         // can't stat the file, ignore it.
     162             :         struct stat buf;
     163          29 :         if (stat(path, &buf) != 0)
     164          24 :           continue;
     165             : 
     166             :         // If this is not a regular file, ignore it. We want to prevent removal
     167             :         // of special files like /dev/null, even if the compiler is being run
     168             :         // with the super-user permissions.
     169          28 :         if (!S_ISREG(buf.st_mode))
     170          22 :           continue;
     171             : 
     172             :         // Otherwise, remove the file. We ignore any errors here as there is
     173             :         // nothing else we can do.
     174           6 :         unlink(path);
     175             : 
     176             :         // We're done removing the file, erasing can safely proceed.
     177             :         currentFile->Filename.exchange(path);
     178             :       }
     179             :     }
     180             : 
     181             :     // We're done removing files, cleanup can safely proceed.
     182             :     Head.exchange(OldHead);
     183         330 :   }
     184             : };
     185             : static std::atomic<FileToRemoveList *> FilesToRemove = ATOMIC_VAR_INIT(nullptr);
     186             : 
     187             : /// Clean up the list in a signal-friendly manner.
     188             : /// Recall that signals can fire during llvm_shutdown. If this occurs we should
     189             : /// either clean something up or nothing at all, but we shouldn't crash!
     190             : struct FilesToRemoveCleanup {
     191             :   // Not signal-safe.
     192       19606 :   ~FilesToRemoveCleanup() {
     193             :     FileToRemoveList *Head = FilesToRemove.exchange(nullptr);
     194       19606 :     if (Head)
     195       19606 :       delete Head;
     196       19606 :   }
     197             : };
     198             : } // namespace
     199             : 
     200             : static StringRef Argv0;
     201             : 
     202             : // Signals that represent requested termination. There's no bug or failure, or
     203             : // if there is, it's not our direct responsibility. For whatever reason, our
     204             : // continued execution is no longer desirable.
     205             : static const int IntSigs[] = {
     206             :   SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
     207             : };
     208             : 
     209             : // Signals that represent that we have a bug, and our prompt termination has
     210             : // been ordered.
     211             : static const int KillSigs[] = {
     212             :   SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGQUIT
     213             : #ifdef SIGSYS
     214             :   , SIGSYS
     215             : #endif
     216             : #ifdef SIGXCPU
     217             :   , SIGXCPU
     218             : #endif
     219             : #ifdef SIGXFSZ
     220             :   , SIGXFSZ
     221             : #endif
     222             : #ifdef SIGEMT
     223             :   , SIGEMT
     224             : #endif
     225             : };
     226             : 
     227             : static std::atomic<unsigned> NumRegisteredSignals = ATOMIC_VAR_INIT(0);
     228             : static struct {
     229             :   struct sigaction SA;
     230             :   int SigNo;
     231             : } RegisteredSignalInfo[array_lengthof(IntSigs) + array_lengthof(KillSigs)];
     232             : 
     233             : #if defined(HAVE_SIGALTSTACK)
     234             : // Hold onto both the old and new alternate signal stack so that it's not
     235             : // reported as a leak. We don't make any attempt to remove our alt signal
     236             : // stack if we remove our signal handlers; that can't be done reliably if
     237             : // someone else is also trying to do the same thing.
     238             : static stack_t OldAltStack;
     239             : static void* NewAltStackPointer;
     240             : 
     241      156780 : static void CreateSigAltStack() {
     242             :   const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;
     243             : 
     244             :   // If we're executing on the alternate stack, or we already have an alternate
     245             :   // signal stack that we're happy with, there's nothing for us to do. Don't
     246             :   // reduce the size, some other part of the process might need a larger stack
     247             :   // than we do.
     248      313560 :   if (sigaltstack(nullptr, &OldAltStack) != 0 ||
     249      313560 :       OldAltStack.ss_flags & SS_ONSTACK ||
     250      156780 :       (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))
     251           0 :     return;
     252             : 
     253      156780 :   stack_t AltStack = {};
     254      156780 :   AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize));
     255      156780 :   NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak.
     256      156780 :   AltStack.ss_size = AltStackSize;
     257      156780 :   if (sigaltstack(&AltStack, &OldAltStack) != 0)
     258           0 :     free(AltStack.ss_sp);
     259             : }
     260             : #else
     261             : static void CreateSigAltStack() {}
     262             : #endif
     263             : 
     264      327621 : static void RegisterHandlers() { // Not signal-safe.
     265             :   // The mutex prevents other threads from registering handlers while we're
     266             :   // doing it. We also have to protect the handlers and their count because
     267             :   // a signal handler could fire while we're registeting handlers.
     268      327621 :   static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex;
     269      327621 :   sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex);
     270             : 
     271             :   // If the handlers are already registered, we're done.
     272      327621 :   if (NumRegisteredSignals.load() != 0)
     273             :     return;
     274             : 
     275             :   // Create an alternate stack for signal handling. This is necessary for us to
     276             :   // be able to reliably handle signals due to stack overflow.
     277      156780 :   CreateSigAltStack();
     278             : 
     279     2508480 :   auto registerHandler = [&](int Signal) {
     280             :     unsigned Index = NumRegisteredSignals.load();
     281             :     assert(Index < array_lengthof(RegisteredSignalInfo) &&
     282             :            "Out of space for signal handlers!");
     283             : 
     284             :     struct sigaction NewHandler;
     285             : 
     286     2508480 :     NewHandler.sa_handler = SignalHandler;
     287     2508480 :     NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
     288     2508480 :     sigemptyset(&NewHandler.sa_mask);
     289             : 
     290             :     // Install the new handler, save the old one in RegisteredSignalInfo.
     291     2508480 :     sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
     292     2508480 :     RegisteredSignalInfo[Index].SigNo = Signal;
     293             :     ++NumRegisteredSignals;
     294     2508480 :   };
     295             : 
     296     2038140 :   for (auto S : IntSigs)
     297      940680 :     registerHandler(S);
     298     3292380 :   for (auto S : KillSigs)
     299     1567800 :     registerHandler(S);
     300             : }
     301             : 
     302           9 : static void UnregisterHandlers() {
     303             :   // Restore all of the signal handlers to how they were before we showed up.
     304         153 :   for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {
     305         144 :     sigaction(RegisteredSignalInfo[i].SigNo,
     306         144 :               &RegisteredSignalInfo[i].SA, nullptr);
     307             :     --NumRegisteredSignals;
     308             :   }
     309           9 : }
     310             : 
     311             : /// Process the FilesToRemove list.
     312             : static void RemoveFilesToRemove() {
     313         330 :   FileToRemoveList::removeAllFiles(FilesToRemove);
     314             : }
     315             : 
     316             : // The signal handler that runs.
     317           9 : static RETSIGTYPE SignalHandler(int Sig) {
     318             :   // Restore the signal behavior to default, so that the program actually
     319             :   // crashes when we return and the signal reissues.  This also ensures that if
     320             :   // we crash in our signal handler that the program will terminate immediately
     321             :   // instead of recursing in the signal handler.
     322           9 :   UnregisterHandlers();
     323             : 
     324             :   // Unmask all potentially blocked kill signals.
     325             :   sigset_t SigMask;
     326           9 :   sigfillset(&SigMask);
     327           9 :   sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
     328             : 
     329             :   {
     330             :     RemoveFilesToRemove();
     331             : 
     332           9 :     if (std::find(std::begin(IntSigs), std::end(IntSigs), Sig)
     333             :         != std::end(IntSigs)) {
     334           9 :       if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr))
     335           9 :         return OldInterruptFunction();
     336             : 
     337           9 :       raise(Sig);   // Execute the default handler.
     338           9 :       return;
     339             :    }
     340             :   }
     341             : 
     342             :   // Otherwise if it is a fault (like SEGV) run any handler.
     343           0 :   llvm::sys::RunSignalHandlers();
     344             : 
     345             : #ifdef __s390__
     346             :   // On S/390, certain signals are delivered with PSW Address pointing to
     347             :   // *after* the faulting instruction.  Simply returning from the signal
     348             :   // handler would continue execution after that point, instead of
     349             :   // re-raising the signal.  Raise the signal manually in those cases.
     350             :   if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
     351             :     raise(Sig);
     352             : #endif
     353             : }
     354             : 
     355         321 : void llvm::sys::RunInterruptHandlers() {
     356             :   RemoveFilesToRemove();
     357         321 : }
     358             : 
     359          11 : void llvm::sys::SetInterruptFunction(void (*IF)()) {
     360             :   InterruptFunction.exchange(IF);
     361          11 :   RegisterHandlers();
     362          11 : }
     363             : 
     364             : // The public API
     365       23925 : bool llvm::sys::RemoveFileOnSignal(StringRef Filename,
     366             :                                    std::string* ErrMsg) {
     367             :   // Ensure that cleanup will occur as soon as one file is added.
     368       23925 :   static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup;
     369       23925 :   *FilesToRemoveCleanup;
     370       47850 :   FileToRemoveList::insert(FilesToRemove, Filename.str());
     371       23925 :   RegisterHandlers();
     372       23925 :   return false;
     373             : }
     374             : 
     375             : // The public API
     376       11997 : void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
     377       23994 :   FileToRemoveList::erase(FilesToRemove, Filename.str());
     378       11997 : }
     379             : 
     380             : /// Add a function to be called when a signal is delivered to the process. The
     381             : /// handler can have a cookie passed to it to identify what instance of the
     382             : /// handler it is.
     383      303685 : void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
     384             :                                  void *Cookie) { // Signal-safe.
     385      303685 :   insertSignalHandler(FnPtr, Cookie);
     386      303685 :   RegisterHandlers();
     387      303685 : }
     388             : 
     389             : #if defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && HAVE_LINK_H &&    \
     390             :     (defined(__linux__) || defined(__FreeBSD__) ||                             \
     391             :      defined(__FreeBSD_kernel__) || defined(__NetBSD__))
     392             : struct DlIteratePhdrData {
     393             :   void **StackTrace;
     394             :   int depth;
     395             :   bool first;
     396             :   const char **modules;
     397             :   intptr_t *offsets;
     398             :   const char *main_exec_name;
     399             : };
     400             : 
     401           0 : static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
     402             :   DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
     403           0 :   const char *name = data->first ? data->main_exec_name : info->dlpi_name;
     404           0 :   data->first = false;
     405           0 :   for (int i = 0; i < info->dlpi_phnum; i++) {
     406           0 :     const auto *phdr = &info->dlpi_phdr[i];
     407           0 :     if (phdr->p_type != PT_LOAD)
     408           0 :       continue;
     409           0 :     intptr_t beg = info->dlpi_addr + phdr->p_vaddr;
     410           0 :     intptr_t end = beg + phdr->p_memsz;
     411           0 :     for (int j = 0; j < data->depth; j++) {
     412           0 :       if (data->modules[j])
     413           0 :         continue;
     414           0 :       intptr_t addr = (intptr_t)data->StackTrace[j];
     415           0 :       if (beg <= addr && addr < end) {
     416           0 :         data->modules[j] = name;
     417           0 :         data->offsets[j] = addr - info->dlpi_addr;
     418             :       }
     419             :     }
     420             :   }
     421           0 :   return 0;
     422             : }
     423             : 
     424             : /// If this is an ELF platform, we can find all loaded modules and their virtual
     425             : /// addresses with dl_iterate_phdr.
     426             : static bool findModulesAndOffsets(void **StackTrace, int Depth,
     427             :                                   const char **Modules, intptr_t *Offsets,
     428             :                                   const char *MainExecutableName,
     429             :                                   StringSaver &StrPool) {
     430           0 :   DlIteratePhdrData data = {StackTrace, Depth,   true,
     431           0 :                             Modules,    Offsets, MainExecutableName};
     432           0 :   dl_iterate_phdr(dl_iterate_phdr_cb, &data);
     433             :   return true;
     434             : }
     435             : #else
     436             : /// This platform does not have dl_iterate_phdr, so we do not yet know how to
     437             : /// find all loaded DSOs.
     438             : static bool findModulesAndOffsets(void **StackTrace, int Depth,
     439             :                                   const char **Modules, intptr_t *Offsets,
     440             :                                   const char *MainExecutableName,
     441             :                                   StringSaver &StrPool) {
     442             :   return false;
     443             : }
     444             : #endif // defined(HAVE_BACKTRACE) && ENABLE_BACKTRACES && ...
     445             : 
     446             : #if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)
     447           0 : static int unwindBacktrace(void **StackTrace, int MaxEntries) {
     448           0 :   if (MaxEntries < 0)
     449             :     return 0;
     450             : 
     451             :   // Skip the first frame ('unwindBacktrace' itself).
     452           0 :   int Entries = -1;
     453             : 
     454           0 :   auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code {
     455             :     // Apparently we need to detect reaching the end of the stack ourselves.
     456           0 :     void *IP = (void *)_Unwind_GetIP(Context);
     457           0 :     if (!IP)
     458             :       return _URC_END_OF_STACK;
     459             : 
     460             :     assert(Entries < MaxEntries && "recursively called after END_OF_STACK?");
     461           0 :     if (Entries >= 0)
     462           0 :       StackTrace[Entries] = IP;
     463             : 
     464           0 :     if (++Entries == MaxEntries)
     465             :       return _URC_END_OF_STACK;
     466           0 :     return _URC_NO_REASON;
     467           0 :   };
     468             : 
     469           0 :   _Unwind_Backtrace(
     470           0 :       [](_Unwind_Context *Context, void *Handler) {
     471             :         return (*static_cast<decltype(HandleFrame) *>(Handler))(Context);
     472           0 :       },
     473             :       static_cast<void *>(&HandleFrame));
     474           0 :   return std::max(Entries, 0);
     475             : }
     476             : #endif
     477             : 
     478             : // In the case of a program crash or fault, print out a stack trace so that the
     479             : // user has an indication of why and where we died.
     480             : //
     481             : // On glibc systems we have the 'backtrace' function, which works nicely, but
     482             : // doesn't demangle symbols.
     483           0 : void llvm::sys::PrintStackTrace(raw_ostream &OS) {
     484             : #if ENABLE_BACKTRACES
     485             :   static void *StackTrace[256];
     486             :   int depth = 0;
     487             : #if defined(HAVE_BACKTRACE)
     488             :   // Use backtrace() to output a backtrace on Linux systems with glibc.
     489             :   if (!depth)
     490           0 :     depth = backtrace(StackTrace, static_cast<int>(array_lengthof(StackTrace)));
     491             : #endif
     492             : #if defined(HAVE__UNWIND_BACKTRACE)
     493             :   // Try _Unwind_Backtrace() if backtrace() failed.
     494           0 :   if (!depth)
     495           0 :     depth = unwindBacktrace(StackTrace,
     496             :                         static_cast<int>(array_lengthof(StackTrace)));
     497             : #endif
     498           0 :   if (!depth)
     499             :     return;
     500             : 
     501           0 :   if (printSymbolizedStackTrace(Argv0, StackTrace, depth, OS))
     502             :     return;
     503             : #if HAVE_DLFCN_H && HAVE_DLADDR
     504             :   int width = 0;
     505             :   for (int i = 0; i < depth; ++i) {
     506             :     Dl_info dlinfo;
     507             :     dladdr(StackTrace[i], &dlinfo);
     508             :     const char* name = strrchr(dlinfo.dli_fname, '/');
     509             : 
     510             :     int nwidth;
     511             :     if (!name) nwidth = strlen(dlinfo.dli_fname);
     512             :     else       nwidth = strlen(name) - 1;
     513             : 
     514             :     if (nwidth > width) width = nwidth;
     515             :   }
     516             : 
     517             :   for (int i = 0; i < depth; ++i) {
     518             :     Dl_info dlinfo;
     519             :     dladdr(StackTrace[i], &dlinfo);
     520             : 
     521             :     OS << format("%-2d", i);
     522             : 
     523             :     const char* name = strrchr(dlinfo.dli_fname, '/');
     524             :     if (!name) OS << format(" %-*s", width, dlinfo.dli_fname);
     525             :     else       OS << format(" %-*s", width, name+1);
     526             : 
     527             :     OS << format(" %#0*lx", (int)(sizeof(void*) * 2) + 2,
     528             :                  (unsigned long)StackTrace[i]);
     529             : 
     530             :     if (dlinfo.dli_sname != nullptr) {
     531             :       OS << ' ';
     532             :       int res;
     533             :       char* d = itaniumDemangle(dlinfo.dli_sname, nullptr, nullptr, &res);
     534             :       if (!d) OS << dlinfo.dli_sname;
     535             :       else    OS << d;
     536             :       free(d);
     537             : 
     538             :       // FIXME: When we move to C++11, use %t length modifier. It's not in
     539             :       // C++03 and causes gcc to issue warnings. Losing the upper 32 bits of
     540             :       // the stack offset for a stack dump isn't likely to cause any problems.
     541             :       OS << format(" + %u",(unsigned)((char*)StackTrace[i]-
     542             :                                       (char*)dlinfo.dli_saddr));
     543             :     }
     544             :     OS << '\n';
     545             :   }
     546             : #elif defined(HAVE_BACKTRACE)
     547           0 :   backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
     548             : #endif
     549             : #endif
     550             : }
     551             : 
     552           0 : static void PrintStackTraceSignalHandler(void *) {
     553           0 :   sys::PrintStackTrace(llvm::errs());
     554           0 : }
     555             : 
     556           0 : void llvm::sys::DisableSystemDialogsOnCrash() {}
     557             : 
     558             : /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
     559             : /// process, print a stack trace and then exit.
     560      154696 : void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
     561             :                                              bool DisableCrashReporting) {
     562      154696 :   ::Argv0 = Argv0;
     563             : 
     564      154696 :   AddSignalHandler(PrintStackTraceSignalHandler, nullptr);
     565             : 
     566             : #if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES
     567             :   // Environment variable to disable any kind of crash dialog.
     568             :   if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) {
     569             :     mach_port_t self = mach_task_self();
     570             : 
     571             :     exception_mask_t mask = EXC_MASK_CRASH;
     572             : 
     573             :     kern_return_t ret = task_set_exception_ports(self,
     574             :                              mask,
     575             :                              MACH_PORT_NULL,
     576             :                              EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
     577             :                              THREAD_STATE_NONE);
     578             :     (void)ret;
     579             :   }
     580             : #endif
     581      644005 : }

Generated by: LCOV version 1.13