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