diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Support/Signals.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Support/Signals.cpp | 224 | 
1 files changed, 224 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Support/Signals.cpp b/contrib/llvm-project/llvm/lib/Support/Signals.cpp new file mode 100644 index 000000000000..add6fde0eb5e --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Support/Signals.cpp @@ -0,0 +1,224 @@ +//===- Signals.cpp - Signal Handling support --------------------*- 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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Signals.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//===          independent code. +//===----------------------------------------------------------------------===// + +using namespace llvm; + +// Use explicit storage to avoid accessing cl::opt in a signal handler. +static bool DisableSymbolicationFlag = false; +static cl::opt<bool, true> +    DisableSymbolication("disable-symbolication", +                         cl::desc("Disable symbolizing crash backtraces."), +                         cl::location(DisableSymbolicationFlag), cl::Hidden); + +// Callbacks to run in signal handler must be lock-free because a signal handler +// could be running as we add new callbacks. We don't add unbounded numbers of +// callbacks, an array is therefore sufficient. +struct CallbackAndCookie { +  sys::SignalHandlerCallback Callback; +  void *Cookie; +  enum class Status { Empty, Initializing, Initialized, Executing }; +  std::atomic<Status> Flag; +}; +static constexpr size_t MaxSignalHandlerCallbacks = 8; +static CallbackAndCookie CallBacksToRun[MaxSignalHandlerCallbacks]; + +// Signal-safe. +void sys::RunSignalHandlers() { +  for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) { +    auto &RunMe = CallBacksToRun[I]; +    auto Expected = CallbackAndCookie::Status::Initialized; +    auto Desired = CallbackAndCookie::Status::Executing; +    if (!RunMe.Flag.compare_exchange_strong(Expected, Desired)) +      continue; +    (*RunMe.Callback)(RunMe.Cookie); +    RunMe.Callback = nullptr; +    RunMe.Cookie = nullptr; +    RunMe.Flag.store(CallbackAndCookie::Status::Empty); +  } +} + +// Signal-safe. +static void insertSignalHandler(sys::SignalHandlerCallback FnPtr, +                                void *Cookie) { +  for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) { +    auto &SetMe = CallBacksToRun[I]; +    auto Expected = CallbackAndCookie::Status::Empty; +    auto Desired = CallbackAndCookie::Status::Initializing; +    if (!SetMe.Flag.compare_exchange_strong(Expected, Desired)) +      continue; +    SetMe.Callback = FnPtr; +    SetMe.Cookie = Cookie; +    SetMe.Flag.store(CallbackAndCookie::Status::Initialized); +    return; +  } +  report_fatal_error("too many signal callbacks already registered"); +} + +static bool findModulesAndOffsets(void **StackTrace, int Depth, +                                  const char **Modules, intptr_t *Offsets, +                                  const char *MainExecutableName, +                                  StringSaver &StrPool); + +/// Format a pointer value as hexadecimal. Zero pad it out so its always the +/// same width. +static FormattedNumber format_ptr(void *PC) { +  // Each byte is two hex digits plus 2 for the 0x prefix. +  unsigned PtrWidth = 2 + 2 * sizeof(void *); +  return format_hex((uint64_t)PC, PtrWidth); +} + +/// Helper that launches llvm-symbolizer and symbolizes a backtrace. +LLVM_ATTRIBUTE_USED +static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace, +                                      int Depth, llvm::raw_ostream &OS) { +  if (DisableSymbolicationFlag) +    return false; + +  // Don't recursively invoke the llvm-symbolizer binary. +  if (Argv0.find("llvm-symbolizer") != std::string::npos) +    return false; + +  // FIXME: Subtract necessary number from StackTrace entries to turn return addresses +  // into actual instruction addresses. +  // Use llvm-symbolizer tool to symbolize the stack traces. First look for it +  // alongside our binary, then in $PATH. +  ErrorOr<std::string> LLVMSymbolizerPathOrErr = std::error_code(); +  if (!Argv0.empty()) { +    StringRef Parent = llvm::sys::path::parent_path(Argv0); +    if (!Parent.empty()) +      LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer", Parent); +  } +  if (!LLVMSymbolizerPathOrErr) +    LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer"); +  if (!LLVMSymbolizerPathOrErr) +    return false; +  const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr; + +  // If we don't know argv0 or the address of main() at this point, try +  // to guess it anyway (it's possible on some platforms). +  std::string MainExecutableName = +      sys::fs::exists(Argv0) ? (std::string)Argv0 +                             : sys::fs::getMainExecutable(nullptr, nullptr); +  BumpPtrAllocator Allocator; +  StringSaver StrPool(Allocator); +  std::vector<const char *> Modules(Depth, nullptr); +  std::vector<intptr_t> Offsets(Depth, 0); +  if (!findModulesAndOffsets(StackTrace, Depth, Modules.data(), Offsets.data(), +                             MainExecutableName.c_str(), StrPool)) +    return false; +  int InputFD; +  SmallString<32> InputFile, OutputFile; +  sys::fs::createTemporaryFile("symbolizer-input", "", InputFD, InputFile); +  sys::fs::createTemporaryFile("symbolizer-output", "", OutputFile); +  FileRemover InputRemover(InputFile.c_str()); +  FileRemover OutputRemover(OutputFile.c_str()); + +  { +    raw_fd_ostream Input(InputFD, true); +    for (int i = 0; i < Depth; i++) { +      if (Modules[i]) +        Input << Modules[i] << " " << (void*)Offsets[i] << "\n"; +    } +  } + +  Optional<StringRef> Redirects[] = {StringRef(InputFile), +                                     StringRef(OutputFile), StringRef("")}; +  StringRef Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining", +#ifdef _WIN32 +                      // Pass --relative-address on Windows so that we don't +                      // have to add ImageBase from PE file. +                      // FIXME: Make this the default for llvm-symbolizer. +                      "--relative-address", +#endif +                      "--demangle"}; +  int RunResult = +      sys::ExecuteAndWait(LLVMSymbolizerPath, Args, None, Redirects); +  if (RunResult != 0) +    return false; + +  // This report format is based on the sanitizer stack trace printer.  See +  // sanitizer_stacktrace_printer.cc in compiler-rt. +  auto OutputBuf = MemoryBuffer::getFile(OutputFile.c_str()); +  if (!OutputBuf) +    return false; +  StringRef Output = OutputBuf.get()->getBuffer(); +  SmallVector<StringRef, 32> Lines; +  Output.split(Lines, "\n"); +  auto CurLine = Lines.begin(); +  int frame_no = 0; +  for (int i = 0; i < Depth; i++) { +    auto PrintLineHeader = [&]() { +      OS << right_justify(formatv("#{0}", frame_no++).str(), +                          std::log10(Depth) + 2) +         << ' ' << format_ptr(StackTrace[i]) << ' '; +    }; +    if (!Modules[i]) { +      PrintLineHeader(); +      OS << '\n'; +      continue; +    } +    // Read pairs of lines (function name and file/line info) until we +    // encounter empty line. +    for (;;) { +      if (CurLine == Lines.end()) +        return false; +      StringRef FunctionName = *CurLine++; +      if (FunctionName.empty()) +        break; +      PrintLineHeader(); +      if (!FunctionName.startswith("??")) +        OS << FunctionName << ' '; +      if (CurLine == Lines.end()) +        return false; +      StringRef FileLineInfo = *CurLine++; +      if (!FileLineInfo.startswith("??")) +        OS << FileLineInfo; +      else +        OS << "(" << Modules[i] << '+' << format_hex(Offsets[i], 0) << ")"; +      OS << "\n"; +    } +  } +  return true; +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Signals.inc" +#endif +#ifdef _WIN32 +#include "Windows/Signals.inc" +#endif  | 
