如何在运行时获得构buildUUID和图像基地址

有没有得到构build的UUID,你可以检查在dSYM生成的文件和iOS的图像基地址。

低级别的东西不太好,任何人都可以启发?

这是一个类似Kerni的答案,但适用于任何平台(iOS设备+模拟器和OS X)和任何体系结构(32位+ 64位)的解决scheme。 它也返回一个NSUUID而不是一个NSString

 #import <mach-o/dyld.h> #import <mach-o/loader.h> static NSUUID *ExecutableUUID(void) { const struct mach_header *executableHeader = NULL; for (uint32_t i = 0; i < _dyld_image_count(); i++) { const struct mach_header *header = _dyld_get_image_header(i); if (header->filetype == MH_EXECUTE) { executableHeader = header; break; } } if (!executableHeader) return nil; BOOL is64bit = executableHeader->magic == MH_MAGIC_64 || executableHeader->magic == MH_CIGAM_64; uintptr_t cursor = (uintptr_t)executableHeader + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); const struct segment_command *segmentCommand = NULL; for (uint32_t i = 0; i < executableHeader->ncmds; i++, cursor += segmentCommand->cmdsize) { segmentCommand = (struct segment_command *)cursor; if (segmentCommand->cmd == LC_UUID) { const struct uuid_command *uuidCommand = (const struct uuid_command *)segmentCommand; return [[NSUUID alloc] initWithUUIDBytes:uuidCommand->uuid]; } } return nil; } 

你自己的build议太复杂了。

