LCOV - code coverage report
Current view: top level - lib/Support - Signals.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 6 59 10.2 %
Date: 2018-10-20 13:21:21 Functions: 1 3 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file defines some helpful functions for dealing with the possibility of
      11             : // Unix signals occurring while your program is running.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "llvm/Support/Signals.h"
      16             : #include "llvm/ADT/STLExtras.h"
      17             : #include "llvm/ADT/StringRef.h"
      18             : #include "llvm/Config/llvm-config.h"
      19             : #include "llvm/Support/ErrorOr.h"
      20             : #include "llvm/Support/FileSystem.h"
      21             : #include "llvm/Support/FileUtilities.h"
      22             : #include "llvm/Support/Format.h"
      23             : #include "llvm/Support/ManagedStatic.h"
      24             : #include "llvm/Support/MemoryBuffer.h"
      25             : #include "llvm/Support/Mutex.h"
      26             : #include "llvm/Support/Program.h"
      27             : #include "llvm/Support/StringSaver.h"
      28             : #include "llvm/Support/raw_ostream.h"
      29             : #include "llvm/Support/Options.h"
      30             : #include <vector>
      31             : 
      32             : //===----------------------------------------------------------------------===//
      33             : //=== WARNING: Implementation here must contain only TRULY operating system
      34             : //===          independent code.
      35             : //===----------------------------------------------------------------------===//
      36             : 
      37             : using namespace llvm;
      38             : 
      39             : // Use explicit storage to avoid accessing cl::opt in a signal handler.
      40             : static bool DisableSymbolicationFlag = false;
      41             : static cl::opt<bool, true>
      42             :     DisableSymbolication("disable-symbolication",
      43             :                          cl::desc("Disable symbolizing crash backtraces."),
      44             :                          cl::location(DisableSymbolicationFlag), cl::Hidden);
      45             : 
      46             : // Callbacks to run in signal handler must be lock-free because a signal handler
      47             : // could be running as we add new callbacks. We don't add unbounded numbers of
      48             : // callbacks, an array is therefore sufficient.
      49             : struct CallbackAndCookie {
      50             :   sys::SignalHandlerCallback Callback;
      51             :   void *Cookie;
      52             :   enum class Status { Empty, Initializing, Initialized, Executing };
      53             :   std::atomic<Status> Flag;
      54             : };
      55             : static constexpr size_t MaxSignalHandlerCallbacks = 8;
      56             : static CallbackAndCookie CallBacksToRun[MaxSignalHandlerCallbacks];
      57             : 
      58             : // Signal-safe.
      59           0 : void sys::RunSignalHandlers() {
      60           0 :   for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) {
      61             :     auto &RunMe = CallBacksToRun[I];
      62             :     auto Expected = CallbackAndCookie::Status::Initialized;
      63             :     auto Desired = CallbackAndCookie::Status::Executing;
      64           0 :     if (!RunMe.Flag.compare_exchange_strong(Expected, Desired))
      65             :       continue;
      66           0 :     (*RunMe.Callback)(RunMe.Cookie);
      67           0 :     RunMe.Callback = nullptr;
      68           0 :     RunMe.Cookie = nullptr;
      69             :     RunMe.Flag.store(CallbackAndCookie::Status::Empty);
      70             :   }
      71           0 : }
      72             : 
      73             : // Signal-safe.
      74      340694 : static void insertSignalHandler(sys::SignalHandlerCallback FnPtr,
      75             :                                 void *Cookie) {
      76      506999 :   for (size_t I = 0; I < MaxSignalHandlerCallbacks; ++I) {
      77             :     auto &SetMe = CallBacksToRun[I];
      78             :     auto Expected = CallbackAndCookie::Status::Empty;
      79             :     auto Desired = CallbackAndCookie::Status::Initializing;
      80      506999 :     if (!SetMe.Flag.compare_exchange_strong(Expected, Desired))
      81             :       continue;
      82      340694 :     SetMe.Callback = FnPtr;
      83      340694 :     SetMe.Cookie = Cookie;
      84             :     SetMe.Flag.store(CallbackAndCookie::Status::Initialized);
      85      340694 :     return;
      86             :   }
      87           0 :   report_fatal_error("too many signal callbacks already registered");
      88             : }
      89             : 
      90             : static bool findModulesAndOffsets(void **StackTrace, int Depth,
      91             :                                   const char **Modules, intptr_t *Offsets,
      92             :                                   const char *MainExecutableName,
      93             :                                   StringSaver &StrPool);
      94             : 
      95             : /// Format a pointer value as hexadecimal. Zero pad it out so its always the
      96             : /// same width.
      97             : static FormattedNumber format_ptr(void *PC) {
      98             :   // Each byte is two hex digits plus 2 for the 0x prefix.
      99             :   unsigned PtrWidth = 2 + 2 * sizeof(void *);
     100           0 :   return format_hex((uint64_t)PC, PtrWidth);
     101             : }
     102             : 
     103             : /// Helper that launches llvm-symbolizer and symbolizes a backtrace.
     104             : LLVM_ATTRIBUTE_USED
     105           0 : static bool printSymbolizedStackTrace(StringRef Argv0, void **StackTrace,
     106             :                                       int Depth, llvm::raw_ostream &OS) {
     107           0 :   if (DisableSymbolicationFlag)
     108             :     return false;
     109             : 
     110             :   // Don't recursively invoke the llvm-symbolizer binary.
     111           0 :   if (Argv0.find("llvm-symbolizer") != std::string::npos)
     112             :     return false;
     113             : 
     114             :   // FIXME: Subtract necessary number from StackTrace entries to turn return addresses
     115             :   // into actual instruction addresses.
     116             :   // Use llvm-symbolizer tool to symbolize the stack traces. First look for it
     117             :   // alongside our binary, then in $PATH.
     118             :   ErrorOr<std::string> LLVMSymbolizerPathOrErr = std::error_code();
     119           0 :   if (!Argv0.empty()) {
     120           0 :     StringRef Parent = llvm::sys::path::parent_path(Argv0);
     121           0 :     if (!Parent.empty())
     122           0 :       LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer", Parent);
     123             :   }
     124           0 :   if (!LLVMSymbolizerPathOrErr)
     125           0 :     LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer");
     126           0 :   if (!LLVMSymbolizerPathOrErr)
     127             :     return false;
     128             :   const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr;
     129             : 
     130             :   // If we don't know argv0 or the address of main() at this point, try
     131             :   // to guess it anyway (it's possible on some platforms).
     132             :   std::string MainExecutableName =
     133             :       Argv0.empty() ? sys::fs::getMainExecutable(nullptr, nullptr)
     134           0 :                     : (std::string)Argv0;
     135           0 :   BumpPtrAllocator Allocator;
     136             :   StringSaver StrPool(Allocator);
     137           0 :   std::vector<const char *> Modules(Depth, nullptr);
     138           0 :   std::vector<intptr_t> Offsets(Depth, 0);
     139           0 :   if (!findModulesAndOffsets(StackTrace, Depth, Modules.data(), Offsets.data(),
     140             :                              MainExecutableName.c_str(), StrPool))
     141             :     return false;
     142             :   int InputFD;
     143             :   SmallString<32> InputFile, OutputFile;
     144           0 :   sys::fs::createTemporaryFile("symbolizer-input", "", InputFD, InputFile);
     145           0 :   sys::fs::createTemporaryFile("symbolizer-output", "", OutputFile);
     146           0 :   FileRemover InputRemover(InputFile.c_str());
     147           0 :   FileRemover OutputRemover(OutputFile.c_str());
     148             : 
     149             :   {
     150           0 :     raw_fd_ostream Input(InputFD, true);
     151           0 :     for (int i = 0; i < Depth; i++) {
     152           0 :       if (Modules[i])
     153           0 :         Input << Modules[i] << " " << (void*)Offsets[i] << "\n";
     154             :     }
     155             :   }
     156             : 
     157             :   Optional<StringRef> Redirects[] = {StringRef(InputFile),
     158             :                                      StringRef(OutputFile), llvm::None};
     159             :   StringRef Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining",
     160             : #ifdef _WIN32
     161             :                       // Pass --relative-address on Windows so that we don't
     162             :                       // have to add ImageBase from PE file.
     163             :                       // FIXME: Make this the default for llvm-symbolizer.
     164             :                       "--relative-address",
     165             : #endif
     166             :                       "--demangle"};
     167             :   int RunResult =
     168           0 :       sys::ExecuteAndWait(LLVMSymbolizerPath, Args, None, Redirects);
     169           0 :   if (RunResult != 0)
     170             :     return false;
     171             : 
     172             :   // This report format is based on the sanitizer stack trace printer.  See
     173             :   // sanitizer_stacktrace_printer.cc in compiler-rt.
     174           0 :   auto OutputBuf = MemoryBuffer::getFile(OutputFile.c_str());
     175           0 :   if (!OutputBuf)
     176             :     return false;
     177           0 :   StringRef Output = OutputBuf.get()->getBuffer();
     178             :   SmallVector<StringRef, 32> Lines;
     179           0 :   Output.split(Lines, "\n");
     180             :   auto CurLine = Lines.begin();
     181             :   int frame_no = 0;
     182           0 :   for (int i = 0; i < Depth; i++) {
     183           0 :     if (!Modules[i]) {
     184           0 :       OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << '\n';
     185           0 :       continue;
     186             :     }
     187             :     // Read pairs of lines (function name and file/line info) until we
     188             :     // encounter empty line.
     189             :     for (;;) {
     190           0 :       if (CurLine == Lines.end())
     191             :         return false;
     192           0 :       StringRef FunctionName = *CurLine++;
     193           0 :       if (FunctionName.empty())
     194             :         break;
     195           0 :       OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << ' ';
     196             :       if (!FunctionName.startswith("??"))
     197           0 :         OS << FunctionName << ' ';
     198           0 :       if (CurLine == Lines.end())
     199             :         return false;
     200           0 :       StringRef FileLineInfo = *CurLine++;
     201             :       if (!FileLineInfo.startswith("??"))
     202           0 :         OS << FileLineInfo;
     203             :       else
     204           0 :         OS << "(" << Modules[i] << '+' << format_hex(Offsets[i], 0) << ")";
     205           0 :       OS << "\n";
     206           0 :     }
     207             :   }
     208             :   return true;
     209             : }
     210             : 
     211             : // Include the platform-specific parts of this class.
     212             : #ifdef LLVM_ON_UNIX
     213             : #include "Unix/Signals.inc"
     214             : #endif
     215             : #ifdef _WIN32
     216             : #include "Windows/Signals.inc"
     217             : #endif

Generated by: LCOV version 1.13