xref: /freebsd/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
20b57cec5SDimitry Andric//
30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric//
70b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric//
90b57cec5SDimitry Andric// This file defines some helpful functions for dealing with the possibility of
100b57cec5SDimitry Andric// Unix signals occurring while your program is running.
110b57cec5SDimitry Andric//
120b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric//
140b57cec5SDimitry Andric// This file is extremely careful to only do signal-safe things while in a
150b57cec5SDimitry Andric// signal handler. In particular, memory allocation and acquiring a mutex
160b57cec5SDimitry Andric// while in a signal handler should never occur. ManagedStatic isn't usable from
170b57cec5SDimitry Andric// a signal handler for 2 reasons:
180b57cec5SDimitry Andric//
190b57cec5SDimitry Andric//  1. Creating a new one allocates.
200b57cec5SDimitry Andric//  2. The signal handler could fire while llvm_shutdown is being processed, in
210b57cec5SDimitry Andric//     which case the ManagedStatic is in an unknown state because it could
220b57cec5SDimitry Andric//     already have been destroyed, or be in the process of being destroyed.
230b57cec5SDimitry Andric//
240b57cec5SDimitry Andric// Modifying the behavior of the signal handlers (such as registering new ones)
250b57cec5SDimitry Andric// can acquire a mutex, but all this guarantees is that the signal handler
260b57cec5SDimitry Andric// behavior is only modified by one thread at a time. A signal handler can still
270b57cec5SDimitry Andric// fire while this occurs!
280b57cec5SDimitry Andric//
290b57cec5SDimitry Andric// Adding work to a signal handler requires lock-freedom (and assume atomics are
300b57cec5SDimitry Andric// always lock-free) because the signal handler could fire while new work is
310b57cec5SDimitry Andric// being added.
320b57cec5SDimitry Andric//
330b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric#include "Unix.h"
360b57cec5SDimitry Andric#include "llvm/ADT/STLExtras.h"
370b57cec5SDimitry Andric#include "llvm/Config/config.h"
380b57cec5SDimitry Andric#include "llvm/Demangle/Demangle.h"
39e8d8bef9SDimitry Andric#include "llvm/Support/ExitCodes.h"
400b57cec5SDimitry Andric#include "llvm/Support/FileSystem.h"
410b57cec5SDimitry Andric#include "llvm/Support/FileUtilities.h"
420b57cec5SDimitry Andric#include "llvm/Support/Format.h"
430b57cec5SDimitry Andric#include "llvm/Support/MemoryBuffer.h"
440b57cec5SDimitry Andric#include "llvm/Support/Mutex.h"
450b57cec5SDimitry Andric#include "llvm/Support/Program.h"
460b57cec5SDimitry Andric#include "llvm/Support/SaveAndRestore.h"
470b57cec5SDimitry Andric#include "llvm/Support/raw_ostream.h"
480b57cec5SDimitry Andric#include <algorithm>
490b57cec5SDimitry Andric#include <string>
500b57cec5SDimitry Andric#ifdef HAVE_BACKTRACE
510b57cec5SDimitry Andric#include BACKTRACE_HEADER // For backtrace().
520b57cec5SDimitry Andric#endif
530b57cec5SDimitry Andric#if HAVE_SIGNAL_H
540b57cec5SDimitry Andric#include <signal.h>
550b57cec5SDimitry Andric#endif
560b57cec5SDimitry Andric#if HAVE_SYS_STAT_H
570b57cec5SDimitry Andric#include <sys/stat.h>
580b57cec5SDimitry Andric#endif
590b57cec5SDimitry Andric#if HAVE_DLFCN_H
600b57cec5SDimitry Andric#include <dlfcn.h>
610b57cec5SDimitry Andric#endif
620b57cec5SDimitry Andric#if HAVE_MACH_MACH_H
630b57cec5SDimitry Andric#include <mach/mach.h>
640b57cec5SDimitry Andric#endif
6506c3fb27SDimitry Andric#ifdef __APPLE__
6606c3fb27SDimitry Andric#include <mach-o/dyld.h>
6706c3fb27SDimitry Andric#endif
680b57cec5SDimitry Andric#if HAVE_LINK_H
690b57cec5SDimitry Andric#include <link.h>
700b57cec5SDimitry Andric#endif
710b57cec5SDimitry Andric#ifdef HAVE__UNWIND_BACKTRACE
720b57cec5SDimitry Andric// FIXME: We should be able to use <unwind.h> for any target that has an
730b57cec5SDimitry Andric// _Unwind_Backtrace function, but on FreeBSD the configure test passes
740b57cec5SDimitry Andric// despite the function not existing, and on Android, <unwind.h> conflicts
750b57cec5SDimitry Andric// with <link.h>.
760b57cec5SDimitry Andric#ifdef __GLIBC__
770b57cec5SDimitry Andric#include <unwind.h>
780b57cec5SDimitry Andric#else
790b57cec5SDimitry Andric#undef HAVE__UNWIND_BACKTRACE
800b57cec5SDimitry Andric#endif
810b57cec5SDimitry Andric#endif
820b57cec5SDimitry Andric
830b57cec5SDimitry Andricusing namespace llvm;
840b57cec5SDimitry Andric
8581ad6265SDimitry Andricstatic void SignalHandler(int Sig);     // defined below.
8681ad6265SDimitry Andricstatic void InfoSignalHandler(int Sig); // defined below.
870b57cec5SDimitry Andric
880b57cec5SDimitry Andricusing SignalHandlerFunctionType = void (*)();
890b57cec5SDimitry Andric/// The function to call if ctrl-c is pressed.
9006c3fb27SDimitry Andricstatic std::atomic<SignalHandlerFunctionType> InterruptFunction = nullptr;
9106c3fb27SDimitry Andricstatic std::atomic<SignalHandlerFunctionType> InfoSignalFunction = nullptr;
92480093f4SDimitry Andric/// The function to call on SIGPIPE (one-time use only).
93480093f4SDimitry Andricstatic std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction =
9406c3fb27SDimitry Andric    nullptr;
950b57cec5SDimitry Andric
960b57cec5SDimitry Andricnamespace {
970b57cec5SDimitry Andric/// Signal-safe removal of files.
980b57cec5SDimitry Andric/// Inserting and erasing from the list isn't signal-safe, but removal of files
990b57cec5SDimitry Andric/// themselves is signal-safe. Memory is freed when the head is freed, deletion
1000b57cec5SDimitry Andric/// is therefore not signal-safe either.
1010b57cec5SDimitry Andricclass FileToRemoveList {
10206c3fb27SDimitry Andric  std::atomic<char *> Filename = nullptr;
10306c3fb27SDimitry Andric  std::atomic<FileToRemoveList *> Next = nullptr;
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric  FileToRemoveList() = default;
1060b57cec5SDimitry Andric  // Not signal-safe.
1070b57cec5SDimitry Andric  FileToRemoveList(const std::string &str) : Filename(strdup(str.c_str())) {}
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andricpublic:
1100b57cec5SDimitry Andric  // Not signal-safe.
1110b57cec5SDimitry Andric  ~FileToRemoveList() {
1120b57cec5SDimitry Andric    if (FileToRemoveList *N = Next.exchange(nullptr))
1130b57cec5SDimitry Andric      delete N;
1140b57cec5SDimitry Andric    if (char *F = Filename.exchange(nullptr))
1150b57cec5SDimitry Andric      free(F);
1160b57cec5SDimitry Andric  }
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric  // Not signal-safe.
1190b57cec5SDimitry Andric  static void insert(std::atomic<FileToRemoveList *> &Head,
1200b57cec5SDimitry Andric                     const std::string &Filename) {
1210b57cec5SDimitry Andric    // Insert the new file at the end of the list.
1220b57cec5SDimitry Andric    FileToRemoveList *NewHead = new FileToRemoveList(Filename);
1230b57cec5SDimitry Andric    std::atomic<FileToRemoveList *> *InsertionPoint = &Head;
1240b57cec5SDimitry Andric    FileToRemoveList *OldHead = nullptr;
1250b57cec5SDimitry Andric    while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {
1260b57cec5SDimitry Andric      InsertionPoint = &OldHead->Next;
1270b57cec5SDimitry Andric      OldHead = nullptr;
1280b57cec5SDimitry Andric    }
1290b57cec5SDimitry Andric  }
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric  // Not signal-safe.
1320b57cec5SDimitry Andric  static void erase(std::atomic<FileToRemoveList *> &Head,
1330b57cec5SDimitry Andric                    const std::string &Filename) {
1340b57cec5SDimitry Andric    // Use a lock to avoid concurrent erase: the comparison would access
1350b57cec5SDimitry Andric    // free'd memory.
1360b57cec5SDimitry Andric    static ManagedStatic<sys::SmartMutex<true>> Lock;
1370b57cec5SDimitry Andric    sys::SmartScopedLock<true> Writer(*Lock);
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric    for (FileToRemoveList *Current = Head.load(); Current;
1400b57cec5SDimitry Andric         Current = Current->Next.load()) {
1410b57cec5SDimitry Andric      if (char *OldFilename = Current->Filename.load()) {
1420b57cec5SDimitry Andric        if (OldFilename != Filename)
1430b57cec5SDimitry Andric          continue;
1440b57cec5SDimitry Andric        // Leave an empty filename.
1450b57cec5SDimitry Andric        OldFilename = Current->Filename.exchange(nullptr);
1460b57cec5SDimitry Andric        // The filename might have become null between the time we
1470b57cec5SDimitry Andric        // compared it and we exchanged it.
1480b57cec5SDimitry Andric        if (OldFilename)
1490b57cec5SDimitry Andric          free(OldFilename);
1500b57cec5SDimitry Andric      }
1510b57cec5SDimitry Andric    }
1520b57cec5SDimitry Andric  }
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric  // Signal-safe.
1550b57cec5SDimitry Andric  static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {
1560b57cec5SDimitry Andric    // If cleanup were to occur while we're removing files we'd have a bad time.
1570b57cec5SDimitry Andric    // Make sure we're OK by preventing cleanup from doing anything while we're
1580b57cec5SDimitry Andric    // removing files. If cleanup races with us and we win we'll have a leak,
1590b57cec5SDimitry Andric    // but we won't crash.
1600b57cec5SDimitry Andric    FileToRemoveList *OldHead = Head.exchange(nullptr);
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric    for (FileToRemoveList *currentFile = OldHead; currentFile;
1630b57cec5SDimitry Andric         currentFile = currentFile->Next.load()) {
1640b57cec5SDimitry Andric      // If erasing was occuring while we're trying to remove files we'd look
1650b57cec5SDimitry Andric      // at free'd data. Take away the path and put it back when done.
1660b57cec5SDimitry Andric      if (char *path = currentFile->Filename.exchange(nullptr)) {
1670b57cec5SDimitry Andric        // Get the status so we can determine if it's a file or directory. If we
1680b57cec5SDimitry Andric        // can't stat the file, ignore it.
1690b57cec5SDimitry Andric        struct stat buf;
1700b57cec5SDimitry Andric        if (stat(path, &buf) != 0)
1710b57cec5SDimitry Andric          continue;
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric        // If this is not a regular file, ignore it. We want to prevent removal
1740b57cec5SDimitry Andric        // of special files like /dev/null, even if the compiler is being run
1750b57cec5SDimitry Andric        // with the super-user permissions.
1760b57cec5SDimitry Andric        if (!S_ISREG(buf.st_mode))
1770b57cec5SDimitry Andric          continue;
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric        // Otherwise, remove the file. We ignore any errors here as there is
1800b57cec5SDimitry Andric        // nothing else we can do.
1810b57cec5SDimitry Andric        unlink(path);
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric        // We're done removing the file, erasing can safely proceed.
1840b57cec5SDimitry Andric        currentFile->Filename.exchange(path);
1850b57cec5SDimitry Andric      }
1860b57cec5SDimitry Andric    }
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric    // We're done removing files, cleanup can safely proceed.
1890b57cec5SDimitry Andric    Head.exchange(OldHead);
1900b57cec5SDimitry Andric  }
1910b57cec5SDimitry Andric};
19206c3fb27SDimitry Andricstatic std::atomic<FileToRemoveList *> FilesToRemove = nullptr;
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric/// Clean up the list in a signal-friendly manner.
1950b57cec5SDimitry Andric/// Recall that signals can fire during llvm_shutdown. If this occurs we should
1960b57cec5SDimitry Andric/// either clean something up or nothing at all, but we shouldn't crash!
1970b57cec5SDimitry Andricstruct FilesToRemoveCleanup {
1980b57cec5SDimitry Andric  // Not signal-safe.
1990b57cec5SDimitry Andric  ~FilesToRemoveCleanup() {
2000b57cec5SDimitry Andric    FileToRemoveList *Head = FilesToRemove.exchange(nullptr);
2010b57cec5SDimitry Andric    if (Head)
2020b57cec5SDimitry Andric      delete Head;
2030b57cec5SDimitry Andric  }
2040b57cec5SDimitry Andric};
2050b57cec5SDimitry Andric} // namespace
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andricstatic StringRef Argv0;
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric/// Signals that represent requested termination. There's no bug or failure, or
2100b57cec5SDimitry Andric/// if there is, it's not our direct responsibility. For whatever reason, our
2110b57cec5SDimitry Andric/// continued execution is no longer desirable.
212bdd1243dSDimitry Andricstatic const int IntSigs[] = {SIGHUP, SIGINT, SIGTERM, SIGUSR2};
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric/// Signals that represent that we have a bug, and our prompt termination has
2150b57cec5SDimitry Andric/// been ordered.
216bdd1243dSDimitry Andricstatic const int KillSigs[] = {SIGILL,
217bdd1243dSDimitry Andric                               SIGTRAP,
218bdd1243dSDimitry Andric                               SIGABRT,
219bdd1243dSDimitry Andric                               SIGFPE,
220bdd1243dSDimitry Andric                               SIGBUS,
221bdd1243dSDimitry Andric                               SIGSEGV,
222bdd1243dSDimitry Andric                               SIGQUIT
2230b57cec5SDimitry Andric#ifdef SIGSYS
224bdd1243dSDimitry Andric                               ,
225bdd1243dSDimitry Andric                               SIGSYS
2260b57cec5SDimitry Andric#endif
2270b57cec5SDimitry Andric#ifdef SIGXCPU
228bdd1243dSDimitry Andric                               ,
229bdd1243dSDimitry Andric                               SIGXCPU
2300b57cec5SDimitry Andric#endif
2310b57cec5SDimitry Andric#ifdef SIGXFSZ
232bdd1243dSDimitry Andric                               ,
233bdd1243dSDimitry Andric                               SIGXFSZ
2340b57cec5SDimitry Andric#endif
2350b57cec5SDimitry Andric#ifdef SIGEMT
236bdd1243dSDimitry Andric                               ,
237bdd1243dSDimitry Andric                               SIGEMT
2380b57cec5SDimitry Andric#endif
2390b57cec5SDimitry Andric};
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric/// Signals that represent requests for status.
242bdd1243dSDimitry Andricstatic const int InfoSigs[] = {SIGUSR1
2430b57cec5SDimitry Andric#ifdef SIGINFO
244bdd1243dSDimitry Andric                               ,
245bdd1243dSDimitry Andric                               SIGINFO
2460b57cec5SDimitry Andric#endif
2470b57cec5SDimitry Andric};
2480b57cec5SDimitry Andric
249bdd1243dSDimitry Andricstatic const size_t NumSigs = std::size(IntSigs) + std::size(KillSigs) +
250bdd1243dSDimitry Andric                              std::size(InfoSigs) + 1 /* SIGPIPE */;
2510b57cec5SDimitry Andric
25206c3fb27SDimitry Andricstatic std::atomic<unsigned> NumRegisteredSignals = 0;
2530b57cec5SDimitry Andricstatic struct {
2540b57cec5SDimitry Andric  struct sigaction SA;
2550b57cec5SDimitry Andric  int SigNo;
2560b57cec5SDimitry Andric} RegisteredSignalInfo[NumSigs];
2570b57cec5SDimitry Andric
2580b57cec5SDimitry Andric#if defined(HAVE_SIGALTSTACK)
2590b57cec5SDimitry Andric// Hold onto both the old and new alternate signal stack so that it's not
2600b57cec5SDimitry Andric// reported as a leak. We don't make any attempt to remove our alt signal
2610b57cec5SDimitry Andric// stack if we remove our signal handlers; that can't be done reliably if
2620b57cec5SDimitry Andric// someone else is also trying to do the same thing.
2630b57cec5SDimitry Andricstatic stack_t OldAltStack;
264fe6060f1SDimitry AndricLLVM_ATTRIBUTE_USED static void *NewAltStackPointer;
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andricstatic void CreateSigAltStack() {
2670b57cec5SDimitry Andric  const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric  // If we're executing on the alternate stack, or we already have an alternate
2700b57cec5SDimitry Andric  // signal stack that we're happy with, there's nothing for us to do. Don't
2710b57cec5SDimitry Andric  // reduce the size, some other part of the process might need a larger stack
2720b57cec5SDimitry Andric  // than we do.
2730b57cec5SDimitry Andric  if (sigaltstack(nullptr, &OldAltStack) != 0 ||
2740b57cec5SDimitry Andric      OldAltStack.ss_flags & SS_ONSTACK ||
2750b57cec5SDimitry Andric      (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))
2760b57cec5SDimitry Andric    return;
2770b57cec5SDimitry Andric
2780b57cec5SDimitry Andric  stack_t AltStack = {};
2790b57cec5SDimitry Andric  AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize));
2800b57cec5SDimitry Andric  NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak.
2810b57cec5SDimitry Andric  AltStack.ss_size = AltStackSize;
2820b57cec5SDimitry Andric  if (sigaltstack(&AltStack, &OldAltStack) != 0)
2830b57cec5SDimitry Andric    free(AltStack.ss_sp);
2840b57cec5SDimitry Andric}
2850b57cec5SDimitry Andric#else
2860b57cec5SDimitry Andricstatic void CreateSigAltStack() {}
2870b57cec5SDimitry Andric#endif
2880b57cec5SDimitry Andric
2890b57cec5SDimitry Andricstatic void RegisterHandlers() { // Not signal-safe.
2900b57cec5SDimitry Andric  // The mutex prevents other threads from registering handlers while we're
2910b57cec5SDimitry Andric  // doing it. We also have to protect the handlers and their count because
292*0fca6ea1SDimitry Andric  // a signal handler could fire while we're registering handlers.
2930b57cec5SDimitry Andric  static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex;
2940b57cec5SDimitry Andric  sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex);
2950b57cec5SDimitry Andric
2960b57cec5SDimitry Andric  // If the handlers are already registered, we're done.
2970b57cec5SDimitry Andric  if (NumRegisteredSignals.load() != 0)
2980b57cec5SDimitry Andric    return;
2990b57cec5SDimitry Andric
3000b57cec5SDimitry Andric  // Create an alternate stack for signal handling. This is necessary for us to
3010b57cec5SDimitry Andric  // be able to reliably handle signals due to stack overflow.
3020b57cec5SDimitry Andric  CreateSigAltStack();
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric  enum class SignalKind { IsKill, IsInfo };
3050b57cec5SDimitry Andric  auto registerHandler = [&](int Signal, SignalKind Kind) {
3060b57cec5SDimitry Andric    unsigned Index = NumRegisteredSignals.load();
307bdd1243dSDimitry Andric    assert(Index < std::size(RegisteredSignalInfo) &&
3080b57cec5SDimitry Andric           "Out of space for signal handlers!");
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric    struct sigaction NewHandler;
3110b57cec5SDimitry Andric
3120b57cec5SDimitry Andric    switch (Kind) {
3130b57cec5SDimitry Andric    case SignalKind::IsKill:
3140b57cec5SDimitry Andric      NewHandler.sa_handler = SignalHandler;
3150b57cec5SDimitry Andric      NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK;
3160b57cec5SDimitry Andric      break;
3170b57cec5SDimitry Andric    case SignalKind::IsInfo:
3180b57cec5SDimitry Andric      NewHandler.sa_handler = InfoSignalHandler;
3190b57cec5SDimitry Andric      NewHandler.sa_flags = SA_ONSTACK;
3200b57cec5SDimitry Andric      break;
3210b57cec5SDimitry Andric    }
3220b57cec5SDimitry Andric    sigemptyset(&NewHandler.sa_mask);
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric    // Install the new handler, save the old one in RegisteredSignalInfo.
3250b57cec5SDimitry Andric    sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);
3260b57cec5SDimitry Andric    RegisteredSignalInfo[Index].SigNo = Signal;
3270b57cec5SDimitry Andric    ++NumRegisteredSignals;
3280b57cec5SDimitry Andric  };
3290b57cec5SDimitry Andric
3300b57cec5SDimitry Andric  for (auto S : IntSigs)
3310b57cec5SDimitry Andric    registerHandler(S, SignalKind::IsKill);
3320b57cec5SDimitry Andric  for (auto S : KillSigs)
3330b57cec5SDimitry Andric    registerHandler(S, SignalKind::IsKill);
334480093f4SDimitry Andric  if (OneShotPipeSignalFunction)
335480093f4SDimitry Andric    registerHandler(SIGPIPE, SignalKind::IsKill);
3360b57cec5SDimitry Andric  for (auto S : InfoSigs)
3370b57cec5SDimitry Andric    registerHandler(S, SignalKind::IsInfo);
3380b57cec5SDimitry Andric}
3390b57cec5SDimitry Andric
340e8d8bef9SDimitry Andricvoid sys::unregisterHandlers() {
3410b57cec5SDimitry Andric  // Restore all of the signal handlers to how they were before we showed up.
3420b57cec5SDimitry Andric  for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {
343bdd1243dSDimitry Andric    sigaction(RegisteredSignalInfo[i].SigNo, &RegisteredSignalInfo[i].SA,
344bdd1243dSDimitry Andric              nullptr);
3450b57cec5SDimitry Andric    --NumRegisteredSignals;
3460b57cec5SDimitry Andric  }
3470b57cec5SDimitry Andric}
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andric/// Process the FilesToRemove list.
3500b57cec5SDimitry Andricstatic void RemoveFilesToRemove() {
3510b57cec5SDimitry Andric  FileToRemoveList::removeAllFiles(FilesToRemove);
3520b57cec5SDimitry Andric}
3530b57cec5SDimitry Andric
354480093f4SDimitry Andricvoid sys::CleanupOnSignal(uintptr_t Context) {
355480093f4SDimitry Andric  int Sig = (int)Context;
356480093f4SDimitry Andric
357480093f4SDimitry Andric  if (llvm::is_contained(InfoSigs, Sig)) {
358480093f4SDimitry Andric    InfoSignalHandler(Sig);
359480093f4SDimitry Andric    return;
360480093f4SDimitry Andric  }
361480093f4SDimitry Andric
362480093f4SDimitry Andric  RemoveFilesToRemove();
363480093f4SDimitry Andric
364480093f4SDimitry Andric  if (llvm::is_contained(IntSigs, Sig) || Sig == SIGPIPE)
365480093f4SDimitry Andric    return;
366480093f4SDimitry Andric
367480093f4SDimitry Andric  llvm::sys::RunSignalHandlers();
368480093f4SDimitry Andric}
369480093f4SDimitry Andric
3700b57cec5SDimitry Andric// The signal handler that runs.
37181ad6265SDimitry Andricstatic void SignalHandler(int Sig) {
3720b57cec5SDimitry Andric  // Restore the signal behavior to default, so that the program actually
3730b57cec5SDimitry Andric  // crashes when we return and the signal reissues.  This also ensures that if
3740b57cec5SDimitry Andric  // we crash in our signal handler that the program will terminate immediately
3750b57cec5SDimitry Andric  // instead of recursing in the signal handler.
376e8d8bef9SDimitry Andric  sys::unregisterHandlers();
3770b57cec5SDimitry Andric
3780b57cec5SDimitry Andric  // Unmask all potentially blocked kill signals.
3790b57cec5SDimitry Andric  sigset_t SigMask;
3800b57cec5SDimitry Andric  sigfillset(&SigMask);
3810b57cec5SDimitry Andric  sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
3820b57cec5SDimitry Andric
3830b57cec5SDimitry Andric  {
3840b57cec5SDimitry Andric    RemoveFilesToRemove();
3850b57cec5SDimitry Andric
386480093f4SDimitry Andric    if (Sig == SIGPIPE)
387480093f4SDimitry Andric      if (auto OldOneShotPipeFunction =
388480093f4SDimitry Andric              OneShotPipeSignalFunction.exchange(nullptr))
389480093f4SDimitry Andric        return OldOneShotPipeFunction();
390480093f4SDimitry Andric
391e8d8bef9SDimitry Andric    bool IsIntSig = llvm::is_contained(IntSigs, Sig);
392e8d8bef9SDimitry Andric    if (IsIntSig)
3930b57cec5SDimitry Andric      if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr))
3940b57cec5SDimitry Andric        return OldInterruptFunction();
3950b57cec5SDimitry Andric
396e8d8bef9SDimitry Andric    if (Sig == SIGPIPE || IsIntSig) {
3970b57cec5SDimitry Andric      raise(Sig); // Execute the default handler.
3980b57cec5SDimitry Andric      return;
3990b57cec5SDimitry Andric    }
4000b57cec5SDimitry Andric  }
4010b57cec5SDimitry Andric
4020b57cec5SDimitry Andric  // Otherwise if it is a fault (like SEGV) run any handler.
4030b57cec5SDimitry Andric  llvm::sys::RunSignalHandlers();
4040b57cec5SDimitry Andric
4050b57cec5SDimitry Andric#ifdef __s390__
4060b57cec5SDimitry Andric  // On S/390, certain signals are delivered with PSW Address pointing to
4070b57cec5SDimitry Andric  // *after* the faulting instruction.  Simply returning from the signal
4080b57cec5SDimitry Andric  // handler would continue execution after that point, instead of
4090b57cec5SDimitry Andric  // re-raising the signal.  Raise the signal manually in those cases.
4100b57cec5SDimitry Andric  if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)
4110b57cec5SDimitry Andric    raise(Sig);
4120b57cec5SDimitry Andric#endif
4130b57cec5SDimitry Andric}
4140b57cec5SDimitry Andric
41581ad6265SDimitry Andricstatic void InfoSignalHandler(int Sig) {
416bdd1243dSDimitry Andric  SaveAndRestore SaveErrnoDuringASignalHandler(errno);
4170b57cec5SDimitry Andric  if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)
4180b57cec5SDimitry Andric    CurrentInfoFunction();
4190b57cec5SDimitry Andric}
4200b57cec5SDimitry Andric
421bdd1243dSDimitry Andricvoid llvm::sys::RunInterruptHandlers() { RemoveFilesToRemove(); }
4220b57cec5SDimitry Andric
4230b57cec5SDimitry Andricvoid llvm::sys::SetInterruptFunction(void (*IF)()) {
4240b57cec5SDimitry Andric  InterruptFunction.exchange(IF);
4250b57cec5SDimitry Andric  RegisterHandlers();
4260b57cec5SDimitry Andric}
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andricvoid llvm::sys::SetInfoSignalFunction(void (*Handler)()) {
4290b57cec5SDimitry Andric  InfoSignalFunction.exchange(Handler);
4300b57cec5SDimitry Andric  RegisterHandlers();
4310b57cec5SDimitry Andric}
4320b57cec5SDimitry Andric
433480093f4SDimitry Andricvoid llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) {
434480093f4SDimitry Andric  OneShotPipeSignalFunction.exchange(Handler);
4358bcb0991SDimitry Andric  RegisterHandlers();
4368bcb0991SDimitry Andric}
4378bcb0991SDimitry Andric
438480093f4SDimitry Andricvoid llvm::sys::DefaultOneShotPipeSignalHandler() {
439480093f4SDimitry Andric  // Send a special return code that drivers can check for, from sysexits.h.
440480093f4SDimitry Andric  exit(EX_IOERR);
441480093f4SDimitry Andric}
442480093f4SDimitry Andric
4430b57cec5SDimitry Andric// The public API
444bdd1243dSDimitry Andricbool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg) {
4450b57cec5SDimitry Andric  // Ensure that cleanup will occur as soon as one file is added.
4460b57cec5SDimitry Andric  static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup;
4470b57cec5SDimitry Andric  *FilesToRemoveCleanup;
4480b57cec5SDimitry Andric  FileToRemoveList::insert(FilesToRemove, Filename.str());
4490b57cec5SDimitry Andric  RegisterHandlers();
4500b57cec5SDimitry Andric  return false;
4510b57cec5SDimitry Andric}
4520b57cec5SDimitry Andric
4530b57cec5SDimitry Andric// The public API
4540b57cec5SDimitry Andricvoid llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {
4550b57cec5SDimitry Andric  FileToRemoveList::erase(FilesToRemove, Filename.str());
4560b57cec5SDimitry Andric}
4570b57cec5SDimitry Andric
4580b57cec5SDimitry Andric/// Add a function to be called when a signal is delivered to the process. The
4590b57cec5SDimitry Andric/// handler can have a cookie passed to it to identify what instance of the
4600b57cec5SDimitry Andric/// handler it is.
4610b57cec5SDimitry Andricvoid llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
4620b57cec5SDimitry Andric                                 void *Cookie) { // Signal-safe.
4630b57cec5SDimitry Andric  insertSignalHandler(FnPtr, Cookie);
4640b57cec5SDimitry Andric  RegisterHandlers();
4650b57cec5SDimitry Andric}
4660b57cec5SDimitry Andric
46706c3fb27SDimitry Andric#if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) && HAVE_LINK_H &&             \
4680b57cec5SDimitry Andric    (defined(__linux__) || defined(__FreeBSD__) ||                             \
4690b57cec5SDimitry Andric     defined(__FreeBSD_kernel__) || defined(__NetBSD__))
4700b57cec5SDimitry Andricstruct DlIteratePhdrData {
4710b57cec5SDimitry Andric  void **StackTrace;
4720b57cec5SDimitry Andric  int depth;
4730b57cec5SDimitry Andric  bool first;
4740b57cec5SDimitry Andric  const char **modules;
4750b57cec5SDimitry Andric  intptr_t *offsets;
4760b57cec5SDimitry Andric  const char *main_exec_name;
4770b57cec5SDimitry Andric};
4780b57cec5SDimitry Andric
4790b57cec5SDimitry Andricstatic int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
4800b57cec5SDimitry Andric  DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
4810b57cec5SDimitry Andric  const char *name = data->first ? data->main_exec_name : info->dlpi_name;
4820b57cec5SDimitry Andric  data->first = false;
4830b57cec5SDimitry Andric  for (int i = 0; i < info->dlpi_phnum; i++) {
4840b57cec5SDimitry Andric    const auto *phdr = &info->dlpi_phdr[i];
4850b57cec5SDimitry Andric    if (phdr->p_type != PT_LOAD)
4860b57cec5SDimitry Andric      continue;
4870b57cec5SDimitry Andric    intptr_t beg = info->dlpi_addr + phdr->p_vaddr;
4880b57cec5SDimitry Andric    intptr_t end = beg + phdr->p_memsz;
4890b57cec5SDimitry Andric    for (int j = 0; j < data->depth; j++) {
4900b57cec5SDimitry Andric      if (data->modules[j])
4910b57cec5SDimitry Andric        continue;
4920b57cec5SDimitry Andric      intptr_t addr = (intptr_t)data->StackTrace[j];
4930b57cec5SDimitry Andric      if (beg <= addr && addr < end) {
4940b57cec5SDimitry Andric        data->modules[j] = name;
4950b57cec5SDimitry Andric        data->offsets[j] = addr - info->dlpi_addr;
4960b57cec5SDimitry Andric      }
4970b57cec5SDimitry Andric    }
4980b57cec5SDimitry Andric  }
4990b57cec5SDimitry Andric  return 0;
5000b57cec5SDimitry Andric}
5010b57cec5SDimitry Andric
5020b57cec5SDimitry Andric/// If this is an ELF platform, we can find all loaded modules and their virtual
5030b57cec5SDimitry Andric/// addresses with dl_iterate_phdr.
5040b57cec5SDimitry Andricstatic bool findModulesAndOffsets(void **StackTrace, int Depth,
5050b57cec5SDimitry Andric                                  const char **Modules, intptr_t *Offsets,
5060b57cec5SDimitry Andric                                  const char *MainExecutableName,
5070b57cec5SDimitry Andric                                  StringSaver &StrPool) {
5080b57cec5SDimitry Andric  DlIteratePhdrData data = {StackTrace, Depth,   true,
5090b57cec5SDimitry Andric                            Modules,    Offsets, MainExecutableName};
5100b57cec5SDimitry Andric  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
5110b57cec5SDimitry Andric  return true;
5120b57cec5SDimitry Andric}
5135f757f3fSDimitry Andric
5145f757f3fSDimitry Andricclass DSOMarkupPrinter {
5155f757f3fSDimitry Andric  llvm::raw_ostream &OS;
5165f757f3fSDimitry Andric  const char *MainExecutableName;
5175f757f3fSDimitry Andric  size_t ModuleCount = 0;
5185f757f3fSDimitry Andric  bool IsFirst = true;
5195f757f3fSDimitry Andric
5205f757f3fSDimitry Andricpublic:
5215f757f3fSDimitry Andric  DSOMarkupPrinter(llvm::raw_ostream &OS, const char *MainExecutableName)
5225f757f3fSDimitry Andric      : OS(OS), MainExecutableName(MainExecutableName) {}
5235f757f3fSDimitry Andric
5245f757f3fSDimitry Andric  /// Print llvm-symbolizer markup describing the layout of the given DSO.
5255f757f3fSDimitry Andric  void printDSOMarkup(dl_phdr_info *Info) {
5265f757f3fSDimitry Andric    ArrayRef<uint8_t> BuildID = findBuildID(Info);
5275f757f3fSDimitry Andric    if (BuildID.empty())
5285f757f3fSDimitry Andric      return;
5295f757f3fSDimitry Andric    OS << format("{{{module:%d:%s:elf:", ModuleCount,
5305f757f3fSDimitry Andric                 IsFirst ? MainExecutableName : Info->dlpi_name);
5315f757f3fSDimitry Andric    for (uint8_t X : BuildID)
5325f757f3fSDimitry Andric      OS << format("%02x", X);
5335f757f3fSDimitry Andric    OS << "}}}\n";
5345f757f3fSDimitry Andric
5355f757f3fSDimitry Andric    for (int I = 0; I < Info->dlpi_phnum; I++) {
5365f757f3fSDimitry Andric      const auto *Phdr = &Info->dlpi_phdr[I];
5375f757f3fSDimitry Andric      if (Phdr->p_type != PT_LOAD)
5385f757f3fSDimitry Andric        continue;
5395f757f3fSDimitry Andric      uintptr_t StartAddress = Info->dlpi_addr + Phdr->p_vaddr;
5405f757f3fSDimitry Andric      uintptr_t ModuleRelativeAddress = Phdr->p_vaddr;
5415f757f3fSDimitry Andric      std::array<char, 4> ModeStr = modeStrFromFlags(Phdr->p_flags);
5425f757f3fSDimitry Andric      OS << format("{{{mmap:%#016x:%#x:load:%d:%s:%#016x}}}\n", StartAddress,
5435f757f3fSDimitry Andric                   Phdr->p_memsz, ModuleCount, &ModeStr[0],
5445f757f3fSDimitry Andric                   ModuleRelativeAddress);
5455f757f3fSDimitry Andric    }
5465f757f3fSDimitry Andric    IsFirst = false;
5475f757f3fSDimitry Andric    ModuleCount++;
5485f757f3fSDimitry Andric  }
5495f757f3fSDimitry Andric
5505f757f3fSDimitry Andric  /// Callback for use with dl_iterate_phdr. The last dl_iterate_phdr argument
5515f757f3fSDimitry Andric  /// must be a pointer to an instance of this class.
5525f757f3fSDimitry Andric  static int printDSOMarkup(dl_phdr_info *Info, size_t Size, void *Arg) {
5535f757f3fSDimitry Andric    static_cast<DSOMarkupPrinter *>(Arg)->printDSOMarkup(Info);
5545f757f3fSDimitry Andric    return 0;
5555f757f3fSDimitry Andric  }
5565f757f3fSDimitry Andric
5575f757f3fSDimitry Andric  // Returns the build ID for the given DSO as an array of bytes. Returns an
5585f757f3fSDimitry Andric  // empty array if none could be found.
5595f757f3fSDimitry Andric  ArrayRef<uint8_t> findBuildID(dl_phdr_info *Info) {
5605f757f3fSDimitry Andric    for (int I = 0; I < Info->dlpi_phnum; I++) {
5615f757f3fSDimitry Andric      const auto *Phdr = &Info->dlpi_phdr[I];
5625f757f3fSDimitry Andric      if (Phdr->p_type != PT_NOTE)
5635f757f3fSDimitry Andric        continue;
5645f757f3fSDimitry Andric
5655f757f3fSDimitry Andric      ArrayRef<uint8_t> Notes(
5665f757f3fSDimitry Andric          reinterpret_cast<const uint8_t *>(Info->dlpi_addr + Phdr->p_vaddr),
5675f757f3fSDimitry Andric          Phdr->p_memsz);
5685f757f3fSDimitry Andric      while (Notes.size() > 12) {
5695f757f3fSDimitry Andric        uint32_t NameSize = *reinterpret_cast<const uint32_t *>(Notes.data());
5705f757f3fSDimitry Andric        Notes = Notes.drop_front(4);
5715f757f3fSDimitry Andric        uint32_t DescSize = *reinterpret_cast<const uint32_t *>(Notes.data());
5725f757f3fSDimitry Andric        Notes = Notes.drop_front(4);
5735f757f3fSDimitry Andric        uint32_t Type = *reinterpret_cast<const uint32_t *>(Notes.data());
5745f757f3fSDimitry Andric        Notes = Notes.drop_front(4);
5755f757f3fSDimitry Andric
5765f757f3fSDimitry Andric        ArrayRef<uint8_t> Name = Notes.take_front(NameSize);
5775f757f3fSDimitry Andric        auto CurPos = reinterpret_cast<uintptr_t>(Notes.data());
5785f757f3fSDimitry Andric        uint32_t BytesUntilDesc =
5795f757f3fSDimitry Andric            alignToPowerOf2(CurPos + NameSize, 4) - CurPos;
5805f757f3fSDimitry Andric        if (BytesUntilDesc >= Notes.size())
5815f757f3fSDimitry Andric          break;
5825f757f3fSDimitry Andric        Notes = Notes.drop_front(BytesUntilDesc);
5835f757f3fSDimitry Andric
5845f757f3fSDimitry Andric        ArrayRef<uint8_t> Desc = Notes.take_front(DescSize);
5855f757f3fSDimitry Andric        CurPos = reinterpret_cast<uintptr_t>(Notes.data());
5865f757f3fSDimitry Andric        uint32_t BytesUntilNextNote =
5875f757f3fSDimitry Andric            alignToPowerOf2(CurPos + DescSize, 4) - CurPos;
5885f757f3fSDimitry Andric        if (BytesUntilNextNote > Notes.size())
5895f757f3fSDimitry Andric          break;
5905f757f3fSDimitry Andric        Notes = Notes.drop_front(BytesUntilNextNote);
5915f757f3fSDimitry Andric
5925f757f3fSDimitry Andric        if (Type == 3 /*NT_GNU_BUILD_ID*/ && Name.size() >= 3 &&
5935f757f3fSDimitry Andric            Name[0] == 'G' && Name[1] == 'N' && Name[2] == 'U')
5945f757f3fSDimitry Andric          return Desc;
5955f757f3fSDimitry Andric      }
5965f757f3fSDimitry Andric    }
5975f757f3fSDimitry Andric    return {};
5985f757f3fSDimitry Andric  }
5995f757f3fSDimitry Andric
6005f757f3fSDimitry Andric  // Returns a symbolizer markup string describing the permissions on a DSO
6015f757f3fSDimitry Andric  // with the given p_flags.
6025f757f3fSDimitry Andric  std::array<char, 4> modeStrFromFlags(uint32_t Flags) {
6035f757f3fSDimitry Andric    std::array<char, 4> Mode;
6045f757f3fSDimitry Andric    char *Cur = &Mode[0];
6055f757f3fSDimitry Andric    if (Flags & PF_R)
6065f757f3fSDimitry Andric      *Cur++ = 'r';
6075f757f3fSDimitry Andric    if (Flags & PF_W)
6085f757f3fSDimitry Andric      *Cur++ = 'w';
6095f757f3fSDimitry Andric    if (Flags & PF_X)
6105f757f3fSDimitry Andric      *Cur++ = 'x';
6115f757f3fSDimitry Andric    *Cur = '\0';
6125f757f3fSDimitry Andric    return Mode;
6135f757f3fSDimitry Andric  }
6145f757f3fSDimitry Andric};
6155f757f3fSDimitry Andric
6165f757f3fSDimitry Andricstatic bool printMarkupContext(llvm::raw_ostream &OS,
6175f757f3fSDimitry Andric                               const char *MainExecutableName) {
6185f757f3fSDimitry Andric  OS << "{{{reset}}}\n";
6195f757f3fSDimitry Andric  DSOMarkupPrinter MP(OS, MainExecutableName);
6205f757f3fSDimitry Andric  dl_iterate_phdr(DSOMarkupPrinter::printDSOMarkup, &MP);
6215f757f3fSDimitry Andric  return true;
6225f757f3fSDimitry Andric}
6235f757f3fSDimitry Andric
62406c3fb27SDimitry Andric#elif ENABLE_BACKTRACES && defined(__APPLE__) && defined(__LP64__)
62506c3fb27SDimitry Andricstatic bool findModulesAndOffsets(void **StackTrace, int Depth,
62606c3fb27SDimitry Andric                                  const char **Modules, intptr_t *Offsets,
62706c3fb27SDimitry Andric                                  const char *MainExecutableName,
62806c3fb27SDimitry Andric                                  StringSaver &StrPool) {
62906c3fb27SDimitry Andric  uint32_t NumImgs = _dyld_image_count();
63006c3fb27SDimitry Andric  for (uint32_t ImageIndex = 0; ImageIndex < NumImgs; ImageIndex++) {
63106c3fb27SDimitry Andric    const char *Name = _dyld_get_image_name(ImageIndex);
63206c3fb27SDimitry Andric    intptr_t Slide = _dyld_get_image_vmaddr_slide(ImageIndex);
63306c3fb27SDimitry Andric    auto *Header =
63406c3fb27SDimitry Andric        (const struct mach_header_64 *)_dyld_get_image_header(ImageIndex);
63506c3fb27SDimitry Andric    if (Header == NULL)
63606c3fb27SDimitry Andric      continue;
63706c3fb27SDimitry Andric    auto Cmd = (const struct load_command *)(&Header[1]);
63806c3fb27SDimitry Andric    for (uint32_t CmdNum = 0; CmdNum < Header->ncmds; ++CmdNum) {
63906c3fb27SDimitry Andric      uint32_t BaseCmd = Cmd->cmd & ~LC_REQ_DYLD;
64006c3fb27SDimitry Andric      if (BaseCmd == LC_SEGMENT_64) {
64106c3fb27SDimitry Andric        auto CmdSeg64 = (const struct segment_command_64 *)Cmd;
64206c3fb27SDimitry Andric        for (int j = 0; j < Depth; j++) {
64306c3fb27SDimitry Andric          if (Modules[j])
64406c3fb27SDimitry Andric            continue;
64506c3fb27SDimitry Andric          intptr_t Addr = (intptr_t)StackTrace[j];
64606c3fb27SDimitry Andric          if ((intptr_t)CmdSeg64->vmaddr + Slide <= Addr &&
64706c3fb27SDimitry Andric              Addr < intptr_t(CmdSeg64->vmaddr + CmdSeg64->vmsize + Slide)) {
64806c3fb27SDimitry Andric            Modules[j] = Name;
64906c3fb27SDimitry Andric            Offsets[j] = Addr - Slide;
65006c3fb27SDimitry Andric          }
65106c3fb27SDimitry Andric        }
65206c3fb27SDimitry Andric      }
65306c3fb27SDimitry Andric      Cmd = (const load_command *)(((const char *)Cmd) + (Cmd->cmdsize));
65406c3fb27SDimitry Andric    }
65506c3fb27SDimitry Andric  }
65606c3fb27SDimitry Andric  return true;
65706c3fb27SDimitry Andric}
6585f757f3fSDimitry Andric
6595f757f3fSDimitry Andricstatic bool printMarkupContext(llvm::raw_ostream &OS,
6605f757f3fSDimitry Andric                               const char *MainExecutableName) {
6615f757f3fSDimitry Andric  return false;
6625f757f3fSDimitry Andric}
6630b57cec5SDimitry Andric#else
66406c3fb27SDimitry Andric/// Backtraces are not enabled or we don't yet know how to find all loaded DSOs
66506c3fb27SDimitry Andric/// on this platform.
6660b57cec5SDimitry Andricstatic bool findModulesAndOffsets(void **StackTrace, int Depth,
6670b57cec5SDimitry Andric                                  const char **Modules, intptr_t *Offsets,
6680b57cec5SDimitry Andric                                  const char *MainExecutableName,
6690b57cec5SDimitry Andric                                  StringSaver &StrPool) {
6700b57cec5SDimitry Andric  return false;
6710b57cec5SDimitry Andric}
6725f757f3fSDimitry Andric
6735f757f3fSDimitry Andricstatic bool printMarkupContext(llvm::raw_ostream &OS,
6745f757f3fSDimitry Andric                               const char *MainExecutableName) {
6755f757f3fSDimitry Andric  return false;
6765f757f3fSDimitry Andric}
67706c3fb27SDimitry Andric#endif // ENABLE_BACKTRACES && ... (findModulesAndOffsets variants)
6780b57cec5SDimitry Andric
6790b57cec5SDimitry Andric#if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)
6800b57cec5SDimitry Andricstatic int unwindBacktrace(void **StackTrace, int MaxEntries) {
6810b57cec5SDimitry Andric  if (MaxEntries < 0)
6820b57cec5SDimitry Andric    return 0;
6830b57cec5SDimitry Andric
6840b57cec5SDimitry Andric  // Skip the first frame ('unwindBacktrace' itself).
6850b57cec5SDimitry Andric  int Entries = -1;
6860b57cec5SDimitry Andric
6870b57cec5SDimitry Andric  auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code {
6880b57cec5SDimitry Andric    // Apparently we need to detect reaching the end of the stack ourselves.
6890b57cec5SDimitry Andric    void *IP = (void *)_Unwind_GetIP(Context);
6900b57cec5SDimitry Andric    if (!IP)
6910b57cec5SDimitry Andric      return _URC_END_OF_STACK;
6920b57cec5SDimitry Andric
6930b57cec5SDimitry Andric    assert(Entries < MaxEntries && "recursively called after END_OF_STACK?");
6940b57cec5SDimitry Andric    if (Entries >= 0)
6950b57cec5SDimitry Andric      StackTrace[Entries] = IP;
6960b57cec5SDimitry Andric
6970b57cec5SDimitry Andric    if (++Entries == MaxEntries)
6980b57cec5SDimitry Andric      return _URC_END_OF_STACK;
6990b57cec5SDimitry Andric    return _URC_NO_REASON;
7000b57cec5SDimitry Andric  };
7010b57cec5SDimitry Andric
7020b57cec5SDimitry Andric  _Unwind_Backtrace(
7030b57cec5SDimitry Andric      [](_Unwind_Context *Context, void *Handler) {
7040b57cec5SDimitry Andric        return (*static_cast<decltype(HandleFrame) *>(Handler))(Context);
7050b57cec5SDimitry Andric      },
7060b57cec5SDimitry Andric      static_cast<void *>(&HandleFrame));
7070b57cec5SDimitry Andric  return std::max(Entries, 0);
7080b57cec5SDimitry Andric}
7090b57cec5SDimitry Andric#endif
7100b57cec5SDimitry Andric
7110b57cec5SDimitry Andric// In the case of a program crash or fault, print out a stack trace so that the
7120b57cec5SDimitry Andric// user has an indication of why and where we died.
7130b57cec5SDimitry Andric//
7140b57cec5SDimitry Andric// On glibc systems we have the 'backtrace' function, which works nicely, but
7150b57cec5SDimitry Andric// doesn't demangle symbols.
716e8d8bef9SDimitry Andricvoid llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {
7170b57cec5SDimitry Andric#if ENABLE_BACKTRACES
7180b57cec5SDimitry Andric  static void *StackTrace[256];
7190b57cec5SDimitry Andric  int depth = 0;
7200b57cec5SDimitry Andric#if defined(HAVE_BACKTRACE)
7210b57cec5SDimitry Andric  // Use backtrace() to output a backtrace on Linux systems with glibc.
7220b57cec5SDimitry Andric  if (!depth)
723bdd1243dSDimitry Andric    depth = backtrace(StackTrace, static_cast<int>(std::size(StackTrace)));
7240b57cec5SDimitry Andric#endif
7250b57cec5SDimitry Andric#if defined(HAVE__UNWIND_BACKTRACE)
7260b57cec5SDimitry Andric  // Try _Unwind_Backtrace() if backtrace() failed.
7270b57cec5SDimitry Andric  if (!depth)
728bdd1243dSDimitry Andric    depth =
729bdd1243dSDimitry Andric        unwindBacktrace(StackTrace, static_cast<int>(std::size(StackTrace)));
7300b57cec5SDimitry Andric#endif
7310b57cec5SDimitry Andric  if (!depth)
7320b57cec5SDimitry Andric    return;
733e8d8bef9SDimitry Andric  // If "Depth" is not provided by the caller, use the return value of
734e8d8bef9SDimitry Andric  // backtrace() for printing a symbolized stack trace.
735e8d8bef9SDimitry Andric  if (!Depth)
736e8d8bef9SDimitry Andric    Depth = depth;
7375f757f3fSDimitry Andric  if (printMarkupStackTrace(Argv0, StackTrace, Depth, OS))
7385f757f3fSDimitry Andric    return;
739e8d8bef9SDimitry Andric  if (printSymbolizedStackTrace(Argv0, StackTrace, Depth, OS))
7400b57cec5SDimitry Andric    return;
741e8d8bef9SDimitry Andric  OS << "Stack dump without symbol names (ensure you have llvm-symbolizer in "
742e8d8bef9SDimitry Andric        "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point "
743e8d8bef9SDimitry Andric        "to it):\n";
7440b57cec5SDimitry Andric#if HAVE_DLFCN_H && HAVE_DLADDR
7450b57cec5SDimitry Andric  int width = 0;
7460b57cec5SDimitry Andric  for (int i = 0; i < depth; ++i) {
7470b57cec5SDimitry Andric    Dl_info dlinfo;
7480b57cec5SDimitry Andric    dladdr(StackTrace[i], &dlinfo);
7490b57cec5SDimitry Andric    const char *name = strrchr(dlinfo.dli_fname, '/');
7500b57cec5SDimitry Andric
7510b57cec5SDimitry Andric    int nwidth;
752bdd1243dSDimitry Andric    if (!name)
753bdd1243dSDimitry Andric      nwidth = strlen(dlinfo.dli_fname);
754bdd1243dSDimitry Andric    else
755bdd1243dSDimitry Andric      nwidth = strlen(name) - 1;
7560b57cec5SDimitry Andric
757bdd1243dSDimitry Andric    if (nwidth > width)
758bdd1243dSDimitry Andric      width = nwidth;
7590b57cec5SDimitry Andric  }
7600b57cec5SDimitry Andric
7610b57cec5SDimitry Andric  for (int i = 0; i < depth; ++i) {
7620b57cec5SDimitry Andric    Dl_info dlinfo;
7630b57cec5SDimitry Andric    dladdr(StackTrace[i], &dlinfo);
7640b57cec5SDimitry Andric
7650b57cec5SDimitry Andric    OS << format("%-2d", i);
7660b57cec5SDimitry Andric
7670b57cec5SDimitry Andric    const char *name = strrchr(dlinfo.dli_fname, '/');
768bdd1243dSDimitry Andric    if (!name)
769bdd1243dSDimitry Andric      OS << format(" %-*s", width, dlinfo.dli_fname);
770bdd1243dSDimitry Andric    else
771bdd1243dSDimitry Andric      OS << format(" %-*s", width, name + 1);
7720b57cec5SDimitry Andric
7730b57cec5SDimitry Andric    OS << format(" %#0*lx", (int)(sizeof(void *) * 2) + 2,
7740b57cec5SDimitry Andric                 (unsigned long)StackTrace[i]);
7750b57cec5SDimitry Andric
7760b57cec5SDimitry Andric    if (dlinfo.dli_sname != nullptr) {
7770b57cec5SDimitry Andric      OS << ' ';
77806c3fb27SDimitry Andric      if (char *d = itaniumDemangle(dlinfo.dli_sname)) {
779bdd1243dSDimitry Andric        OS << d;
7800b57cec5SDimitry Andric        free(d);
78106c3fb27SDimitry Andric      } else {
78206c3fb27SDimitry Andric        OS << dlinfo.dli_sname;
78306c3fb27SDimitry Andric      }
7840b57cec5SDimitry Andric
7850b57cec5SDimitry Andric      OS << format(" + %tu", (static_cast<const char *>(StackTrace[i]) -
7860b57cec5SDimitry Andric                              static_cast<const char *>(dlinfo.dli_saddr)));
7870b57cec5SDimitry Andric    }
7880b57cec5SDimitry Andric    OS << '\n';
7890b57cec5SDimitry Andric  }
7900b57cec5SDimitry Andric#elif defined(HAVE_BACKTRACE)
791e8d8bef9SDimitry Andric  backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO);
7920b57cec5SDimitry Andric#endif
7930b57cec5SDimitry Andric#endif
7940b57cec5SDimitry Andric}
7950b57cec5SDimitry Andric
7960b57cec5SDimitry Andricstatic void PrintStackTraceSignalHandler(void *) {
7970b57cec5SDimitry Andric  sys::PrintStackTrace(llvm::errs());
7980b57cec5SDimitry Andric}
7990b57cec5SDimitry Andric
8000b57cec5SDimitry Andricvoid llvm::sys::DisableSystemDialogsOnCrash() {}
8010b57cec5SDimitry Andric
8020b57cec5SDimitry Andric/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
8030b57cec5SDimitry Andric/// process, print a stack trace and then exit.
8040b57cec5SDimitry Andricvoid llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
8050b57cec5SDimitry Andric                                             bool DisableCrashReporting) {
8060b57cec5SDimitry Andric  ::Argv0 = Argv0;
8070b57cec5SDimitry Andric
8080b57cec5SDimitry Andric  AddSignalHandler(PrintStackTraceSignalHandler, nullptr);
8090b57cec5SDimitry Andric
8100b57cec5SDimitry Andric#if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES
8110b57cec5SDimitry Andric  // Environment variable to disable any kind of crash dialog.
8120b57cec5SDimitry Andric  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) {
8130b57cec5SDimitry Andric    mach_port_t self = mach_task_self();
8140b57cec5SDimitry Andric
8150b57cec5SDimitry Andric    exception_mask_t mask = EXC_MASK_CRASH;
8160b57cec5SDimitry Andric
817bdd1243dSDimitry Andric    kern_return_t ret = task_set_exception_ports(
818bdd1243dSDimitry Andric        self, mask, MACH_PORT_NULL,
819bdd1243dSDimitry Andric        EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
8200b57cec5SDimitry Andric    (void)ret;
8210b57cec5SDimitry Andric  }
8220b57cec5SDimitry Andric#endif
8230b57cec5SDimitry Andric}
824