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,89 @@ 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. + MachO::mach_header MachHdr; + memcpy(&MachHdr, ImageBase, sizeof(MachO::mach_header)); + + bool ByteSwap = + MachHdr.magic == MachO::MH_CIGAM || MachHdr.magic == MachO::MH_CIGAM_64; + bool Is64Bit = + MachHdr.magic == MachO::MH_MAGIC_64 || MachHdr.magic == MachO::MH_CIGAM_64; + + if (ByteSwap) + swapStruct(MachHdr); + + ImagePtr += Is64Bit + ? sizeof(MachO::mach_header_64) + : sizeof(MachO::mach_header); + + // Process load commands. + for (uint32_t I = 0; I < MachHdr.ncmds; ++I) { + MachO::load_command LC; + memcpy(&LC, ImagePtr, sizeof(MachO::load_command)); + if (ByteSwap) + swapStruct(LC); + + if (Is64Bit && LC.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 LCSeg64; + memcpy(&LCSeg64, ImagePtr, sizeof(MachO::segment_command_64)); + if (ByteSwap) + swapStruct(LCSeg64); + if (strncmp(LCSeg64.segname, "__TEXT", 16) == 0) + return LCSeg64.vmaddr; + } else if (!Is64Bit && LC.cmd == MachO::LC_SEGMENT) { + MachO::segment_command LCSeg; + memcpy(&LCSeg, ImagePtr, sizeof(MachO::segment_command)); + if (ByteSwap) + swapStruct(LCSeg); + 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.