llvm/llvm/lib/Support/Unix/Signals.inc

//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines some helpful functions for dealing with the possibility of
// Unix signals occurring while your program is running.
//
//===----------------------------------------------------------------------===//
//
// This file is extremely careful to only do signal-safe things while in a
// signal handler. In particular, memory allocation and acquiring a mutex
// while in a signal handler should never occur. ManagedStatic isn't usable from
// a signal handler for 2 reasons:
//
//  1. Creating a new one allocates.
//  2. The signal handler could fire while llvm_shutdown is being processed, in
//     which case the ManagedStatic is in an unknown state because it could
//     already have been destroyed, or be in the process of being destroyed.
//
// Modifying the behavior of the signal handlers (such as registering new ones)
// can acquire a mutex, but all this guarantees is that the signal handler
// behavior is only modified by one thread at a time. A signal handler can still
// fire while this occurs!
//
// Adding work to a signal handler requires lock-freedom (and assume atomics are
// always lock-free) because the signal handler could fire while new work is
// being added.
//
//===----------------------------------------------------------------------===//

#include "Unix.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/ExitCodes.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <string>
#ifdef HAVE_BACKTRACE
#include BACKTRACE_HEADER // For backtrace().
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#if HAVE_MACH_MACH_H
#include <mach/mach.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#if __has_include(<link.h>)
#include <link.h>
#endif
#ifdef HAVE__UNWIND_BACKTRACE
// FIXME: We should be able to use <unwind.h> for any target that has an
// _Unwind_Backtrace function, but on FreeBSD the configure test passes
// despite the function not existing, and on Android, <unwind.h> conflicts
// with <link.h>.
#ifdef __GLIBC__
#include <unwind.h>
#else
#undef HAVE__UNWIND_BACKTRACE
#endif
#endif

usingnamespacellvm;

static void SignalHandler(int Sig);     // defined below.
static void InfoSignalHandler(int Sig); // defined below.

SignalHandlerFunctionType;
/// The function to call if ctrl-c is pressed.
static std::atomic<SignalHandlerFunctionType> InterruptFunction =;
static std::atomic<SignalHandlerFunctionType> InfoSignalFunction =;
/// The function to call on SIGPIPE (one-time use only).
static std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction =;

namespace {
/// Signal-safe removal of files.
/// Inserting and erasing from the list isn't signal-safe, but removal of files
/// themselves is signal-safe. Memory is freed when the head is freed, deletion
/// is therefore not signal-safe either.
class FileToRemoveList {};
static std::atomic<FileToRemoveList *> FilesToRemove =;

/// Clean up the list in a signal-friendly manner.
/// Recall that signals can fire during llvm_shutdown. If this occurs we should
/// either clean something up or nothing at all, but we shouldn't crash!
struct FilesToRemoveCleanup {};
} // namespace

static StringRef Argv0;

/// Signals that represent requested termination. There's no bug or failure, or
/// if there is, it's not our direct responsibility. For whatever reason, our
/// continued execution is no longer desirable.
static const int IntSigs[] =;

/// Signals that represent that we have a bug, and our prompt termination has
/// been ordered.
static const int KillSigs[] =;

/// Signals that represent requests for status.
static const int InfoSigs[] =;

static const size_t NumSigs = /* SIGPIPE */;

static std::atomic<unsigned> NumRegisteredSignals =;
static struct {} RegisteredSignalInfo[NumSigs];

#if defined(HAVE_SIGALTSTACK)
// Hold onto both the old and new alternate signal stack so that it's not
// reported as a leak. We don't make any attempt to remove our alt signal
// stack if we remove our signal handlers; that can't be done reliably if
// someone else is also trying to do the same thing.
static stack_t OldAltStack;
LLVM_ATTRIBUTE_USED static void *NewAltStackPointer;

static void CreateSigAltStack() {}
#else
static void CreateSigAltStack() {}
#endif

static void RegisterHandlers() {}

void sys::unregisterHandlers() {}

/// Process the FilesToRemove list.
static void RemoveFilesToRemove() {}

void sys::CleanupOnSignal(uintptr_t Context) {}

// The signal handler that runs.
static void SignalHandler(int Sig) {}

