1 | //===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines some helpful functions for dealing with the possibility of |
10 | // Unix signals occurring while your program is running. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | // |
14 | // This file is extremely careful to only do signal-safe things while in a |
15 | // signal handler. In particular, memory allocation and acquiring a mutex |
16 | // while in a signal handler should never occur. ManagedStatic isn't usable from |
17 | // a signal handler for 2 reasons: |
18 | // |
19 | // 1. Creating a new one allocates. |
20 | // 2. The signal handler could fire while llvm_shutdown is being processed, in |
21 | // which case the ManagedStatic is in an unknown state because it could |
22 | // already have been destroyed, or be in the process of being destroyed. |
23 | // |
24 | // Modifying the behavior of the signal handlers (such as registering new ones) |
25 | // can acquire a mutex, but all this guarantees is that the signal handler |
26 | // behavior is only modified by one thread at a time. A signal handler can still |
27 | // fire while this occurs! |
28 | // |
29 | // Adding work to a signal handler requires lock-freedom (and assume atomics are |
30 | // always lock-free) because the signal handler could fire while new work is |
31 | // being added. |
32 | // |
33 | //===----------------------------------------------------------------------===// |
34 | |
35 | #include "Unix.h" |
36 | #include "llvm/ADT/STLExtras.h" |
37 | #include "llvm/Config/config.h" |
38 | #include "llvm/Demangle/Demangle.h" |
39 | #include "llvm/Support/ExitCodes.h" |
40 | #include "llvm/Support/FileSystem.h" |
41 | #include "llvm/Support/FileUtilities.h" |
42 | #include "llvm/Support/Format.h" |
43 | #include "llvm/Support/MemoryBuffer.h" |
44 | #include "llvm/Support/Mutex.h" |
45 | #include "llvm/Support/Program.h" |
46 | #include "llvm/Support/SaveAndRestore.h" |
47 | #include "llvm/Support/raw_ostream.h" |
48 | #include <algorithm> |
49 | #include <string> |
50 | #ifdef HAVE_BACKTRACE |
51 | #include BACKTRACE_HEADER // For backtrace(). |
52 | #endif |
53 | #if HAVE_SIGNAL_H |
54 | #include <signal.h> |
55 | #endif |
56 | #if HAVE_SYS_STAT_H |
57 | #include <sys/stat.h> |
58 | #endif |
59 | #if HAVE_DLFCN_H |
60 | #include <dlfcn.h> |
61 | #endif |
62 | #if HAVE_MACH_MACH_H |
63 | #include <mach/mach.h> |
64 | #endif |
65 | #ifdef __APPLE__ |
66 | #include <mach-o/dyld.h> |
67 | #endif |
68 | #if HAVE_LINK_H |
69 | #include <link.h> |
70 | #endif |
71 | #ifdef HAVE__UNWIND_BACKTRACE |
72 | // FIXME: We should be able to use <unwind.h> for any target that has an |
73 | // _Unwind_Backtrace function, but on FreeBSD the configure test passes |
74 | // despite the function not existing, and on Android, <unwind.h> conflicts |
75 | // with <link.h>. |
76 | #ifdef __GLIBC__ |
77 | #include <unwind.h> |
78 | #else |
79 | #undef HAVE__UNWIND_BACKTRACE |
80 | #endif |
81 | #endif |
82 | |
83 | using namespace llvm; |
84 | |
85 | static void SignalHandler(int Sig); // defined below. |
86 | static void InfoSignalHandler(int Sig); // defined below. |
87 | |
88 | using SignalHandlerFunctionType = void (*)(); |
89 | /// The function to call if ctrl-c is pressed. |
90 | static std::atomic<SignalHandlerFunctionType> InterruptFunction = nullptr; |
91 | static std::atomic<SignalHandlerFunctionType> InfoSignalFunction = nullptr; |
92 | /// The function to call on SIGPIPE (one-time use only). |
93 | static std::atomic<SignalHandlerFunctionType> OneShotPipeSignalFunction = |
94 | nullptr; |
95 | |
96 | namespace { |
97 | /// Signal-safe removal of files. |
98 | /// Inserting and erasing from the list isn't signal-safe, but removal of files |
99 | /// themselves is signal-safe. Memory is freed when the head is freed, deletion |
100 | /// is therefore not signal-safe either. |
101 | class FileToRemoveList { |
102 | std::atomic<char *> Filename = nullptr; |
103 | std::atomic<FileToRemoveList *> Next = nullptr; |
104 | |
105 | FileToRemoveList() = default; |
106 | // Not signal-safe. |
107 | FileToRemoveList(const std::string &str) : Filename(strdup(s: str.c_str())) {} |
108 | |
109 | public: |
110 | // Not signal-safe. |
111 | ~FileToRemoveList() { |
112 | if (FileToRemoveList *N = Next.exchange(p: nullptr)) |
113 | delete N; |
114 | if (char *F = Filename.exchange(p: nullptr)) |
115 | free(ptr: F); |
116 | } |
117 | |
118 | // Not signal-safe. |
119 | static void insert(std::atomic<FileToRemoveList *> &Head, |
120 | const std::string &Filename) { |
121 | // Insert the new file at the end of the list. |
122 | FileToRemoveList *NewHead = new FileToRemoveList(Filename); |
123 | std::atomic<FileToRemoveList *> *InsertionPoint = &Head; |
124 | FileToRemoveList *OldHead = nullptr; |
125 | while (!InsertionPoint->compare_exchange_strong(p1&: OldHead, p2: NewHead)) { |
126 | InsertionPoint = &OldHead->Next; |
127 | OldHead = nullptr; |
128 | } |
129 | } |
130 | |
131 | // Not signal-safe. |
132 | static void erase(std::atomic<FileToRemoveList *> &Head, |
133 | const std::string &Filename) { |
134 | // Use a lock to avoid concurrent erase: the comparison would access |
135 | // free'd memory. |
136 | static ManagedStatic<sys::SmartMutex<true>> Lock; |
137 | sys::SmartScopedLock<true> Writer(*Lock); |
138 | |
139 | for (FileToRemoveList *Current = Head.load(); Current; |
140 | Current = Current->Next.load()) { |
141 | if (char *OldFilename = Current->Filename.load()) { |
142 | if (OldFilename != Filename) |
143 | continue; |
144 | // Leave an empty filename. |
145 | OldFilename = Current->Filename.exchange(p: nullptr); |
146 | // The filename might have become null between the time we |
147 | // compared it and we exchanged it. |
148 | if (OldFilename) |
149 | free(ptr: OldFilename); |
150 | } |
151 | } |
152 | } |
153 | |
154 | // Signal-safe. |
155 | static void removeAllFiles(std::atomic<FileToRemoveList *> &Head) { |
156 | // If cleanup were to occur while we're removing files we'd have a bad time. |
157 | // Make sure we're OK by preventing cleanup from doing anything while we're |
158 | // removing files. If cleanup races with us and we win we'll have a leak, |
159 | // but we won't crash. |
160 | FileToRemoveList *OldHead = Head.exchange(p: nullptr); |
161 | |
162 | for (FileToRemoveList *currentFile = OldHead; currentFile; |
163 | currentFile = currentFile->Next.load()) { |
164 | // If erasing was occuring while we're trying to remove files we'd look |
165 | // at free'd data. Take away the path and put it back when done. |
166 | if (char *path = currentFile->Filename.exchange(p: nullptr)) { |
167 | // Get the status so we can determine if it's a file or directory. If we |
168 | // can't stat the file, ignore it. |
169 | struct stat buf; |
170 | if (stat(file: path, buf: &buf) != 0) |
171 | continue; |
172 | |
173 | // If this is not a regular file, ignore it. We want to prevent removal |
174 | // of special files like /dev/null, even if the compiler is being run |
175 | // with the super-user permissions. |
176 | if (!S_ISREG(buf.st_mode)) |
177 | continue; |
178 | |
179 | // Otherwise, remove the file. We ignore any errors here as there is |
180 | // nothing else we can do. |
181 | unlink(name: path); |
182 | |
183 | // We're done removing the file, erasing can safely proceed. |
184 | currentFile->Filename.exchange(p: path); |
185 | } |
186 | } |
187 | |
188 | // We're done removing files, cleanup can safely proceed. |
189 | Head.exchange(p: OldHead); |
190 | } |
191 | }; |
192 | static std::atomic<FileToRemoveList *> FilesToRemove = nullptr; |
193 | |
194 | /// Clean up the list in a signal-friendly manner. |
195 | /// Recall that signals can fire during llvm_shutdown. If this occurs we should |
196 | /// either clean something up or nothing at all, but we shouldn't crash! |
197 | struct FilesToRemoveCleanup { |
198 | // Not signal-safe. |
199 | ~FilesToRemoveCleanup() { |
200 | FileToRemoveList *Head = FilesToRemove.exchange(p: nullptr); |
201 | if (Head) |
202 | delete Head; |
203 | } |
204 | }; |
205 | } // namespace |
206 | |
207 | static StringRef Argv0; |
208 | |
209 | /// Signals that represent requested termination. There's no bug or failure, or |
210 | /// if there is, it's not our direct responsibility. For whatever reason, our |
211 | /// continued execution is no longer desirable. |
212 | static const int IntSigs[] = {SIGHUP, SIGINT, SIGTERM, SIGUSR2}; |
213 | |
214 | /// Signals that represent that we have a bug, and our prompt termination has |
215 | /// been ordered. |
216 | static const int KillSigs[] = {SIGILL, |
217 | SIGTRAP, |
218 | SIGABRT, |
219 | SIGFPE, |
220 | SIGBUS, |
221 | SIGSEGV, |
222 | SIGQUIT |
223 | #ifdef SIGSYS |
224 | , |
225 | SIGSYS |
226 | #endif |
227 | #ifdef SIGXCPU |
228 | , |
229 | SIGXCPU |
230 | #endif |
231 | #ifdef SIGXFSZ |
232 | , |
233 | SIGXFSZ |
234 | #endif |
235 | #ifdef SIGEMT |
236 | , |
237 | SIGEMT |
238 | #endif |
239 | }; |
240 | |
241 | /// Signals that represent requests for status. |
242 | static const int InfoSigs[] = {SIGUSR1 |
243 | #ifdef SIGINFO |
244 | , |
245 | SIGINFO |
246 | #endif |
247 | }; |
248 | |
249 | static const size_t NumSigs = std::size(IntSigs) + std::size(KillSigs) + |
250 | std::size(InfoSigs) + 1 /* SIGPIPE */; |
251 | |
252 | static std::atomic<unsigned> NumRegisteredSignals = 0; |
253 | static struct { |
254 | struct sigaction SA; |
255 | int SigNo; |
256 | } RegisteredSignalInfo[NumSigs]; |
257 | |
258 | #if defined(HAVE_SIGALTSTACK) |
259 | // Hold onto both the old and new alternate signal stack so that it's not |
260 | // reported as a leak. We don't make any attempt to remove our alt signal |
261 | // stack if we remove our signal handlers; that can't be done reliably if |
262 | // someone else is also trying to do the same thing. |
263 | static stack_t OldAltStack; |
264 | LLVM_ATTRIBUTE_USED static void *NewAltStackPointer; |
265 | |
266 | static void CreateSigAltStack() { |
267 | const size_t AltStackSize = MINSIGSTKSZ + 64 * 1024; |
268 | |
269 | // If we're executing on the alternate stack, or we already have an alternate |
270 | // signal stack that we're happy with, there's nothing for us to do. Don't |
271 | // reduce the size, some other part of the process might need a larger stack |
272 | // than we do. |
273 | if (sigaltstack(ss: nullptr, oss: &OldAltStack) != 0 || |
274 | OldAltStack.ss_flags & SS_ONSTACK || |
275 | (OldAltStack.ss_sp && OldAltStack.ss_size >= AltStackSize)) |
276 | return; |
277 | |
278 | stack_t AltStack = {}; |
279 | AltStack.ss_sp = static_cast<char *>(safe_malloc(Sz: AltStackSize)); |
280 | NewAltStackPointer = AltStack.ss_sp; // Save to avoid reporting a leak. |
281 | AltStack.ss_size = AltStackSize; |
282 | if (sigaltstack(ss: &AltStack, oss: &OldAltStack) != 0) |
283 | free(ptr: AltStack.ss_sp); |
284 | } |
285 | #else |
286 | static void CreateSigAltStack() {} |
287 | #endif |
288 | |
289 | static void RegisterHandlers() { // Not signal-safe. |
290 | // The mutex prevents other threads from registering handlers while we're |
291 | // doing it. We also have to protect the handlers and their count because |
292 | // a signal handler could fire while we're registering handlers. |
293 | static ManagedStatic<sys::SmartMutex<true>> SignalHandlerRegistrationMutex; |
294 | sys::SmartScopedLock<true> Guard(*SignalHandlerRegistrationMutex); |
295 | |
296 | // If the handlers are already registered, we're done. |
297 | if (NumRegisteredSignals.load() != 0) |
298 | return; |
299 | |
300 | // Create an alternate stack for signal handling. This is necessary for us to |
301 | // be able to reliably handle signals due to stack overflow. |
302 | CreateSigAltStack(); |
303 | |
304 | enum class SignalKind { IsKill, IsInfo }; |
305 | auto registerHandler = [&](int Signal, SignalKind Kind) { |
306 | unsigned Index = NumRegisteredSignals.load(); |
307 | assert(Index < std::size(RegisteredSignalInfo) && |
308 | "Out of space for signal handlers!" ); |
309 | |
310 | struct sigaction NewHandler; |
311 | |
312 | switch (Kind) { |
313 | case SignalKind::IsKill: |
314 | NewHandler.sa_handler = SignalHandler; |
315 | NewHandler.sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK; |
316 | break; |
317 | case SignalKind::IsInfo: |
318 | NewHandler.sa_handler = InfoSignalHandler; |
319 | NewHandler.sa_flags = SA_ONSTACK; |
320 | break; |
321 | } |
322 | sigemptyset(set: &NewHandler.sa_mask); |
323 | |
324 | // Install the new handler, save the old one in RegisteredSignalInfo. |
325 | sigaction(sig: Signal, act: &NewHandler, oact: &RegisteredSignalInfo[Index].SA); |
326 | RegisteredSignalInfo[Index].SigNo = Signal; |
327 | ++NumRegisteredSignals; |
328 | }; |
329 | |
330 | for (auto S : IntSigs) |
331 | registerHandler(S, SignalKind::IsKill); |
332 | for (auto S : KillSigs) |
333 | registerHandler(S, SignalKind::IsKill); |
334 | if (OneShotPipeSignalFunction) |
335 | registerHandler(SIGPIPE, SignalKind::IsKill); |
336 | for (auto S : InfoSigs) |
337 | registerHandler(S, SignalKind::IsInfo); |
338 | } |
339 | |
340 | void sys::unregisterHandlers() { |
341 | // Restore all of the signal handlers to how they were before we showed up. |
342 | for (unsigned i = 0, e = NumRegisteredSignals.load(); i != e; ++i) { |
343 | sigaction(sig: RegisteredSignalInfo[i].SigNo, act: &RegisteredSignalInfo[i].SA, |
344 | oact: nullptr); |
345 | --NumRegisteredSignals; |
346 | } |
347 | } |
348 | |
349 | /// Process the FilesToRemove list. |
350 | static void RemoveFilesToRemove() { |
351 | FileToRemoveList::removeAllFiles(Head&: FilesToRemove); |
352 | } |
353 | |
354 | void sys::CleanupOnSignal(uintptr_t Context) { |
355 | int Sig = (int)Context; |
356 | |
357 | if (llvm::is_contained(Range: InfoSigs, Element: Sig)) { |
358 | InfoSignalHandler(Sig); |
359 | return; |
360 | } |
361 | |
362 | RemoveFilesToRemove(); |
363 | |
364 | if (llvm::is_contained(Range: IntSigs, Element: Sig) || Sig == SIGPIPE) |
365 | return; |
366 | |
367 | llvm::sys::RunSignalHandlers(); |
368 | } |
369 | |
370 | // The signal handler that runs. |
371 | static void SignalHandler(int Sig) { |
372 | // Restore the signal behavior to default, so that the program actually |
373 | // crashes when we return and the signal reissues. This also ensures that if |
374 | // we crash in our signal handler that the program will terminate immediately |
375 | // instead of recursing in the signal handler. |
376 | sys::unregisterHandlers(); |
377 | |
378 | // Unmask all potentially blocked kill signals. |
379 | sigset_t SigMask; |
380 | sigfillset(set: &SigMask); |
381 | sigprocmask(SIG_UNBLOCK, set: &SigMask, oset: nullptr); |
382 | |
383 | { |
384 | RemoveFilesToRemove(); |
385 | |
386 | if (Sig == SIGPIPE) |
387 | if (auto OldOneShotPipeFunction = |
388 | OneShotPipeSignalFunction.exchange(p: nullptr)) |
389 | return OldOneShotPipeFunction(); |
390 | |
391 | bool IsIntSig = llvm::is_contained(Range: IntSigs, Element: Sig); |
392 | if (IsIntSig) |
393 | if (auto OldInterruptFunction = InterruptFunction.exchange(p: nullptr)) |
394 | return OldInterruptFunction(); |
395 | |
396 | if (Sig == SIGPIPE || IsIntSig) { |
397 | raise(sig: Sig); // Execute the default handler. |
398 | return; |
399 | } |
400 | } |
401 | |
402 | // Otherwise if it is a fault (like SEGV) run any handler. |
403 | llvm::sys::RunSignalHandlers(); |
404 | |
405 | #ifdef __s390__ |
406 | // On S/390, certain signals are delivered with PSW Address pointing to |
407 | // *after* the faulting instruction. Simply returning from the signal |
408 | // handler would continue execution after that point, instead of |
409 | // re-raising the signal. Raise the signal manually in those cases. |
410 | if (Sig == SIGILL || Sig == SIGFPE || Sig == SIGTRAP) |
411 | raise(Sig); |
412 | #endif |
413 | } |
414 | |
415 | static void InfoSignalHandler(int Sig) { |
416 | SaveAndRestore SaveErrnoDuringASignalHandler(errno); |
417 | if (SignalHandlerFunctionType CurrentInfoFunction = InfoSignalFunction) |
418 | CurrentInfoFunction(); |
419 | } |
420 | |
421 | void llvm::sys::RunInterruptHandlers() { RemoveFilesToRemove(); } |
422 | |
423 | void llvm::sys::SetInterruptFunction(void (*IF)()) { |
424 | InterruptFunction.exchange(p: IF); |
425 | RegisterHandlers(); |
426 | } |
427 | |
428 | void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { |
429 | InfoSignalFunction.exchange(p: Handler); |
430 | RegisterHandlers(); |
431 | } |
432 | |
433 | void llvm::sys::SetOneShotPipeSignalFunction(void (*Handler)()) { |
434 | OneShotPipeSignalFunction.exchange(p: Handler); |
435 | RegisterHandlers(); |
436 | } |
437 | |
438 | void llvm::sys::DefaultOneShotPipeSignalHandler() { |
439 | // Send a special return code that drivers can check for, from sysexits.h. |
440 | exit(EX_IOERR); |
441 | } |
442 | |
443 | // The public API |
444 | bool llvm::sys::RemoveFileOnSignal(StringRef Filename, std::string *ErrMsg) { |
445 | // Ensure that cleanup will occur as soon as one file is added. |
446 | static ManagedStatic<FilesToRemoveCleanup> FilesToRemoveCleanup; |
447 | *FilesToRemoveCleanup; |
448 | FileToRemoveList::insert(Head&: FilesToRemove, Filename: Filename.str()); |
449 | RegisterHandlers(); |
450 | return false; |
451 | } |
452 | |
453 | // The public API |
454 | void llvm::sys::DontRemoveFileOnSignal(StringRef Filename) { |
455 | FileToRemoveList::erase(Head&: FilesToRemove, Filename: Filename.str()); |
456 | } |
457 | |
458 | /// Add a function to be called when a signal is delivered to the process. The |
459 | /// handler can have a cookie passed to it to identify what instance of the |
460 | /// handler it is. |
461 | void llvm::sys::AddSignalHandler(sys::SignalHandlerCallback FnPtr, |
462 | void *Cookie) { // Signal-safe. |
463 | insertSignalHandler(FnPtr, Cookie); |
464 | RegisterHandlers(); |
465 | } |
466 | |
467 | #if ENABLE_BACKTRACES && defined(HAVE_BACKTRACE) && HAVE_LINK_H && \ |
468 | (defined(__linux__) || defined(__FreeBSD__) || \ |
469 | defined(__FreeBSD_kernel__) || defined(__NetBSD__)) |
470 | struct DlIteratePhdrData { |
471 | void **StackTrace; |
472 | int depth; |
473 | bool first; |
474 | const char **modules; |
475 | intptr_t *offsets; |
476 | const char *main_exec_name; |
477 | }; |
478 | |
479 | static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { |
480 | DlIteratePhdrData *data = (DlIteratePhdrData *)arg; |
481 | const char *name = data->first ? data->main_exec_name : info->dlpi_name; |
482 | data->first = false; |
483 | for (int i = 0; i < info->dlpi_phnum; i++) { |
484 | const auto *phdr = &info->dlpi_phdr[i]; |
485 | if (phdr->p_type != PT_LOAD) |
486 | continue; |
487 | intptr_t beg = info->dlpi_addr + phdr->p_vaddr; |
488 | intptr_t end = beg + phdr->p_memsz; |
489 | for (int j = 0; j < data->depth; j++) { |
490 | if (data->modules[j]) |
491 | continue; |
492 | intptr_t addr = (intptr_t)data->StackTrace[j]; |
493 | if (beg <= addr && addr < end) { |
494 | data->modules[j] = name; |
495 | data->offsets[j] = addr - info->dlpi_addr; |
496 | } |
497 | } |
498 | } |
499 | return 0; |
500 | } |
501 | |
502 | /// If this is an ELF platform, we can find all loaded modules and their virtual |
503 | /// addresses with dl_iterate_phdr. |
504 | static bool findModulesAndOffsets(void **StackTrace, int Depth, |
505 | const char **Modules, intptr_t *Offsets, |
506 | const char *MainExecutableName, |
507 | StringSaver &StrPool) { |
508 | DlIteratePhdrData data = {.StackTrace: StackTrace, .depth: Depth, .first: true, |
509 | .modules: Modules, .offsets: Offsets, .main_exec_name: MainExecutableName}; |
510 | dl_iterate_phdr(callback: dl_iterate_phdr_cb, data: &data); |
511 | return true; |
512 | } |
513 | |
514 | class DSOMarkupPrinter { |
515 | llvm::raw_ostream &OS; |
516 | const char *MainExecutableName; |
517 | size_t ModuleCount = 0; |
518 | bool IsFirst = true; |
519 | |
520 | public: |
521 | DSOMarkupPrinter(llvm::raw_ostream &OS, const char *MainExecutableName) |
522 | : OS(OS), MainExecutableName(MainExecutableName) {} |
523 | |
524 | /// Print llvm-symbolizer markup describing the layout of the given DSO. |
525 | void printDSOMarkup(dl_phdr_info *Info) { |
526 | ArrayRef<uint8_t> BuildID = findBuildID(Info); |
527 | if (BuildID.empty()) |
528 | return; |
529 | OS << format(Fmt: "{{{module:%d:%s:elf:" , Vals: ModuleCount, |
530 | Vals: IsFirst ? MainExecutableName : Info->dlpi_name); |
531 | for (uint8_t X : BuildID) |
532 | OS << format(Fmt: "%02x" , Vals: X); |
533 | OS << "}}}\n" ; |
534 | |
535 | for (int I = 0; I < Info->dlpi_phnum; I++) { |
536 | const auto *Phdr = &Info->dlpi_phdr[I]; |
537 | if (Phdr->p_type != PT_LOAD) |
538 | continue; |
539 | uintptr_t StartAddress = Info->dlpi_addr + Phdr->p_vaddr; |
540 | uintptr_t ModuleRelativeAddress = Phdr->p_vaddr; |
541 | std::array<char, 4> ModeStr = modeStrFromFlags(Flags: Phdr->p_flags); |
542 | OS << format(Fmt: "{{{mmap:%#016x:%#x:load:%d:%s:%#016x}}}\n" , Vals: StartAddress, |
543 | Vals: Phdr->p_memsz, Vals: ModuleCount, Vals: &ModeStr[0], |
544 | Vals: ModuleRelativeAddress); |
545 | } |
546 | IsFirst = false; |
547 | ModuleCount++; |
548 | } |
549 | |
550 | /// Callback for use with dl_iterate_phdr. The last dl_iterate_phdr argument |
551 | /// must be a pointer to an instance of this class. |
552 | static int printDSOMarkup(dl_phdr_info *Info, size_t Size, void *Arg) { |
553 | static_cast<DSOMarkupPrinter *>(Arg)->printDSOMarkup(Info); |
554 | return 0; |
555 | } |
556 | |
557 | // Returns the build ID for the given DSO as an array of bytes. Returns an |
558 | // empty array if none could be found. |
559 | ArrayRef<uint8_t> findBuildID(dl_phdr_info *Info) { |
560 | for (int I = 0; I < Info->dlpi_phnum; I++) { |
561 | const auto *Phdr = &Info->dlpi_phdr[I]; |
562 | if (Phdr->p_type != PT_NOTE) |
563 | continue; |
564 | |
565 | ArrayRef<uint8_t> Notes( |
566 | reinterpret_cast<const uint8_t *>(Info->dlpi_addr + Phdr->p_vaddr), |
567 | Phdr->p_memsz); |
568 | while (Notes.size() > 12) { |
569 | uint32_t NameSize = *reinterpret_cast<const uint32_t *>(Notes.data()); |
570 | Notes = Notes.drop_front(N: 4); |
571 | uint32_t DescSize = *reinterpret_cast<const uint32_t *>(Notes.data()); |
572 | Notes = Notes.drop_front(N: 4); |
573 | uint32_t Type = *reinterpret_cast<const uint32_t *>(Notes.data()); |
574 | Notes = Notes.drop_front(N: 4); |
575 | |
576 | ArrayRef<uint8_t> Name = Notes.take_front(N: NameSize); |
577 | auto CurPos = reinterpret_cast<uintptr_t>(Notes.data()); |
578 | uint32_t BytesUntilDesc = |
579 | alignToPowerOf2(Value: CurPos + NameSize, Align: 4) - CurPos; |
580 | if (BytesUntilDesc >= Notes.size()) |
581 | break; |
582 | Notes = Notes.drop_front(N: BytesUntilDesc); |
583 | |
584 | ArrayRef<uint8_t> Desc = Notes.take_front(N: DescSize); |
585 | CurPos = reinterpret_cast<uintptr_t>(Notes.data()); |
586 | uint32_t BytesUntilNextNote = |
587 | alignToPowerOf2(Value: CurPos + DescSize, Align: 4) - CurPos; |
588 | if (BytesUntilNextNote > Notes.size()) |
589 | break; |
590 | Notes = Notes.drop_front(N: BytesUntilNextNote); |
591 | |
592 | if (Type == 3 /*NT_GNU_BUILD_ID*/ && Name.size() >= 3 && |
593 | Name[0] == 'G' && Name[1] == 'N' && Name[2] == 'U') |
594 | return Desc; |
595 | } |
596 | } |
597 | return {}; |
598 | } |
599 | |
600 | // Returns a symbolizer markup string describing the permissions on a DSO |
601 | // with the given p_flags. |
602 | std::array<char, 4> modeStrFromFlags(uint32_t Flags) { |
603 | std::array<char, 4> Mode; |
604 | char *Cur = &Mode[0]; |
605 | if (Flags & PF_R) |
606 | *Cur++ = 'r'; |
607 | if (Flags & PF_W) |
608 | *Cur++ = 'w'; |
609 | if (Flags & PF_X) |
610 | *Cur++ = 'x'; |
611 | *Cur = '\0'; |
612 | return Mode; |
613 | } |
614 | }; |
615 | |
616 | static bool printMarkupContext(llvm::raw_ostream &OS, |
617 | const char *MainExecutableName) { |
618 | OS << "{{{reset}}}\n" ; |
619 | DSOMarkupPrinter MP(OS, MainExecutableName); |
620 | dl_iterate_phdr(callback: DSOMarkupPrinter::printDSOMarkup, data: &MP); |
621 | return true; |
622 | } |
623 | |
624 | #elif ENABLE_BACKTRACES && defined(__APPLE__) && defined(__LP64__) |
625 | static bool findModulesAndOffsets(void **StackTrace, int Depth, |
626 | const char **Modules, intptr_t *Offsets, |
627 | const char *MainExecutableName, |
628 | StringSaver &StrPool) { |
629 | uint32_t NumImgs = _dyld_image_count(); |
630 | for (uint32_t ImageIndex = 0; ImageIndex < NumImgs; ImageIndex++) { |
631 | const char *Name = _dyld_get_image_name(ImageIndex); |
632 | intptr_t Slide = _dyld_get_image_vmaddr_slide(ImageIndex); |
633 | auto *Header = |
634 | (const struct mach_header_64 *)_dyld_get_image_header(ImageIndex); |
635 | if (Header == NULL) |
636 | continue; |
637 | auto Cmd = (const struct load_command *)(&Header[1]); |
638 | for (uint32_t CmdNum = 0; CmdNum < Header->ncmds; ++CmdNum) { |
639 | uint32_t BaseCmd = Cmd->cmd & ~LC_REQ_DYLD; |
640 | if (BaseCmd == LC_SEGMENT_64) { |
641 | auto CmdSeg64 = (const struct segment_command_64 *)Cmd; |
642 | for (int j = 0; j < Depth; j++) { |
643 | if (Modules[j]) |
644 | continue; |
645 | intptr_t Addr = (intptr_t)StackTrace[j]; |
646 | if ((intptr_t)CmdSeg64->vmaddr + Slide <= Addr && |
647 | Addr < intptr_t(CmdSeg64->vmaddr + CmdSeg64->vmsize + Slide)) { |
648 | Modules[j] = Name; |
649 | Offsets[j] = Addr - Slide; |
650 | } |
651 | } |
652 | } |
653 | Cmd = (const load_command *)(((const char *)Cmd) + (Cmd->cmdsize)); |
654 | } |
655 | } |
656 | return true; |
657 | } |
658 | |
659 | static bool printMarkupContext(llvm::raw_ostream &OS, |
660 | const char *MainExecutableName) { |
661 | return false; |
662 | } |
663 | #else |
664 | /// Backtraces are not enabled or we don't yet know how to find all loaded DSOs |
665 | /// on this platform. |
666 | static bool findModulesAndOffsets(void **StackTrace, int Depth, |
667 | const char **Modules, intptr_t *Offsets, |
668 | const char *MainExecutableName, |
669 | StringSaver &StrPool) { |
670 | return false; |
671 | } |
672 | |
673 | static bool printMarkupContext(llvm::raw_ostream &OS, |
674 | const char *MainExecutableName) { |
675 | return false; |
676 | } |
677 | #endif // ENABLE_BACKTRACES && ... (findModulesAndOffsets variants) |
678 | |
679 | #if ENABLE_BACKTRACES && defined(HAVE__UNWIND_BACKTRACE) |
680 | static int unwindBacktrace(void **StackTrace, int MaxEntries) { |
681 | if (MaxEntries < 0) |
682 | return 0; |
683 | |
684 | // Skip the first frame ('unwindBacktrace' itself). |
685 | int Entries = -1; |
686 | |
687 | auto HandleFrame = [&](_Unwind_Context *Context) -> _Unwind_Reason_Code { |
688 | // Apparently we need to detect reaching the end of the stack ourselves. |
689 | void *IP = (void *)_Unwind_GetIP(Context); |
690 | if (!IP) |
691 | return _URC_END_OF_STACK; |
692 | |
693 | assert(Entries < MaxEntries && "recursively called after END_OF_STACK?" ); |
694 | if (Entries >= 0) |
695 | StackTrace[Entries] = IP; |
696 | |
697 | if (++Entries == MaxEntries) |
698 | return _URC_END_OF_STACK; |
699 | return _URC_NO_REASON; |
700 | }; |
701 | |
702 | _Unwind_Backtrace( |
703 | [](_Unwind_Context *Context, void *Handler) { |
704 | return (*static_cast<decltype(HandleFrame) *>(Handler))(Context); |
705 | }, |
706 | static_cast<void *>(&HandleFrame)); |
707 | return std::max(a: Entries, b: 0); |
708 | } |
709 | #endif |
710 | |
711 | // In the case of a program crash or fault, print out a stack trace so that the |
712 | // user has an indication of why and where we died. |
713 | // |
714 | // On glibc systems we have the 'backtrace' function, which works nicely, but |
715 | // doesn't demangle symbols. |
716 | void llvm::sys::PrintStackTrace(raw_ostream &OS, int Depth) { |
717 | #if ENABLE_BACKTRACES |
718 | static void *StackTrace[256]; |
719 | int depth = 0; |
720 | #if defined(HAVE_BACKTRACE) |
721 | // Use backtrace() to output a backtrace on Linux systems with glibc. |
722 | if (!depth) |
723 | depth = backtrace(array: StackTrace, size: static_cast<int>(std::size(StackTrace))); |
724 | #endif |
725 | #if defined(HAVE__UNWIND_BACKTRACE) |
726 | // Try _Unwind_Backtrace() if backtrace() failed. |
727 | if (!depth) |
728 | depth = |
729 | unwindBacktrace(StackTrace, MaxEntries: static_cast<int>(std::size(StackTrace))); |
730 | #endif |
731 | if (!depth) |
732 | return; |
733 | // If "Depth" is not provided by the caller, use the return value of |
734 | // backtrace() for printing a symbolized stack trace. |
735 | if (!Depth) |
736 | Depth = depth; |
737 | if (printMarkupStackTrace(Argv0, StackTrace, Depth, OS)) |
738 | return; |
739 | if (printSymbolizedStackTrace(Argv0, StackTrace, Depth, OS)) |
740 | return; |
741 | OS << "Stack dump without symbol names (ensure you have llvm-symbolizer in " |
742 | "your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point " |
743 | "to it):\n" ; |
744 | #if HAVE_DLFCN_H && HAVE_DLADDR |
745 | int width = 0; |
746 | for (int i = 0; i < depth; ++i) { |
747 | Dl_info dlinfo; |
748 | dladdr(address: StackTrace[i], info: &dlinfo); |
749 | const char *name = strrchr(s: dlinfo.dli_fname, c: '/'); |
750 | |
751 | int nwidth; |
752 | if (!name) |
753 | nwidth = strlen(s: dlinfo.dli_fname); |
754 | else |
755 | nwidth = strlen(s: name) - 1; |
756 | |
757 | if (nwidth > width) |
758 | width = nwidth; |
759 | } |
760 | |
761 | for (int i = 0; i < depth; ++i) { |
762 | Dl_info dlinfo; |
763 | dladdr(address: StackTrace[i], info: &dlinfo); |
764 | |
765 | OS << format(Fmt: "%-2d" , Vals: i); |
766 | |
767 | const char *name = strrchr(s: dlinfo.dli_fname, c: '/'); |
768 | if (!name) |
769 | OS << format(Fmt: " %-*s" , Vals: width, Vals: dlinfo.dli_fname); |
770 | else |
771 | OS << format(Fmt: " %-*s" , Vals: width, Vals: name + 1); |
772 | |
773 | OS << format(Fmt: " %#0*lx" , Vals: (int)(sizeof(void *) * 2) + 2, |
774 | Vals: (unsigned long)StackTrace[i]); |
775 | |
776 | if (dlinfo.dli_sname != nullptr) { |
777 | OS << ' '; |
778 | if (char *d = itaniumDemangle(mangled_name: dlinfo.dli_sname)) { |
779 | OS << d; |
780 | free(ptr: d); |
781 | } else { |
782 | OS << dlinfo.dli_sname; |
783 | } |
784 | |
785 | OS << format(Fmt: " + %tu" , Vals: (static_cast<const char *>(StackTrace[i]) - |
786 | static_cast<const char *>(dlinfo.dli_saddr))); |
787 | } |
788 | OS << '\n'; |
789 | } |
790 | #elif defined(HAVE_BACKTRACE) |
791 | backtrace_symbols_fd(StackTrace, Depth, STDERR_FILENO); |
792 | #endif |
793 | #endif |
794 | } |
795 | |
796 | static void PrintStackTraceSignalHandler(void *) { |
797 | sys::PrintStackTrace(OS&: llvm::errs()); |
798 | } |
799 | |
800 | void llvm::sys::DisableSystemDialogsOnCrash() {} |
801 | |
802 | /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the |
803 | /// process, print a stack trace and then exit. |
804 | void llvm::sys::PrintStackTraceOnErrorSignal(StringRef Argv0, |
805 | bool DisableCrashReporting) { |
806 | ::Argv0 = Argv0; |
807 | |
808 | AddSignalHandler(FnPtr: PrintStackTraceSignalHandler, Cookie: nullptr); |
809 | |
810 | #if defined(__APPLE__) && ENABLE_CRASH_OVERRIDES |
811 | // Environment variable to disable any kind of crash dialog. |
812 | if (DisableCrashReporting || getenv("LLVM_DISABLE_CRASH_REPORT" )) { |
813 | mach_port_t self = mach_task_self(); |
814 | |
815 | exception_mask_t mask = EXC_MASK_CRASH; |
816 | |
817 | kern_return_t ret = task_set_exception_ports( |
818 | self, mask, MACH_PORT_NULL, |
819 | EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); |
820 | (void)ret; |
821 | } |
822 | #endif |
823 | } |
824 | |