Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 1 | //===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===// |
Misha Brukman | 10468d8 | 2005-04-21 22:55:34 +0000 | [diff] [blame] | 2 | // |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
Chris Lattner | f3ebc3f | 2007-12-29 20:36:04 +0000 | [diff] [blame] | 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
Misha Brukman | 10468d8 | 2005-04-21 22:55:34 +0000 | [diff] [blame] | 7 | // |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file defines some helpful functions for dealing with the possibility of |
Chris Lattner | 0ab5e2c | 2011-04-15 05:18:47 +0000 | [diff] [blame] | 11 | // Unix signals occurring while your program is running. |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
Reid Kleckner | ba5757d | 2015-11-05 01:07:54 +0000 | [diff] [blame] | 15 | #include "llvm/ADT/STLExtras.h" |
| 16 | #include "llvm/ADT/StringRef.h" |
Reid Spencer | 844f3fe | 2004-12-27 06:16:11 +0000 | [diff] [blame] | 17 | #include "llvm/Config/config.h" |
Reid Kleckner | ba5757d | 2015-11-05 01:07:54 +0000 | [diff] [blame] | 18 | #include "llvm/Support/ErrorOr.h" |
| 19 | #include "llvm/Support/FileSystem.h" |
| 20 | #include "llvm/Support/FileUtilities.h" |
| 21 | #include "llvm/Support/Format.h" |
Yaron Keren | 240bd9c | 2015-07-22 19:01:14 +0000 | [diff] [blame] | 22 | #include "llvm/Support/ManagedStatic.h" |
Reid Kleckner | ba5757d | 2015-11-05 01:07:54 +0000 | [diff] [blame] | 23 | #include "llvm/Support/MemoryBuffer.h" |
| 24 | #include "llvm/Support/Mutex.h" |
| 25 | #include "llvm/Support/Program.h" |
Yaron Keren | 240bd9c | 2015-07-22 19:01:14 +0000 | [diff] [blame] | 26 | #include "llvm/Support/Signals.h" |
Reid Kleckner | ba5757d | 2015-11-05 01:07:54 +0000 | [diff] [blame] | 27 | #include "llvm/Support/StringSaver.h" |
| 28 | #include "llvm/Support/raw_ostream.h" |
Yaron Keren | 240bd9c | 2015-07-22 19:01:14 +0000 | [diff] [blame] | 29 | #include <vector> |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 30 | |
| 31 | namespace llvm { |
| 32 | using namespace sys; |
| 33 | |
| 34 | //===----------------------------------------------------------------------===// |
| 35 | //=== WARNING: Implementation here must contain only TRULY operating system |
Misha Brukman | 10468d8 | 2005-04-21 22:55:34 +0000 | [diff] [blame] | 36 | //=== independent code. |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 37 | //===----------------------------------------------------------------------===// |
| 38 | |
Yaron Keren | 240bd9c | 2015-07-22 19:01:14 +0000 | [diff] [blame] | 39 | static ManagedStatic<std::vector<std::pair<void (*)(void *), void *>>> |
| 40 | CallBacksToRun; |
Yaron Keren | 2873810 | 2015-07-22 21:11:17 +0000 | [diff] [blame] | 41 | void sys::RunSignalHandlers() { |
Yaron Keren | 240bd9c | 2015-07-22 19:01:14 +0000 | [diff] [blame] | 42 | if (!CallBacksToRun.isConstructed()) |
| 43 | return; |
| 44 | for (auto &I : *CallBacksToRun) |
| 45 | I.first(I.second); |
| 46 | CallBacksToRun->clear(); |
| 47 | } |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 48 | } |
| 49 | |
Reid Kleckner | ba5757d | 2015-11-05 01:07:54 +0000 | [diff] [blame] | 50 | using namespace llvm; |
| 51 | |
| 52 | static bool findModulesAndOffsets(void **StackTrace, int Depth, |
| 53 | const char **Modules, intptr_t *Offsets, |
| 54 | const char *MainExecutableName, |
| 55 | StringSaver &StrPool); |
| 56 | |
| 57 | /// Format a pointer value as hexadecimal. Zero pad it out so its always the |
| 58 | /// same width. |
| 59 | static FormattedNumber format_ptr(void *PC) { |
| 60 | // Each byte is two hex digits plus 2 for the 0x prefix. |
| 61 | unsigned PtrWidth = 2 + 2 * sizeof(void *); |
| 62 | return format_hex((uint64_t)PC, PtrWidth); |
| 63 | } |
| 64 | |
NAKAMURA Takumi | 02d97aa | 2015-11-08 09:45:06 +0000 | [diff] [blame] | 65 | static bool printSymbolizedStackTrace(void **StackTrace, int Depth, |
| 66 | llvm::raw_ostream &OS) |
| 67 | LLVM_ATTRIBUTE_USED; |
| 68 | |
Reid Kleckner | ba5757d | 2015-11-05 01:07:54 +0000 | [diff] [blame] | 69 | /// Helper that launches llvm-symbolizer and symbolizes a backtrace. |
| 70 | static bool printSymbolizedStackTrace(void **StackTrace, int Depth, |
| 71 | llvm::raw_ostream &OS) { |
| 72 | // FIXME: Subtract necessary number from StackTrace entries to turn return addresses |
| 73 | // into actual instruction addresses. |
| 74 | // Use llvm-symbolizer tool to symbolize the stack traces. |
| 75 | ErrorOr<std::string> LLVMSymbolizerPathOrErr = |
| 76 | sys::findProgramByName("llvm-symbolizer"); |
| 77 | if (!LLVMSymbolizerPathOrErr) |
| 78 | return false; |
| 79 | const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr; |
| 80 | // We don't know argv0 or the address of main() at this point, but try |
| 81 | // to guess it anyway (it's possible on some platforms). |
| 82 | std::string MainExecutableName = sys::fs::getMainExecutable(nullptr, nullptr); |
| 83 | if (MainExecutableName.empty() || |
| 84 | MainExecutableName.find("llvm-symbolizer") != std::string::npos) |
| 85 | return false; |
| 86 | |
| 87 | BumpPtrAllocator Allocator; |
| 88 | StringSaver StrPool(Allocator); |
| 89 | std::vector<const char *> Modules(Depth, nullptr); |
| 90 | std::vector<intptr_t> Offsets(Depth, 0); |
| 91 | if (!findModulesAndOffsets(StackTrace, Depth, Modules.data(), Offsets.data(), |
| 92 | MainExecutableName.c_str(), StrPool)) |
| 93 | return false; |
| 94 | int InputFD; |
| 95 | SmallString<32> InputFile, OutputFile; |
| 96 | sys::fs::createTemporaryFile("symbolizer-input", "", InputFD, InputFile); |
| 97 | sys::fs::createTemporaryFile("symbolizer-output", "", OutputFile); |
| 98 | FileRemover InputRemover(InputFile.c_str()); |
| 99 | FileRemover OutputRemover(OutputFile.c_str()); |
| 100 | |
| 101 | { |
| 102 | raw_fd_ostream Input(InputFD, true); |
| 103 | for (int i = 0; i < Depth; i++) { |
| 104 | if (Modules[i]) |
| 105 | Input << Modules[i] << " " << (void*)Offsets[i] << "\n"; |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | StringRef InputFileStr(InputFile); |
| 110 | StringRef OutputFileStr(OutputFile); |
| 111 | StringRef StderrFileStr; |
| 112 | const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr, |
| 113 | &StderrFileStr}; |
| 114 | const char *Args[] = {"llvm-symbolizer", "--functions=linkage", "--inlining", |
| 115 | #ifdef LLVM_ON_WIN32 |
| 116 | // Pass --relative-address on Windows so that we don't |
| 117 | // have to add ImageBase from PE file. |
| 118 | // FIXME: Make this the default for llvm-symbolizer. |
| 119 | "--relative-address", |
| 120 | #endif |
| 121 | "--demangle", nullptr}; |
| 122 | int RunResult = |
| 123 | sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects); |
| 124 | if (RunResult != 0) |
| 125 | return false; |
| 126 | |
| 127 | // This report format is based on the sanitizer stack trace printer. See |
| 128 | // sanitizer_stacktrace_printer.cc in compiler-rt. |
| 129 | auto OutputBuf = MemoryBuffer::getFile(OutputFile.c_str()); |
| 130 | if (!OutputBuf) |
| 131 | return false; |
| 132 | StringRef Output = OutputBuf.get()->getBuffer(); |
| 133 | SmallVector<StringRef, 32> Lines; |
| 134 | Output.split(Lines, "\n"); |
| 135 | auto CurLine = Lines.begin(); |
| 136 | int frame_no = 0; |
| 137 | for (int i = 0; i < Depth; i++) { |
| 138 | if (!Modules[i]) { |
| 139 | OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << '\n'; |
| 140 | continue; |
| 141 | } |
| 142 | // Read pairs of lines (function name and file/line info) until we |
| 143 | // encounter empty line. |
| 144 | for (;;) { |
| 145 | if (CurLine == Lines.end()) |
| 146 | return false; |
| 147 | StringRef FunctionName = *CurLine++; |
| 148 | if (FunctionName.empty()) |
| 149 | break; |
| 150 | OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << ' '; |
| 151 | if (!FunctionName.startswith("??")) |
| 152 | OS << FunctionName << ' '; |
| 153 | if (CurLine == Lines.end()) |
| 154 | return false; |
| 155 | StringRef FileLineInfo = *CurLine++; |
| 156 | if (!FileLineInfo.startswith("??")) |
| 157 | OS << FileLineInfo; |
| 158 | else |
| 159 | OS << "(" << Modules[i] << '+' << format_hex(Offsets[i], 0) << ")"; |
| 160 | OS << "\n"; |
| 161 | } |
| 162 | } |
| 163 | return true; |
| 164 | } |
| 165 | |
Reid Spencer | 3d7a614 | 2004-08-29 19:22:48 +0000 | [diff] [blame] | 166 | // Include the platform-specific parts of this class. |
Reid Spencer | 844f3fe | 2004-12-27 06:16:11 +0000 | [diff] [blame] | 167 | #ifdef LLVM_ON_UNIX |
Reid Spencer | c892a0d | 2005-01-09 23:29:00 +0000 | [diff] [blame] | 168 | #include "Unix/Signals.inc" |
Reid Spencer | 844f3fe | 2004-12-27 06:16:11 +0000 | [diff] [blame] | 169 | #endif |
| 170 | #ifdef LLVM_ON_WIN32 |
Michael J. Spencer | 447762d | 2010-11-29 18:16:10 +0000 | [diff] [blame] | 171 | #include "Windows/Signals.inc" |
Reid Spencer | 844f3fe | 2004-12-27 06:16:11 +0000 | [diff] [blame] | 172 | #endif |