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/ADT/STLExtras.h" |
16 | #include "llvm/ADT/StringRef.h" |
17 | #include "llvm/Config/config.h" |
18 | #include "llvm/Support/ErrorOr.h" |
19 | #include "llvm/Support/FileSystem.h" |
20 | #include "llvm/Support/FileUtilities.h" |
21 | #include "llvm/Support/Format.h" |
22 | #include "llvm/Support/ManagedStatic.h" |
23 | #include "llvm/Support/MemoryBuffer.h" |
24 | #include "llvm/Support/Mutex.h" |
25 | #include "llvm/Support/Program.h" |
26 | #include "llvm/Support/Signals.h" |
27 | #include "llvm/Support/StringSaver.h" |
28 | #include "llvm/Support/raw_ostream.h" |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | using namespace sys; |
33 | |
34 | //===----------------------------------------------------------------------===// |
35 | //=== WARNING: Implementation here must contain only TRULY operating system |
36 | //=== independent code. |
37 | //===----------------------------------------------------------------------===// |
38 | |
39 | static ManagedStatic<std::vector<std::pair<void (*)(void *), void *>>> |
40 | CallBacksToRun; |
41 | void sys::RunSignalHandlers() { |
42 | if (!CallBacksToRun.isConstructed()) |
43 | return; |
44 | for (auto &I : *CallBacksToRun) |
45 | I.first(I.second); |
46 | CallBacksToRun->clear(); |
47 | } |
48 | } |
49 | |
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 | |
65 | static bool printSymbolizedStackTrace(StringRef Argv0, |
66 | void **StackTrace, int Depth, |
67 | llvm::raw_ostream &OS) |
68 | LLVM_ATTRIBUTE_USED; |
69 | |
70 | /// Helper that launches llvm-symbolizer and symbolizes a backtrace. |
71 | static bool printSymbolizedStackTrace(StringRef Argv0, |
72 | void **StackTrace, int Depth, |
73 | llvm::raw_ostream &OS) { |
74 | // Don't recursively invoke the llvm-symbolizer binary. |
75 | if (Argv0.find("llvm-symbolizer" ) != std::string::npos) |
76 | return false; |
77 | |
78 | // FIXME: Subtract necessary number from StackTrace entries to turn return addresses |
79 | // into actual instruction addresses. |
80 | // Use llvm-symbolizer tool to symbolize the stack traces. First look for it |
81 | // alongside our binary, then in $PATH. |
82 | ErrorOr<std::string> LLVMSymbolizerPathOrErr = std::error_code(); |
83 | if (!Argv0.empty()) { |
84 | StringRef Parent = llvm::sys::path::parent_path(Argv0); |
85 | if (!Parent.empty()) |
86 | LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer" , Parent); |
87 | } |
88 | if (!LLVMSymbolizerPathOrErr) |
89 | LLVMSymbolizerPathOrErr = sys::findProgramByName("llvm-symbolizer" ); |
90 | if (!LLVMSymbolizerPathOrErr) |
91 | return false; |
92 | const std::string &LLVMSymbolizerPath = *LLVMSymbolizerPathOrErr; |
93 | |
94 | // If we don't know argv0 or the address of main() at this point, try |
95 | // to guess it anyway (it's possible on some platforms). |
96 | std::string MainExecutableName = |
97 | Argv0.empty() ? sys::fs::getMainExecutable(nullptr, nullptr) |
98 | : (std::string)Argv0; |
99 | BumpPtrAllocator Allocator; |
100 | StringSaver StrPool(Allocator); |
101 | std::vector<const char *> Modules(Depth, nullptr); |
102 | std::vector<intptr_t> Offsets(Depth, 0); |
103 | if (!findModulesAndOffsets(StackTrace, Depth, Modules.data(), Offsets.data(), |
104 | MainExecutableName.c_str(), StrPool)) |
105 | return false; |
106 | int InputFD; |
107 | SmallString<32> InputFile, OutputFile; |
108 | sys::fs::createTemporaryFile("symbolizer-input" , "" , InputFD, InputFile); |
109 | sys::fs::createTemporaryFile("symbolizer-output" , "" , OutputFile); |
110 | FileRemover InputRemover(InputFile.c_str()); |
111 | FileRemover OutputRemover(OutputFile.c_str()); |
112 | |
113 | { |
114 | raw_fd_ostream Input(InputFD, true); |
115 | for (int i = 0; i < Depth; i++) { |
116 | if (Modules[i]) |
117 | Input << Modules[i] << " " << (void*)Offsets[i] << "\n" ; |
118 | } |
119 | } |
120 | |
121 | StringRef InputFileStr(InputFile); |
122 | StringRef OutputFileStr(OutputFile); |
123 | StringRef StderrFileStr; |
124 | const StringRef *Redirects[] = {&InputFileStr, &OutputFileStr, |
125 | &StderrFileStr}; |
126 | const char *Args[] = {"llvm-symbolizer" , "--functions=linkage" , "--inlining" , |
127 | #ifdef LLVM_ON_WIN32 |
128 | // Pass --relative-address on Windows so that we don't |
129 | // have to add ImageBase from PE file. |
130 | // FIXME: Make this the default for llvm-symbolizer. |
131 | "--relative-address" , |
132 | #endif |
133 | "--demangle" , nullptr}; |
134 | int RunResult = |
135 | sys::ExecuteAndWait(LLVMSymbolizerPath, Args, nullptr, Redirects); |
136 | if (RunResult != 0) |
137 | return false; |
138 | |
139 | // This report format is based on the sanitizer stack trace printer. See |
140 | // sanitizer_stacktrace_printer.cc in compiler-rt. |
141 | auto OutputBuf = MemoryBuffer::getFile(OutputFile.c_str()); |
142 | if (!OutputBuf) |
143 | return false; |
144 | StringRef Output = OutputBuf.get()->getBuffer(); |
145 | SmallVector<StringRef, 32> Lines; |
146 | Output.split(Lines, "\n" ); |
147 | auto CurLine = Lines.begin(); |
148 | int frame_no = 0; |
149 | for (int i = 0; i < Depth; i++) { |
150 | if (!Modules[i]) { |
151 | OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << '\n'; |
152 | continue; |
153 | } |
154 | // Read pairs of lines (function name and file/line info) until we |
155 | // encounter empty line. |
156 | for (;;) { |
157 | if (CurLine == Lines.end()) |
158 | return false; |
159 | StringRef FunctionName = *CurLine++; |
160 | if (FunctionName.empty()) |
161 | break; |
162 | OS << '#' << frame_no++ << ' ' << format_ptr(StackTrace[i]) << ' '; |
163 | if (!FunctionName.startswith("??" )) |
164 | OS << FunctionName << ' '; |
165 | if (CurLine == Lines.end()) |
166 | return false; |
167 | StringRef FileLineInfo = *CurLine++; |
168 | if (!FileLineInfo.startswith("??" )) |
169 | OS << FileLineInfo; |
170 | else |
171 | OS << "(" << Modules[i] << '+' << format_hex(Offsets[i], 0) << ")" ; |
172 | OS << "\n" ; |
173 | } |
174 | } |
175 | return true; |
176 | } |
177 | |
178 | // Include the platform-specific parts of this class. |
179 | #ifdef LLVM_ON_UNIX |
180 | #include "Unix/Signals.inc" |
181 | #endif |
182 | #ifdef LLVM_ON_WIN32 |
183 | #include "Windows/Signals.inc" |
184 | #endif |
185 | |