brintos

brintos / llvm-project-archived public Read only

0
0
Text · 32.2 KiB · 78d6540 Raw
942 lines · plain
1//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines some helpful functions for dealing with the possibility of10// Unix signals occurring while your program is running.11//12//===----------------------------------------------------------------------===//13//14// This file is extremely careful to only do signal-safe things while in a15// signal handler. In particular, memory allocation and acquiring a mutex16// while in a signal handler should never occur. ManagedStatic isn't usable from17// a signal handler for 2 reasons:18//19//  1. Creating a new one allocates.20//  2. The signal handler could fire while llvm_shutdown is being processed, in21//     which case the ManagedStatic is in an unknown state because it could22//     already have been destroyed, or be in the process of being destroyed.23//24// Modifying the behavior of the signal handlers (such as registering new ones)25// can acquire a mutex, but all this guarantees is that the signal handler26// behavior is only modified by one thread at a time. A signal handler can still27// fire while this occurs!28//29// Adding work to a signal handler requires lock-freedom (and assume atomics are30// always lock-free) because the signal handler could fire while new work is31// being added.32//33//===----------------------------------------------------------------------===//34 35#include "Unix.h"36#include "llvm/ADT/STLExtras.h"37#include "llvm/Config/config.h"38#include "llvm/Demangle/Demangle.h"39#include "llvm/Support/ExitCodes.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/SaveAndRestore.h"47#include "llvm/Support/raw_ostream.h"48#include <algorithm>49#include <string>50#ifdef HAVE_BACKTRACE51#include BACKTRACE_HEADER // For backtrace().52#endif53#include <signal.h>54#include <sys/stat.h>55#include <dlfcn.h>56#if HAVE_MACH_MACH_H57#include <mach/mach.h>58#endif59#ifdef __APPLE__60#include <mach-o/dyld.h>61#endif62#if __has_include(<link.h>)63#include <link.h>64#endif65#ifdef HAVE__UNWIND_BACKTRACE66// FIXME: We should be able to use <unwind.h> for any target that has an67// _Unwind_Backtrace function, but on FreeBSD the configure test passes68// despite the function not existing, and on Android, <unwind.h> conflicts69// with <link.h>.70#ifdef __GLIBC__71#include <unwind.h>72#else73#undef HAVE__UNWIND_BACKTRACE74#endif75#endif76#if ENABLE_BACKTRACES && defined(__MVS__)77#include "llvm/Support/ConvertEBCDIC.h"78#include <__le_cwi.h>79#endif80 81#if defined(__linux__)82#include <sys/syscall.h>83#endif84 85using namespace llvm;86 87static void SignalHandler(int Sig, siginfo_t *Info, void *);88static void InfoSignalHandler(int Sig); // defined below.89 90using SignalHandlerFunctionType = void (*)();91/// The function to call if ctrl-c is pressed.92static std::atomic<SignalHandlerFunctionType> InterruptFunction = nullptr;93static std::atomic<SignalHandlerFunctionType> InfoSignalFunction = nullptr;94/// The function to call on SIGPIPE (one-time use only).95static std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction =96    nullptr;97 98namespace {99/// Signal-safe removal of files.100/// Inserting and erasing from the list isn't signal-safe, but removal of files101/// themselves is signal-safe. Memory is freed when the head is freed, deletion102/// is therefore not signal-safe either.103class FileToRemoveList {104  std::atomic<char *> Filename = nullptr;105  std::atomic<FileToRemoveList *> Next = nullptr;106 107  FileToRemoveList() = default;108  // Not signal-safe.109  FileToRemoveList(const std::string &str) : Filename(strdup(str.c_str())) {}110 111public:112  // Not signal-safe.113  ~FileToRemoveList() {114    if (FileToRemoveList *N = Next.exchange(nullptr))115      delete N;116    if (char *F = Filename.exchange(nullptr))117      free(F);118  }119 120  // Not signal-safe.121  static void insert(std::atomic<FileToRemoveList *> &Head,122                     const std::string &Filename) {123    // Insert the new file at the end of the list.124    FileToRemoveList *NewHead = new FileToRemoveList(Filename);125    std::atomic<FileToRemoveList *> *InsertionPoint = &Head;126    FileToRemoveList *OldHead = nullptr;127    while (!InsertionPoint->compare_exchange_strong(OldHead, NewHead)) {128      InsertionPoint = &OldHead->Next;129      OldHead = nullptr;130    }131  }132 133  // Not signal-safe.134  static void erase(std::atomic<FileToRemoveList *> &Head,135                    const std::string &Filename) {136    // Use a lock to avoid concurrent erase: the comparison would access137    // free'd memory.138    static ManagedStatic<sys::SmartMutex<true>> Lock;139    sys::SmartScopedLock<true> Writer(*Lock);140 141    for (FileToRemoveList *Current = Head.load(); Current;142         Current = Current->Next.load()) {143      if (char *OldFilename = Current->Filename.load()) {144        if (OldFilename != Filename)145          continue;146        // Leave an empty filename.147        OldFilename = Current->Filename.exchange(nullptr);148        // The filename might have become null between the time we149        // compared it and we exchanged it.150        if (OldFilename)151          free(OldFilename);152      }153    }154  }155 156  static void removeFile(char *path) {157    // Get the status so we can determine if it's a file or directory. If we158    // can't stat the file, ignore it.159    struct stat buf;160    if (stat(path, &buf) != 0)161      return;162 163    // If this is not a regular file, ignore it. We want to prevent removal164    // of special files like /dev/null, even if the compiler is being run165    // with the super-user permissions.166    if (!S_ISREG(buf.st_mode))167      return;168 169    // Otherwise, remove the file. We ignore any errors here as there is170    // nothing else we can do.171    unlink(path);172  }173 174  // Signal-safe.175  static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) {176    // If cleanup were to occur while we're removing files we'd have a bad time.177    // Make sure we're OK by preventing cleanup from doing anything while we're178    // removing files. If cleanup races with us and we win we'll have a leak,179    // but we won't crash.180    FileToRemoveList *OldHead = Head.exchange(nullptr);181 182    for (FileToRemoveList *currentFile = OldHead; currentFile;183         currentFile = currentFile->Next.load()) {184      // If erasing was occuring while we're trying to remove files we'd look185      // at free'd data. Take away the path and put it back when done.186      if (char *path = currentFile->Filename.exchange(nullptr)) {187        removeFile(path);188 189        // We're done removing the file, erasing can safely proceed.190        currentFile->Filename.exchange(path);191      }192    }193 194    // We're done removing files, cleanup can safely proceed.195    Head.exchange(OldHead);196  }197};198static std::atomic<FileToRemoveList *> FilesToRemove = nullptr;199 200/// Clean up the list in a signal-friendly manner.201/// Recall that signals can fire during llvm_shutdown. If this occurs we should202/// either clean something up or nothing at all, but we shouldn't crash!203struct FilesToRemoveCleanup {204  // Not signal-safe.205  ~FilesToRemoveCleanup() {206    FileToRemoveList *Head = FilesToRemove.exchange(nullptr);207    if (Head)208      delete Head;209  }210};211} // namespace212 213static StringRef Argv0;214 215/// Signals that represent requested termination. There's no bug or failure, or216/// if there is, it's not our direct responsibility. For whatever reason, our217/// continued execution is no longer desirable.218static const int IntSigs[] = {SIGHUP, SIGINT, SIGTERM, SIGUSR2};219 220/// Signals that represent that we have a bug, and our prompt termination has221/// been ordered.222static const int KillSigs[] = {SIGILL,223                               SIGTRAP,224                               SIGABRT,225                               SIGFPE,226                               SIGBUS,227                               SIGSEGV,228                               SIGQUIT229#ifdef SIGSYS230                               ,231                               SIGSYS232#endif233#ifdef SIGXCPU234                               ,235                               SIGXCPU236#endif237#ifdef SIGXFSZ238                               ,239                               SIGXFSZ240#endif241#ifdef SIGEMT242                               ,243                               SIGEMT244#endif245};246 247/// Signals that represent requests for status.248static const int InfoSigs[] = {SIGUSR1249#ifdef SIGINFO250                               ,251                               SIGINFO252#endif253};254 255static const size_t NumSigs = std::size(IntSigs) + std::size(KillSigs) +256                              std::size(InfoSigs) + 1 /* SIGPIPE */;257 258static std::atomic<unsigned> NumRegisteredSignals = 0;259static struct {260  struct sigaction SA;261  int SigNo;262} RegisteredSignalInfo[NumSigs];263 264#if defined(HAVE_SIGALTSTACK)265// Hold onto both the old and new alternate signal stack so that it's not266// reported as a leak. We don't make any attempt to remove our alt signal267// stack if we remove our signal handlers; that can't be done reliably if268// someone else is also trying to do the same thing.269static stack_t OldAltStack;270LLVM_ATTRIBUTE_USED static void *NewAltStackPointer;271 272static void CreateSigAltStack() {273  const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024;274 275  // If we're executing on the alternate stack, or we already have an alternate276  // signal stack that we're happy with, there's nothing for us to do. Don't277  // reduce the size, some other part of the process might need a larger stack278  // than we do.279  if (sigaltstack(nullptr, &OldAltStack) != 0 ||280      OldAltStack.ss_flags & SS_ONSTACK ||281      (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize))282    return;283 284  stack_t AltStack = {};285  AltStack.ss_sp = static_cast<char *>(safe_malloc(AltStackSize));286  NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak.287  AltStack.ss_size = AltStackSize;288  if (sigaltstack(&AltStack, &OldAltStack) != 0)289    free(AltStack.ss_sp);290}291#else292static void CreateSigAltStack() {}293#endif294 295static void RegisterHandlers() { // Not signal-safe.296  // The mutex prevents other threads from registering handlers while we're297  // doing it. We also have to protect the handlers and their count because298  // a signal handler could fire while we're registering handlers.299  static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex;300  sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex);301 302  // If the handlers are already registered, we're done.303  if (NumRegisteredSignals.load() != 0)304    return;305 306  // Create an alternate stack for signal handling. This is necessary for us to307  // be able to reliably handle signals due to stack overflow.308  CreateSigAltStack();309 310  enum class SignalKind { IsKill, IsInfo };311  auto registerHandler = [&](int Signal, SignalKind Kind) {312    unsigned Index = NumRegisteredSignals.load();313    assert(Index < std::size(RegisteredSignalInfo) &&314           "Out of space for signal handlers!");315 316    struct sigaction NewHandler;317 318    switch (Kind) {319    case SignalKind::IsKill:320      NewHandler.sa_sigaction = SignalHandler;321      NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK | SA_SIGINFO;322      break;323    case SignalKind::IsInfo:324      NewHandler.sa_handler = InfoSignalHandler;325      NewHandler.sa_flags = SA_ONSTACK;326      break;327    }328    sigemptyset(&NewHandler.sa_mask);329 330    // Install the new handler, save the old one in RegisteredSignalInfo.331    sigaction(Signal, &NewHandler, &RegisteredSignalInfo[Index].SA);332    RegisteredSignalInfo[Index].SigNo = Signal;333    ++NumRegisteredSignals;334  };335 336  for (auto S : IntSigs)337    registerHandler(S, SignalKind::IsKill);338  for (auto S : KillSigs)339    registerHandler(S, SignalKind::IsKill);340  if (OneShotPipeSignalFunction)341    registerHandler(SIGPIPE, SignalKind::IsKill);342  for (auto S : InfoSigs)343    registerHandler(S, SignalKind::IsInfo);344}345 346void sys::unregisterHandlers() {347  // Restore all of the signal handlers to how they were before we showed up.348  for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) {349    sigaction(RegisteredSignalInfo[i].SigNo, &RegisteredSignalInfo[i].SA,350              nullptr);351    --NumRegisteredSignals;352  }353}354 355/// Process the FilesToRemove list.356static void RemoveFilesToRemove() {357  FileToRemoveList::removeAllFiles(FilesToRemove);358}359 360void sys::CleanupOnSignal(uintptr_t Context) {361  int Sig = (int)Context;362 363  if (llvm::is_contained(InfoSigs, Sig)) {364    InfoSignalHandler(Sig);365    return;366  }367 368  RemoveFilesToRemove();369 370  if (llvm::is_contained(IntSigs, Sig) || Sig == SIGPIPE)371    return;372 373  llvm::sys::RunSignalHandlers();374}375 376// The signal handler that runs.377static void SignalHandler(int Sig, siginfo_t *Info, void *) {378  // Restore the signal behavior to default, so that the program actually379  // crashes when we return and the signal reissues.  This also ensures that if380  // we crash in our signal handler that the program will terminate immediately381  // instead of recursing in the signal handler.382  sys::unregisterHandlers();383 384  // Unmask all potentially blocked kill signals.385  sigset_t SigMask;386  sigfillset(&SigMask);387  sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);388 389  {390    RemoveFilesToRemove();391 392    if (Sig == SIGPIPE)393      if (auto OldOneShotPipeFunction =394              OneShotPipeSignalFunction.exchange(nullptr))395        return OldOneShotPipeFunction();396 397    bool IsIntSig = llvm::is_contained(IntSigs, Sig);398    if (IsIntSig)399      if (auto OldInterruptFunction = InterruptFunction.exchange(nullptr))400        return OldInterruptFunction();401 402    if (Sig == SIGPIPE || IsIntSig) {403      raise(Sig); // Execute the default handler.404      return;405    }406  }407 408  // Otherwise if it is a fault (like SEGV) run any handler.409  llvm::sys::RunSignalHandlers();410 411#ifdef __s390__412  // On S/390, certain signals are delivered with PSW Address pointing to413  // *after* the faulting instruction.  Simply returning from the signal414  // handler would continue execution after that point, instead of415  // re-raising the signal.  Raise the signal manually in those cases.416  if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP)417    raise(Sig);418#endif419 420#if defined(__linux__)421  // Re-raising a signal via `raise` loses the original siginfo. Recent422  // versions of linux (>= 3.9) support processes sending a signal to itself423  // with arbitrary signal information using a syscall. If this syscall is424  // unsupported, errno will be set to EPERM and `raise` will be used instead.425  int retval =426      syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), Sig, Info);427  if (retval != 0 && errno == EPERM)428    raise(Sig);429#else430  // Signal sent from another userspace process, do not assume that continuing431  // the execution would re-raise it.432  if (Info->si_pid != getpid() && Info->si_pid != 0)433    raise(Sig);434#endif435}436 437static void InfoSignalHandler(int Sig) {438  SaveAndRestore SaveErrnoDuringASignalHandler(errno);439  if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction)440    CurrentInfoFunction();441}442 443void llvm::sys::RunInterruptHandlers() { RemoveFilesToRemove(); }444 445void llvm::sys::SetInterruptFunction(void (*IF)()) {446  InterruptFunction.exchange(IF);447  RegisterHandlers();448}449 450void llvm::sys::SetInfoSignalFunction(void (*Handler)()) {451  InfoSignalFunction.exchange(Handler);452  RegisterHandlers();453}454 455void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) {456  OneShotPipeSignalFunction.exchange(Handler);457  RegisterHandlers();458}459 460void llvm::sys::DefaultOneShotPipeSignalHandler() {461  // Send a special return code that drivers can check for, from sysexits.h.462  exit(EX_IOERR);463}464 465// The public API466bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg) {467  // Ensure that cleanup will occur as soon as one file is added.468  static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup;469  *FilesToRemoveCleanup;470  FileToRemoveList::insert(FilesToRemove, Filename.str());471  RegisterHandlers();472  return false;473}474 475// The public API476void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) {477  FileToRemoveList::erase(FilesToRemove, Filename.str());478}479 480/// Add a function to be called when a signal is delivered to the process. The481/// handler can have a cookie passed to it to identify what instance of the482/// handler it is.483void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr,484                                 void *Cookie) { // Signal-safe.485  insertSignalHandler(FnPtr, Cookie);486  RegisterHandlers();487}488 489#if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) &&                            \490    (defined(__linux__) || defined(__FreeBSD__) ||                             \491     defined(__FreeBSD_kernel__) || defined(__NetBSD__) ||                     \492     defined(__OpenBSD__) || defined(__DragonFly__))493struct DlIteratePhdrData {494  void **StackTrace;495  int depth;496  bool first;497  const char **modules;498  intptr_t *offsets;499  const char *main_exec_name;500};501 502static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {503  DlIteratePhdrData *data = (DlIteratePhdrData *)arg;504  const char *name = data->first ? data->main_exec_name : info->dlpi_name;505  data->first = false;506  for (int i = 0; i < info->dlpi_phnum; i++) {507    const auto *phdr = &info->dlpi_phdr[i];508    if (phdr->p_type != PT_LOAD)509      continue;510    intptr_t beg = info->dlpi_addr + phdr->p_vaddr;511    intptr_t end = beg + phdr->p_memsz;512    for (int j = 0; j < data->depth; j++) {513      if (data->modules[j])514        continue;515      intptr_t addr = (intptr_t)data->StackTrace[j];516      if (beg <= addr && addr < end) {517        data->modules[j] = name;518        data->offsets[j] = addr - info->dlpi_addr;519      }520    }521  }522  return 0;523}524 525#if LLVM_ENABLE_DEBUGLOC_TRACKING_ORIGIN526#if !defined(HAVE_BACKTRACE)527#error DebugLoc origin-tracking currently requires `backtrace()`.528#endif529namespace llvm {530namespace sys {531template <unsigned long MaxDepth>532int getStackTrace(std::array<void *, MaxDepth> &StackTrace) {533  return backtrace(StackTrace.data(), MaxDepth);534}535template int getStackTrace<16ul>(std::array<void *, 16ul> &);536} // namespace sys537} // namespace llvm538#endif539 540/// If this is an ELF platform, we can find all loaded modules and their virtual541/// addresses with dl_iterate_phdr.542static bool findModulesAndOffsets(void **StackTrace, int Depth,543                                  const char **Modules, intptr_t *Offsets,544                                  const char *MainExecutableName,545                                  StringSaver &StrPool) {546  DlIteratePhdrData data = {StackTrace, Depth,   true,547                            Modules,    Offsets, MainExecutableName};548  dl_iterate_phdr(dl_iterate_phdr_cb, &data);549  return true;550}551 552class DSOMarkupPrinter {553  llvm::raw_ostream &OS;554  const char *MainExecutableName;555  size_t ModuleCount = 0;556  bool IsFirst = true;557 558public:559  DSOMarkupPrinter(llvm::raw_ostream &OS, const char *MainExecutableName)560      : OS(OS), MainExecutableName(MainExecutableName) {}561 562  /// Print llvm-symbolizer markup describing the layout of the given DSO.563  void printDSOMarkup(dl_phdr_info *Info) {564    ArrayRef<uint8_t> BuildID = findBuildID(Info);565    if (BuildID.empty())566      return;567    OS << format("{{{module:%d:%s:elf:", ModuleCount,568                 IsFirst ? MainExecutableName : Info->dlpi_name);569    for (uint8_t X : BuildID)570      OS << format("%02x", X);571    OS << "}}}\n";572 573    for (int I = 0; I < Info->dlpi_phnum; I++) {574      const auto *Phdr = &Info->dlpi_phdr[I];575      if (Phdr->p_type != PT_LOAD)576        continue;577      uintptr_t StartAddress = Info->dlpi_addr + Phdr->p_vaddr;578      uintptr_t ModuleRelativeAddress = Phdr->p_vaddr;579      std::array<char, 4> ModeStr = modeStrFromFlags(Phdr->p_flags);580      OS << format("{{{mmap:%#016x:%#x:load:%d:%s:%#016x}}}\n", StartAddress,581                   Phdr->p_memsz, ModuleCount, &ModeStr[0],582                   ModuleRelativeAddress);583    }584    IsFirst = false;585    ModuleCount++;586  }587 588  /// Callback for use with dl_iterate_phdr. The last dl_iterate_phdr argument589  /// must be a pointer to an instance of this class.590  static int printDSOMarkup(dl_phdr_info *Info, size_t Size, void *Arg) {591    static_cast<DSOMarkupPrinter *>(Arg)->printDSOMarkup(Info);592    return 0;593  }594 595  // Returns the build ID for the given DSO as an array of bytes. Returns an596  // empty array if none could be found.597  ArrayRef<uint8_t> findBuildID(dl_phdr_info *Info) {598    for (int I = 0; I < Info->dlpi_phnum; I++) {599      const auto *Phdr = &Info->dlpi_phdr[I];600      if (Phdr->p_type != PT_NOTE)601        continue;602 603      ArrayRef<uint8_t> Notes(604          reinterpret_cast<const uint8_t *>(Info->dlpi_addr + Phdr->p_vaddr),605          Phdr->p_memsz);606      while (Notes.size() > 12) {607        uint32_t NameSize = *reinterpret_cast<const uint32_t *>(Notes.data());608        Notes = Notes.drop_front(4);609        uint32_t DescSize = *reinterpret_cast<const uint32_t *>(Notes.data());610        Notes = Notes.drop_front(4);611        uint32_t Type = *reinterpret_cast<const uint32_t *>(Notes.data());612        Notes = Notes.drop_front(4);613 614        ArrayRef<uint8_t> Name = Notes.take_front(NameSize);615        auto CurPos = reinterpret_cast<uintptr_t>(Notes.data());616        uint32_t BytesUntilDesc =617            alignToPowerOf2(CurPos + NameSize, 4) - CurPos;618        if (BytesUntilDesc >= Notes.size())619          break;620        Notes = Notes.drop_front(BytesUntilDesc);621 622        ArrayRef<uint8_t> Desc = Notes.take_front(DescSize);623        CurPos = reinterpret_cast<uintptr_t>(Notes.data());624        uint32_t BytesUntilNextNote =625            alignToPowerOf2(CurPos + DescSize, 4) - CurPos;626        if (BytesUntilNextNote > Notes.size())627          break;628        Notes = Notes.drop_front(BytesUntilNextNote);629 630        if (Type == 3 /*NT_GNU_BUILD_ID*/ && Name.size() >= 3 &&631            Name[0] == 'G' && Name[1] == 'N' && Name[2] == 'U')632          return Desc;633      }634    }635    return {};636  }637 638  // Returns a symbolizer markup string describing the permissions on a DSO639  // with the given p_flags.640  std::array<char, 4> modeStrFromFlags(uint32_t Flags) {641    std::array<char, 4> Mode;642    char *Cur = &Mode[0];643    if (Flags & PF_R)644      *Cur++ = 'r';645    if (Flags & PF_W)646      *Cur++ = 'w';647    if (Flags & PF_X)648      *Cur++ = 'x';649    *Cur = '\0';650    return Mode;651  }652};653 654static bool printMarkupContext(llvm::raw_ostream &OS,655                               const char *MainExecutableName) {656  OS << "{{{reset}}}\n";657  DSOMarkupPrinter MP(OS, MainExecutableName);658  dl_iterate_phdr(DSOMarkupPrinter::printDSOMarkup, &MP);659  return true;660}661 662#elif ENABLE_BACKTRACES && defined(__APPLE__) && defined(__LP64__)663static bool findModulesAndOffsets(void **StackTrace, int Depth,664                                  const char **Modules, intptr_t *Offsets,665                                  const char *MainExecutableName,666                                  StringSaver &StrPool) {667  uint32_t NumImgs = _dyld_image_count();668  for (uint32_t ImageIndex = 0; ImageIndex < NumImgs; ImageIndex++) {669    const char *Name = _dyld_get_image_name(ImageIndex);670    intptr_t Slide = _dyld_get_image_vmaddr_slide(ImageIndex);671    auto *Header =672        (const struct mach_header_64 *)_dyld_get_image_header(ImageIndex);673    if (Header == NULL)674      continue;675    auto Cmd = (const struct load_command *)(&Header[1]);676    for (uint32_t CmdNum = 0; CmdNum < Header->ncmds; ++CmdNum) {677      uint32_t BaseCmd = Cmd->cmd & ~LC_REQ_DYLD;678      if (BaseCmd == LC_SEGMENT_64) {679        auto CmdSeg64 = (const struct segment_command_64 *)Cmd;680        for (int j = 0; j < Depth; j++) {681          if (Modules[j])682            continue;683          intptr_t Addr = (intptr_t)StackTrace[j];684          if ((intptr_t)CmdSeg64->vmaddr + Slide <= Addr &&685              Addr < intptr_t(CmdSeg64->vmaddr + CmdSeg64->vmsize + Slide)) {686            Modules[j] = Name;687            Offsets[j] = Addr - Slide;688          }689        }690      }691      Cmd = (const load_command *)(((const char *)Cmd) + (Cmd->cmdsize));692    }693  }694  return true;695}696 697static bool printMarkupContext(llvm::raw_ostream &OS,698                               const char *MainExecutableName) {699  return false;700}701#else702/// Backtraces are not enabled or we don't yet know how to find all loaded DSOs703/// on this platform.704static bool findModulesAndOffsets(void **StackTrace, int Depth,705                                  const char **Modules, intptr_t *Offsets,706                                  const char *MainExecutableName,707                                  StringSaver &StrPool) {708  return false;709}710 711static bool printMarkupContext(llvm::raw_ostream &OS,712                               const char *MainExecutableName) {713  return false;714}715#endif // ENABLE_BACKTRACES && ... (findModulesAndOffsets variants)716 717#if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE)718static int unwindBacktrace(void **StackTrace, int MaxEntries) {719  if (MaxEntries < 0)720    return 0;721 722  // Skip the first frame ('unwindBacktrace' itself).723  int Entries = -1;724 725  auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code {726    // Apparently we need to detect reaching the end of the stack ourselves.727    void *IP = (void *)_Unwind_GetIP(Context);728    if (!IP)729      return _URC_END_OF_STACK;730 731    assert(Entries < MaxEntries && "recursively called after END_OF_STACK?");732    if (Entries >= 0)733      StackTrace[Entries] = IP;734 735    if (++Entries == MaxEntries)736      return _URC_END_OF_STACK;737    return _URC_NO_REASON;738  };739 740  _Unwind_Backtrace(741      [](_Unwind_Context *Context, void *Handler) {742        return (*static_cast<decltype(HandleFrame) *>(Handler))(Context);743      },744      static_cast<void *>(&HandleFrame));745  return std::max(Entries, 0);746}747#endif748 749#if ENABLE_BACKTRACES && defined(__MVS__)750static void zosbacktrace(raw_ostream &OS) {751  // A function name in the PPA1 can have length 16k.752  constexpr size_t MAX_ENTRY_NAME = UINT16_MAX;753  // Limit all other strings to 8 byte.754  constexpr size_t MAX_OTHER = 8;755  int32_t dsa_format = -1;                  // Input/Output756  void *caaptr = _gtca();                   // Input757  int32_t member_id;                        // Output758  char compile_unit_name[MAX_OTHER];        // Output759  void *compile_unit_address;               // Output760  void *call_instruction_address = nullptr; // Input/Output761  char entry_name[MAX_ENTRY_NAME];          // Output762  void *entry_address;                      // Output763  void *callers_instruction_address;        // Output764  void *callers_dsaptr;                     // Output765  int32_t callers_dsa_format;               // Output766  char statement_id[MAX_OTHER];             // Output767  void *cibptr;                             // Output768  int32_t main_program;                     // Output769  _FEEDBACK fc;                             // Output770 771  // The DSA pointer is the value of the stack pointer r4.772  // __builtin_frame_address() returns a pointer to the stack frame, so the773  // stack bias has to be considered to get the expected DSA value.774  void *dsaptr = static_cast<char *>(__builtin_frame_address(0)) - 2048;775  int count = 0;776  OS << " DSA  Adr                EP                 +EP         DSA           "777        "     Entry\n";778  while (1) {779    // After the call, these variables contain the length of the string.780    int32_t compile_unit_name_length = sizeof(compile_unit_name);781    int32_t entry_name_length = sizeof(entry_name);782    int32_t statement_id_length = sizeof(statement_id);783    // See784    // https://www.ibm.com/docs/en/zos/3.1.0?topic=cwicsa6a-celqtbck-also-known-as-celqtbck-64-bit-traceback-service785    // for documentation of the parameters.786    __CELQTBCK(&dsaptr, &dsa_format, &caaptr, &member_id, &compile_unit_name[0],787               &compile_unit_name_length, &compile_unit_address,788               &call_instruction_address, &entry_name[0], &entry_name_length,789               &entry_address, &callers_instruction_address, &callers_dsaptr,790               &callers_dsa_format, &statement_id[0], &statement_id_length,791               &cibptr, &main_program, &fc);792    if (fc.tok_sev) {793      OS << format("error: CELQTBCK returned severity %d message %d\n",794                   fc.tok_sev, fc.tok_msgno);795      break;796    }797 798    if (count) { // Omit first entry.799      uintptr_t diff = reinterpret_cast<uintptr_t>(call_instruction_address) -800                       reinterpret_cast<uintptr_t>(entry_address);801      OS << format(" %3d. 0x%016lX", count, call_instruction_address);802      OS << format(" 0x%016lX +0x%08lX 0x%016lX", entry_address, diff, dsaptr);803      SmallString<256> Str;804      ConverterEBCDIC::convertToUTF8(StringRef(entry_name, entry_name_length),805                                     Str);806      OS << ' ' << Str << '\n';807    }808    ++count;809    if (callers_dsaptr) {810      dsaptr = callers_dsaptr;811      dsa_format = callers_dsa_format;812      call_instruction_address = callers_instruction_address;813    } else814      break;815  }816}817#endif818 819// In the case of a program crash or fault, print out a stack trace so that the820// user has an indication of why and where we died.821//822// On glibc systems we have the 'backtrace' function, which works nicely, but823// doesn't demangle symbols.824void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) {825#if ENABLE_BACKTRACES826#ifdef __MVS__827  zosbacktrace(OS);828#else829  static void *StackTrace[256];830  int depth = 0;831#if defined(HAVE_BACKTRACE)832  // Use backtrace() to output a backtrace on Linux systems with glibc.833  if (!depth)834    depth = backtrace(StackTrace, static_cast<int>(std::size(StackTrace)));835#endif836#if defined(HAVE__UNWIND_BACKTRACE)837  // Try _Unwind_Backtrace() if backtrace() failed.838  if (!depth)839    depth =840        unwindBacktrace(StackTrace, static_cast<int>(std::size(StackTrace)));841#endif842  if (!depth)843    return;844  // If "Depth" is not provided by the caller, use the return value of845  // backtrace() for printing a symbolized stack trace.846  if (!Depth)847    Depth = depth;848  if (printMarkupStackTrace(Argv0, StackTrace, Depth, OS))849    return;850  if (printSymbolizedStackTrace(Argv0, StackTrace, Depth, OS))851    return;852  OS << "Stack dump without symbol names (ensure you have llvm-symbolizer in "853        "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point "854        "to it):\n";855#if HAVE_DLOPEN && !defined(_AIX)856  int width = 0;857  for (int i = 0; i < depth; ++i) {858    Dl_info dlinfo;859    int nwidth;860    if (dladdr(StackTrace[i], &dlinfo) == 0) {861      nwidth = 7; // "(error)"862    } else {863      const char *name = strrchr(dlinfo.dli_fname, '/');864 865      if (!name)866        nwidth = strlen(dlinfo.dli_fname);867      else868        nwidth = strlen(name) - 1;869    }870 871    width = std::max(nwidth, width);872  }873 874  for (int i = 0; i < depth; ++i) {875    Dl_info dlinfo;876 877    OS << format("%-2d", i);878 879    if (dladdr(StackTrace[i], &dlinfo) == 0) {880      OS << format(" %-*s", width, static_cast<const char *>("(error)"));881      dlinfo.dli_sname = nullptr;882    } else {883      const char *name = strrchr(dlinfo.dli_fname, '/');884      if (!name)885        OS << format(" %-*s", width, dlinfo.dli_fname);886      else887        OS << format(" %-*s", width, name + 1);888    }889 890    OS << format(" %#0*lx", (int)(sizeof(void *) * 2) + 2,891                 (unsigned long)StackTrace[i]);892 893    if (dlinfo.dli_sname != nullptr) {894      OS << ' ';895      if (char *d = itaniumDemangle(dlinfo.dli_sname)) {896        OS << d;897        free(d);898      } else {899        OS << dlinfo.dli_sname;900      }901 902      OS << format(" + %tu", (static_cast<const char *>(StackTrace[i]) -903                              static_cast<const char *>(dlinfo.dli_saddr)));904    }905    OS << '\n';906  }907#elif defined(HAVE_BACKTRACE)908  backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO);909#endif910#endif911#endif912}913 914static void PrintStackTraceSignalHandler(void *) {915  sys::PrintStackTrace(llvm::errs());916}917 918void llvm::sys::DisableSystemDialogsOnCrash() {}919 920/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the921/// process, print a stack trace and then exit.922void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0,923                                             bool DisableCrashReporting) {924  ::Argv0 = Argv0;925 926  AddSignalHandler(PrintStackTraceSignalHandler, nullptr);927 928#if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES929  // Environment variable to disable any kind of crash dialog.930  if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT")) {931    mach_port_t self = mach_task_self();932 933    exception_mask_t mask = EXC_MASK_CRASH;934 935    kern_return_t ret = task_set_exception_ports(936        self, mask, MACH_PORT_NULL,937        EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);938    (void)ret;939  }940#endif941}942