static void InfoSignalHandler(int Sig) {}

void llvm::sys::RunInterruptHandlers() {}

void llvm::sys::SetInterruptFunction(void (*IF)()) {}

void llvm::sys::SetInfoSignalFunction(void (*Handler)()) {}

void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) {}

void llvm::sys::DefaultOneShotPipeSignalHandler() {}

// The public API
bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg) {}

// The public API
void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {}

/// Add a function to be called when a signal is delivered to the process. The
/// handler can have a cookie passed to it to identify what instance of the
/// handler it is.
void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,
                                 void *Cookie) {}

#if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) &&                            \
    (defined(__linux__) || defined(__FreeBSD__) ||                             \
     defined(__FreeBSD_kernel__) || defined(__NetBSD__))
struct DlIteratePhdrData {};

static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {}

/// If this is an ELF platform, we can find all loaded modules and their virtual
/// addresses with dl_iterate_phdr.
static bool findModulesAndOffsets(void **StackTrace, int Depth,
                                  const char **Modules, intptr_t *Offsets,
                                  const char *MainExecutableName,
                                  StringSaver &StrPool) {}

class DSOMarkupPrinter {};

static bool printMarkupContext(llvm::raw_ostream &OS,
                               const char *MainExecutableName) {}

#elif ENABLE_BACKTRACES && defined(__APPLE__) && defined(__LP64__)
static bool findModulesAndOffsets(void **StackTrace, int Depth,
                                  const char **Modules, intptr_t *Offsets,
                                  const char *MainExecutableName,
                                  StringSaver &StrPool) {
  uint32_t NumImgs = _dyld_image_count();
  for (uint32_t ImageIndex = 0; ImageIndex < NumImgs; ImageIndex++) {
    const char *Name = _dyld_get_image_name(ImageIndex);
    intptr_t Slide = _dyld_get_image_vmaddr_slide(ImageIndex);
    auto *Header =
        (const struct mach_header_64 *)_dyld_get_image_header(ImageIndex);
    if (Header == NULL)
      continue;
    auto Cmd = (const struct load_command *)(&Header[1]);
    for (uint32_t CmdNum = 0; CmdNum < Header->ncmds; ++CmdNum) {
      uint32_t BaseCmd = Cmd->cmd & ~LC_REQ_DYLD;
      if (BaseCmd == LC_SEGMENT_64) {
        auto CmdSeg64 = (const struct segment_command_64 *)Cmd;
        for (int j = 0; j < Depth; j++) {
          if (Modules[j])
            continue;
          intptr_t Addr = (intptr_t)StackTrace[j];
          if ((intptr_t)CmdSeg64->vmaddr + Slide <= Addr &&
              Addr < intptr_t(CmdSeg64->vmaddr + CmdSeg64->vmsize + Slide)) {
            Modules[j] = Name;
            Offsets[j] = Addr - Slide;
          }
        }
      }
      Cmd = (const load_command *)(((const char *)Cmd) + (Cmd->cmdsize));
    }
  }
  return true;
}

static bool printMarkupContext(llvm::raw_ostream &OS,
                               const char *MainExecutableName) {
  return false;
}
#else
/// Backtraces are not enabled or we don't yet know how to find all loaded DSOs
/// on this platform.
static bool findModulesAndOffsets(void **StackTrace, int Depth,
                                  const char **Modules, intptr_t *Offsets,
                                  const char *MainExecutableName,
                                  StringSaver &StrPool) {
  return false;
}

static bool printMarkupContext(llvm::raw_ostream &OS,
                               const char *MainExecutableName) {
  return false;
}
#endif // ENABLE_BACKTRACES && ... (findModulesAndOffsets variants)

#if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)
static int unwindBacktrace(void **StackTrace, int MaxEntries) {}
#endif

// In the case of a program crash or fault, print out a stack trace so that the
// user has an indication of why and where we died.
//
// On glibc systems we have the 'backtrace' function, which works nicely, but
// doesn't demangle symbols.
void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {}

static void PrintStackTraceSignalHandler(void *) {}

void llvm::sys::DisableSystemDialogsOnCrash() {}

/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
/// process, print a stack trace and then exit.
void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0,
                                             bool DisableCrashReporting) {}