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 @@ -61,6 +61,7 @@ #endif #if HAVE_MACH_MACH_H #include +#include #endif #if HAVE_LINK_H #include @@ -507,6 +508,70 @@ dl_iterate_phdr(dl_iterate_phdr_cb, &data); return true; } +#elif HAVE_MACH_MACH_H + +// Use the _dyld_* functions to find the loaded modules and populate +// the modules and offset arrays for each stack frame. +static bool findModulesAndOffsets(void **StackTrace, int Depth, + const char **Modules, intptr_t *Offsets, + const char *MainExecutableName, + StringSaver &Unused) { + int ImageCount = _dyld_image_count(); + // Find the image name and the offset for a given PC. + auto ProcessPC = [&](intptr_t pc, const char **Name, intptr_t *Offset) { + *Name = nullptr; + *Offset = 0; + // Scan the images in the binary and find the one that contains the PC. + for (int ImageID = 0; ImageID < ImageCount; ++ImageID) { + // Get the image header, and find the pointer to the first command (right + // after the header). + const struct mach_header *Header = + (const struct mach_header *)_dyld_get_image_header(ImageID); + intptr_t ImageOffset = _dyld_get_image_vmaddr_slide(ImageID); + intptr_t HeaderSize = sizeof(mach_header); + if (Header->magic == MH_MAGIC_64) + HeaderSize = sizeof(mach_header_64); + const struct load_command *cmd = + reinterpret_cast( + reinterpret_cast(Header) + HeaderSize); + + // Iterate all the load commands, looking for a segment containing the PC. + for (unsigned CmdID = 0; CmdID < Header->ncmds; + ++CmdID, cmd = (const struct load_command + *)(reinterpret_cast(cmd) + + cmd->cmdsize)) { + // Compute the interval of addresses covered by this segment. + intptr_t SegStart = 0; + intptr_t SegEnd = 0; + if (cmd->cmd == LC_SEGMENT) { + const struct segment_command *seg = + (const struct segment_command *)cmd; + SegStart = seg->vmaddr + ImageOffset; + SegEnd = SegStart + seg->vmsize; + } else if (cmd->cmd == LC_SEGMENT_64) { + const struct segment_command_64 *seg = + (const struct segment_command_64 *)cmd; + SegStart = seg->vmaddr + ImageOffset; + SegEnd = SegStart + seg->vmsize; + } else { + continue; + } + if ((pc >= SegStart) && (pc < SegEnd)) { + *Name = _dyld_get_image_name(ImageID); + *Offset = pc - ImageOffset; + return; + } + } + } + }; + // Iterate over the stack trace and find the module and offset for each PC. + for (int i = 0; i < Depth; i++) { + intptr_t pc = reinterpret_cast(StackTrace[i]); + ProcessPC(pc, &Modules[i], &Offsets[i]); + } + return true; +} + #else /// This platform does not have dl_iterate_phdr, so we do not yet know how to /// find all loaded DSOs.