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