michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "shared-libraries.h" michael@0: michael@0: #ifndef MAC_OS_X_VERSION_10_6 michael@0: #define MAC_OS_X_VERSION_10_6 1060 michael@0: #endif michael@0: michael@0: #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 michael@0: // borrowed from Breakpad michael@0: // Fallback declarations for TASK_DYLD_INFO and friends, introduced in michael@0: // in the Mac OS X 10.6 SDK. michael@0: #define TASK_DYLD_INFO 17 michael@0: struct task_dyld_info { michael@0: mach_vm_address_t all_image_info_addr; michael@0: mach_vm_size_t all_image_info_size; michael@0: }; michael@0: typedef struct task_dyld_info task_dyld_info_data_t; michael@0: typedef struct task_dyld_info *task_dyld_info_t; michael@0: #define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t)) michael@0: michael@0: #endif michael@0: michael@0: // Architecture specific abstraction. michael@0: #ifdef __i386__ michael@0: typedef mach_header platform_mach_header; michael@0: typedef segment_command mach_segment_command_type; michael@0: #define MACHO_MAGIC_NUMBER MH_MAGIC michael@0: #define CMD_SEGMENT LC_SEGMENT michael@0: #define seg_size uint32_t michael@0: #else michael@0: typedef mach_header_64 platform_mach_header; michael@0: typedef segment_command_64 mach_segment_command_type; michael@0: #define MACHO_MAGIC_NUMBER MH_MAGIC_64 michael@0: #define CMD_SEGMENT LC_SEGMENT_64 michael@0: #define seg_size uint64_t michael@0: #endif michael@0: michael@0: static michael@0: void addSharedLibrary(const platform_mach_header* header, char *name, SharedLibraryInfo &info) { michael@0: const struct load_command *cmd = michael@0: reinterpret_cast(header + 1); michael@0: michael@0: seg_size size = 0; michael@0: unsigned long long start = reinterpret_cast(header); michael@0: // Find the cmd segment in the macho image. It will contain the offset we care about. michael@0: const uint8_t *uuid_bytes = nullptr; michael@0: for (unsigned int i = 0; michael@0: cmd && (i < header->ncmds) && (uuid_bytes == nullptr || size == 0); michael@0: ++i) { michael@0: if (cmd->cmd == CMD_SEGMENT) { michael@0: const mach_segment_command_type *seg = michael@0: reinterpret_cast(cmd); michael@0: michael@0: if (!strcmp(seg->segname, "__TEXT")) { michael@0: size = seg->vmsize; michael@0: } michael@0: } else if (cmd->cmd == LC_UUID) { michael@0: const uuid_command *ucmd = reinterpret_cast(cmd); michael@0: uuid_bytes = ucmd->uuid; michael@0: } michael@0: michael@0: cmd = reinterpret_cast michael@0: (reinterpret_cast(cmd) + cmd->cmdsize); michael@0: } michael@0: michael@0: std::stringstream uuid; michael@0: uuid << std::hex << std::uppercase; michael@0: if (uuid_bytes != nullptr) { michael@0: for (int i = 0; i < 16; ++i) { michael@0: uuid << ((uuid_bytes[i] & 0xf0) >> 4); michael@0: uuid << (uuid_bytes[i] & 0xf); michael@0: } michael@0: uuid << '0'; michael@0: } michael@0: michael@0: info.AddSharedLibrary(SharedLibrary(start, start + size, 0, uuid.str(), michael@0: name)); michael@0: } michael@0: michael@0: // Use dyld to inspect the macho image information. We can build the SharedLibraryEntry structure michael@0: // giving us roughtly the same info as /proc/PID/maps in Linux. michael@0: SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() michael@0: { michael@0: SharedLibraryInfo sharedLibraryInfo; michael@0: michael@0: task_dyld_info_data_t task_dyld_info; michael@0: mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; michael@0: if (task_info(mach_task_self (), TASK_DYLD_INFO, (task_info_t)&task_dyld_info, michael@0: &count) != KERN_SUCCESS) { michael@0: return sharedLibraryInfo; michael@0: } michael@0: michael@0: struct dyld_all_image_infos* aii = (struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr; michael@0: size_t infoCount = aii->infoArrayCount; michael@0: michael@0: // Iterate through all dyld images (loaded libraries) to get their names michael@0: // and offests. michael@0: for (size_t i = 0; i < infoCount; ++i) { michael@0: const dyld_image_info *info = &aii->infoArray[i]; michael@0: michael@0: // If the magic number doesn't match then go no further michael@0: // since we're not pointing to where we think we are. michael@0: if (info->imageLoadAddress->magic != MACHO_MAGIC_NUMBER) { michael@0: continue; michael@0: } michael@0: michael@0: const platform_mach_header* header = michael@0: reinterpret_cast(info->imageLoadAddress); michael@0: michael@0: // Add the entry for this image. michael@0: addSharedLibrary(header, (char*)info->imageFilePath, sharedLibraryInfo); michael@0: michael@0: } michael@0: return sharedLibraryInfo; michael@0: } michael@0: