- unsigned entriesSize = (unsigned)imageInfos.count()*sizeof(dyld_process_info_image_entry);
- unsigned pathsSize = 0;
- for (uintptr_t i=0; i < imageInfos.count(); ++i) {
- launch_cache::Image image(imageInfos[i].imageData);
- pathsSize += (strlen(image.path()) + 1);
- }
- unsigned totalSize = (sizeof(dyld_process_info_notify_header) + MAX_TRAILER_SIZE + entriesSize + pathsSize + 127) & -128; // align
- if ( totalSize > DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE ) {
- // Putting all image paths into one message would make buffer too big.
- // Instead split into two messages. Recurse as needed until paths fit in buffer.
- unsigned imageHalfCount = (unsigned)imageInfos.count()/2;
- const launch_cache::DynArray<loader::ImageInfo> firstHalf(imageHalfCount, (loader::ImageInfo*)&imageInfos[0]);
- const launch_cache::DynArray<loader::ImageInfo> secondHalf(imageInfos.count() - imageHalfCount, (loader::ImageInfo*)&imageInfos[imageHalfCount]);
- notifyMonitoringDyld(unloading, portSlot, firstHalf);
- notifyMonitoringDyld(unloading, portSlot, secondHalf);
- return;
- }
- // build buffer to send
- dyld_all_image_infos* allImageInfo = gAllImages.oldAllImageInfo();
- uint8_t buffer[totalSize];
- dyld_process_info_notify_header* header = (dyld_process_info_notify_header*)buffer;
- header->version = 1;
- header->imageCount = (uint32_t)imageInfos.count();
- header->imagesOffset = sizeof(dyld_process_info_notify_header);
- header->stringsOffset = sizeof(dyld_process_info_notify_header) + entriesSize;
- header->timestamp = allImageInfo->infoArrayChangeTimestamp;
- dyld_process_info_image_entry* entries = (dyld_process_info_image_entry*)&buffer[header->imagesOffset];
- char* const pathPoolStart = (char*)&buffer[header->stringsOffset];
- char* pathPool = pathPoolStart;
- for (uintptr_t i=0; i < imageInfos.count(); ++i) {
- launch_cache::Image image(imageInfos[i].imageData);
- strcpy(pathPool, image.path());
- uint32_t len = (uint32_t)strlen(pathPool);
- memcpy(entries->uuid, image.uuid(), sizeof(uuid_t));
- entries->loadAddress = (uint64_t)imageInfos[i].loadAddress;
- entries->pathStringOffset = (uint32_t)(pathPool - pathPoolStart);
- entries->pathLength = len;
- pathPool += (len +1);
- ++entries;
- }
- // lazily alloc reply port
- if ( sNotifyReplyPorts[portSlot] == 0 ) {
- if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sNotifyReplyPorts[portSlot]) )
- mach_port_insert_right(mach_task_self(), sNotifyReplyPorts[portSlot], sNotifyReplyPorts[portSlot], MACH_MSG_TYPE_MAKE_SEND);
- //log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]);
- }
- //log("found port to send to\n");
- mach_msg_header_t* h = (mach_msg_header_t*)buffer;
- h->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND); // MACH_MSG_TYPE_MAKE_SEND_ONCE
- h->msgh_id = unloading ? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID : DYLD_PROCESS_INFO_NOTIFY_LOAD_ID;
- h->msgh_local_port = sNotifyReplyPorts[portSlot];
- h->msgh_remote_port = allImageInfo->notifyPorts[portSlot];
- h->msgh_reserved = 0;
- h->msgh_size = (mach_msg_size_t)sizeof(buffer);
- //log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", portSlot, allImageInfo->notifyPorts[portSlot], h->msgh_size, sNotifyReplyPorts[portSlot], h->msgh_id);
- kern_return_t sendResult = mach_msg(h, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_TIMEOUT, h->msgh_size, h->msgh_size, sNotifyReplyPorts[portSlot], 2000, MACH_PORT_NULL);
- //log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
- if ( sendResult == MACH_SEND_INVALID_DEST ) {
- // sender is not responding, detatch
- //log("process requesting notification gone. deallocation send port %d and receive port %d\n", allImageInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]);
- mach_port_deallocate(mach_task_self(), allImageInfo->notifyPorts[portSlot]);
- mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[portSlot]);
- allImageInfo->notifyPorts[portSlot] = 0;
- sNotifyReplyPorts[portSlot] = 0;
- }
- else if ( sendResult == MACH_RCV_TIMED_OUT ) {
- // client took too long, ignore him from now on
- sZombieNotifiers[portSlot] = true;
- mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[portSlot]);
- sNotifyReplyPorts[portSlot] = 0;
- }