从HockeySDK中检查这个代码,只需要几行代码: https : //github.com/bitstadium/HockeySDK-iOS/blob/develop/Classes/BITHockeyBaseManager.m#L136

 - (NSString *)executableUUID { // This now requires the testing of this feature to be done on an actual device, since it returns always empty strings on the simulator #if !TARGET_IPHONE_SIMULATOR const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1); for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) { const struct load_command *load_command = (const struct load_command *)command; if (load_command->cmd == LC_UUID) { const struct uuid_command *uuid_command = (const struct uuid_command *)command; const uint8_t *uuid = uuid_command->uuid; return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]] lowercaseString]; } else { command += load_command->cmdsize; } } #endif return @""; } 

这可以通过我从一些同事那里发现的一个类别来实现,他们在合理的实验室中发现了这些类别,并且根据他们的需要进行了重构。

在这里你可以得到构buildUUID的图像基地址和应用程序名称。

  /** * @internal * * Async-safe binary image list element. */ typedef struct bin_image { /** The binary image's header address. */ uintptr_t header; /** The binary image's name/path. */ char *name; /** The previous image in the list, or NULL */ struct bin_image *prev; /** The next image in the list, or NULL. */ struct bin_image *next; } bin_image_t; /** * @internal * * Async-safe binary image list. May be used to iterate over the binary images currently * available in-process. */ typedef struct bs_image_list { /** The lock used by writers. No lock is required for readers. */ OSSpinLock write_lock; /** The head of the list, or NULL if the list is empty. Must only be used to iterate or delete entries. */ bin_image_t *head; /** The tail of the list, or NULL if the list is empty. Must only be used to append new entries. */ bin_image_t *tail; /** The list reference count. No nodes will be deallocated while the count is greater than 0. If the count * reaches 0, all nodes in the free list will be deallocated. */ int32_t refcount; /** The node free list. */ bin_image_t *free; } bs_image_list_t; /** * @internal * * Shared dyld image list. */ static bs_image_list_t shared_image_list = { 0 }; /** * @internal * * Maintains a linked list of binary images with support for async-safe iteration. Writing may occur concurrently with * async-safe reading, but is not async-safe. * * Atomic compare and swap is used to ensure a consistent view of the list for readers. To simplify implementation, a * write mutex is held for all updates; the implementation is not designed for efficiency in the face of contention * between readers and writers, and it's assumed that no contention should realistically occur. * @{ */ /** * Initialize a new binary image list and issue a memory barrier * * @param list The list structure to be initialized. * * @warning This method is not async safe. */ static void image_list_init (bs_image_list_t *list) { memset(list, 0, sizeof(*list)); list->write_lock = OS_SPINLOCK_INIT; } /** * Free any binary image list resources. * * @warning This method is not async safe. */ static void image_list_free (bs_image_list_t *list) { bin_image_t *next = list->head; while (next != NULL) { /* Save the current pointer and fetch the next pointer. */ bin_image_t *cur = next; next = cur->next; /* Deallocate the current item. */ if (cur->name != NULL) free(cur->name); free(cur); } } /** * Append a new binary image record to @a list. * * @param list The list to which the image record should be appended. * @param header The image's header address. * @param name The image's name. * * @warning This method is not async safe. */ static void image_list_append (bs_image_list_t *list, uintptr_t header, const char *name) { /* Initialize the new entry. */ bin_image_t *new = calloc(1, sizeof(bin_image_t)); new->header = header; new->name = strdup(name); /* Update the image record and issue a memory barrier to ensure a consistent view. */ OSMemoryBarrier(); /* Lock the list from other writers. */ OSSpinLockLock(&list->write_lock); { /* If this is the first entry, initialize the list. */ if (list->tail == NULL) { /* Update the list tail. This need not be done atomically, as tail is never accessed by a lockless reader. */ list->tail = new; /* Atomically update the list head; this will be iterated upon by lockless readers. */ if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new, (void **) (&list->head))) { /* Should never occur */ NSLog(@"An async image head was set with tail == NULL despite holding lock."); } } /* Otherwise, append to the end of the list */ else { /* Atomically slot the new record into place; this may be iterated on by a lockless reader. */ if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new, (void **) (&list->tail->next))) { NSLog(@"Failed to append to image list despite holding lock"); } /* Update the prev and tail pointers. This is never accessed without a lock, so no additional barrier * is required here. */ new->prev = list->tail; list->tail = new; } } OSSpinLockUnlock(&list->write_lock); } /** * Remove a binary image record from @a list. * * @param header The header address of the record to be removed. The first record matching this address will be removed. * * @warning This method is not async safe. */ static void image_list_remove (bs_image_list_t *list, uintptr_t header) { /* Lock the list from other writers. */ OSSpinLockLock(&list->write_lock); { /* Find the record. */ bin_image_t *item = list->head; while (item != NULL) { if (item->header == header) break; item = item->next; } /* If not found, nothing to do */ if (item == NULL) { OSSpinLockUnlock(&list->write_lock); return; } /* * Atomically make the item unreachable by readers. * * This serves as a synchronization point -- after the CAS, the item is no longer reachable via the list. */ if (item == list->head) { if (!OSAtomicCompareAndSwapPtrBarrier(item, item->next, (void **) &list->head)) { NSLog(@"Failed to remove image list head despite holding lock"); } } else { /* There MUST be a non-NULL prev pointer, as this is not HEAD. */ if (!OSAtomicCompareAndSwapPtrBarrier(item, item->next, (void **) &item->prev->next)) { NSLog(@"Failed to remove image list item despite holding lock"); } } /* Now that the item is unreachable, update the prev/tail pointers. These are never accessed without a lock, * and need not be updated atomically. */ if (item->next != NULL) { /* Item is not the tail (otherwise next would be NULL), so simply update the next item's prev pointer. */ item->next->prev = item->prev; } else { /* Item is the tail (next is NULL). Simply update the tail record. */ list->tail = item->prev; } /* If a reader is active, simply spin until inactive. */ while (list->refcount > 0) { } if (item->name != NULL) free(item->name); free(item); } OSSpinLockUnlock(&list->write_lock); } /** * Retain or release the list for reading. This method is async-safe. * * This must be issued prior to attempting to iterate the list, and must called again once reads have completed. * * @param list The list to be be retained or released for reading. * @param enable If true, the list will be retained. If false, released. */ static void image_list_set_reading (bs_image_list_t *list, bool enable) { if (enable) { /* Increment and issue a barrier. Once issued, no items will be deallocated while a reference is held. */ OSAtomicIncrement32Barrier(&list->refcount); } else { /* Increment and issue a barrier. Once issued, items may again be deallocated. */ OSAtomicDecrement32Barrier(&list->refcount); } } /** * Return the next image record. This method is async-safe. If no additional images are available, will return NULL; * * @param list The list to be iterated. * @param current The current image record, or NULL to start iteration. */ static bin_image_t *image_list_next (bs_image_list_t *list, bin_image_t *current) { if (current != NULL) return current->next; return list->head; } /** * @internal * dyld image add notification callback. */ static void image_add_callback (const struct mach_header *mh, intptr_t vmaddr_slide) { Dl_info info; /* Look up the image info */ if (dladdr(mh, &info) == 0) { NSLog(@"%s: dladdr(%p, ...) failed", __FUNCTION__, mh); return; } /* Register the image */ image_list_append(&shared_image_list, (uintptr_t) mh, info.dli_fname); } /** * @internal * * Write a binary image frame * * @param file Output file * @param name binary image path (or name). * @param image_base Mach-O image base. */ static void process_binary_image (const char *name, const void *header, struct uuid_command *out_uuid, uintptr_t *out_baseaddr) { uint32_t ncmds; const struct mach_header *header32 = (const struct mach_header *) header; const struct mach_header_64 *header64 = (const struct mach_header_64 *) header; struct load_command *cmd; /* Check for 32-bit/64-bit header and extract required values */ switch (header32->magic) { /* 32-bit */ case MH_MAGIC: case MH_CIGAM: ncmds = header32->ncmds; cmd = (struct load_command *) (header32 + 1); break; /* 64-bit */ case MH_MAGIC_64: case MH_CIGAM_64: ncmds = header64->ncmds; cmd = (struct load_command *) (header64 + 1); break; default: NSLog(@"Invalid Mach-O header magic value: %x", header32->magic); return; } /* Compute the image size and search for a UUID */ struct uuid_command *uuid = NULL; for (uint32_t i = 0; cmd != NULL && i < ncmds; i++) { /* DWARF dSYM UUID */ if (cmd->cmd == LC_UUID && cmd->cmdsize == sizeof(struct uuid_command)) uuid = (struct uuid_command *) cmd; cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize); } /* Base address */ uintptr_t base_addr; base_addr = (uintptr_t) header; *out_baseaddr = base_addr; if(out_uuid && uuid) memcpy(out_uuid, uuid, sizeof(struct uuid_command)); } + (void)registerCallback { _dyld_register_func_for_add_image(image_add_callback); } + (NSArray *)loadedImages { NSMutableArray *array = [NSMutableArray array]; int i; struct uuid_command uuid = { 0 }; uintptr_t baseaddr; char uuidstr[64] = { 0 }; image_list_set_reading(&shared_image_list, true); bin_image_t *image = NULL; while ((image = image_list_next(&shared_image_list, image)) != NULL) { process_binary_image(image->name, (const void *) (image->header), &uuid, &baseaddr); for(i=0; i<16; i++) { sprintf(&uuidstr[2*i], "%02x", uuid.uuid[i]); } [array addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSString stringWithCString:image->name encoding:NSASCIIStringEncoding], [NSString stringWithCString:uuidstr encoding:NSASCIIStringEncoding], [NSNumber numberWithUnsignedLong:(long unsigned) baseaddr], nil] forKeys:[NSArray arrayWithObjects:@"name", @"uuid", @"baseaddr", nil]]]; } return [NSArray arrayWithArray:array]; } 

您必须在某处调用registerCallbacks ,以便它可以正确地返回结果。

问候。