diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc --- a/llvm/lib/Support/Unix/Signals.inc +++ b/llvm/lib/Support/Unix/Signals.inc @@ -34,6 +34,7 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Config/config.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/FileSystem.h" @@ -490,6 +491,73 @@ dl_iterate_phdr(dl_iterate_phdr_cb, &data); return true; } +#elif defined(__APPLE__) + +static uintptr_t getImagePreferredLoadAddress(const void *ImageBase) { + const char *ImagePtr = reinterpret_cast(ImageBase); + + // Process header. + const auto *MachHdr = reinterpret_cast(ImagePtr); + + if (MachHdr->magic != MachO::MH_MAGIC && MachHdr->magic != MachO::MH_MAGIC_64) + return ~0ULL; + bool Is64Bit = MachHdr->magic == MachO::MH_MAGIC_64; + ImagePtr += + Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); + + // Process load commands. + for (uint32_t I = 0; I < MachHdr->ncmds; ++I) { + const auto *LC = reinterpret_cast(ImagePtr); + if (Is64Bit && LC->cmd == MachO::LC_SEGMENT_64) { + const auto *LCSeg64 = + reinterpret_cast(ImagePtr); + if (strncmp(LCSeg64->segname, "__TEXT", 16) == 0) + return LCSeg64->vmaddr; + } else if (!Is64Bit && LC->cmd == MachO::LC_SEGMENT) { + const auto *LCSeg = reinterpret_cast(ImagePtr); + if (strncmp(LCSeg->segname, "__TEXT", 16) == 0) + return LCSeg->vmaddr; + } + + ImagePtr += LC->cmdsize; + + // Bail out with an error value if the load command walk takes us out of + // bounds. This should never happen with well-formed images. + if (ImagePtr - reinterpret_cast(ImageBase) >= + MachHdr->sizeofcmds) + return ~0U; + } + + // No segment load command found. Return an error value. + return ~0U; +} + +static bool findModulesAndOffsets(void **StackTrace, int Depth, + const char **Modules, intptr_t *Offsets, + const char *MainExecutableName, + StringSaver &StrPool) { + for (int I = 0; I != Depth; ++I) { + Dl_info dlinfo; + dladdr(StackTrace[I], &dlinfo); + + uintptr_t OffsetInImage = + (uintptr_t)StackTrace[I] - (uintptr_t)dlinfo.dli_fbase; + + uintptr_t PreferredLoadAddress = + getImagePreferredLoadAddress(dlinfo.dli_fbase); + + if (PreferredLoadAddress == (uintptr_t)~0ULL) + return false; + + if (auto *Basename = strrchr(dlinfo.dli_fname, '/')) + Modules[I] = Basename + 1; + else + Modules[I] = dlinfo.dli_fname; + Offsets[I] = OffsetInImage + PreferredLoadAddress; + } + return true; +} + #else /// This platform does not have dl_iterate_phdr, so we do not yet know how to /// find all loaded DSOs.