- return NULL;
-
- // read all_image_infos struct
- dyld_all_image_infos_64 allImageInfo64;
- mach_vm_size_t readSize = task_dyld_info.all_image_info_size;
- if ( kern_return_t r = mach_vm_read_overwrite(task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size, (vm_address_t)&allImageInfo64, &readSize) ) {
- if ( kr != NULL )
- *kr = r;
- return NULL;
- }
- if ( allImageInfo64.infoArrayCount == 0 ) {
- // could be task was launch suspended or still launching, wait a moment to see
- usleep(1000 * 50); // 50ms
- if ( kern_return_t r = mach_vm_read_overwrite(task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size, (vm_address_t)&allImageInfo64, &readSize) ) {
- if ( kr != NULL )
- *kr = r;
- return NULL;
- }
- // if infoArrayCount is still zero, then target was most likely launched suspended
- if ( allImageInfo64.infoArrayCount == 0 )
- return dyld_process_info_base::makeSuspended(task, kr);
- }
-
- // bail out of dyld is too old
- if ( allImageInfo64.version < 15 ) {
- if ( kr != NULL )
- *kr = KERN_INVALID_HOST;
- return NULL;
- }
-
- // normalize by expanding 32-bit all_image_infos into 64-bit one
- uint32_t imageCount = allImageInfo64.infoArrayCount;
- size_t imageArraySize = imageCount * sizeof(dyld_image_info_64);
- if ( task_dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32 ) {
- const dyld_all_image_infos_32* allImageInfo32 = (dyld_all_image_infos_32*)&allImageInfo64;
- dyld_all_image_infos_64 info64;
- bzero(&info64, sizeof(info64));
- info64.version = allImageInfo32->version;
- info64.infoArrayCount = allImageInfo32->infoArrayCount;
- info64.infoArray = allImageInfo32->infoArray;
- info64.processDetachedFromSharedRegion = allImageInfo32->processDetachedFromSharedRegion;
- info64.libSystemInitialized = allImageInfo32->libSystemInitialized;
- info64.dyldImageLoadAddress = allImageInfo32->dyldImageLoadAddress;
- info64.initialImageCount = allImageInfo32->initialImageCount;
- info64.uuidArrayCount = allImageInfo32->uuidArrayCount;
- info64.uuidArray = allImageInfo32->uuidArray;
- info64.dyldAllImageInfosAddress = allImageInfo32->dyldAllImageInfosAddress;
- info64.sharedCacheSlide = allImageInfo32->sharedCacheSlide;
- info64.infoArrayChangeTimestamp = allImageInfo32->infoArrayChangeTimestamp;
- info64.sharedCacheBaseAddress = allImageInfo32->sharedCacheBaseAddress;
- info64.dyldPath = allImageInfo32->dyldPath;
- memcpy((void*)(info64.sharedCacheUUID), (void*)(allImageInfo32->sharedCacheUUID), 16);
- allImageInfo64 = info64;
- imageCount = allImageInfo64.infoArrayCount;
- imageArraySize = imageCount * sizeof(dyld_image_info_32);
- }
-
- // don't do any (more) work if target process's dyld timestamp has not changed since previous query
- if ( (timestamp != 0) && (timestamp == allImageInfo64.infoArrayChangeTimestamp) ) {
- if ( kr != NULL )
- *kr = KERN_SUCCESS;
- return NULL;
- }
-
- // For the moment we are going to truncate any image list longer than 8192 because some programs do
- // terrible things that corrupt their own image lists and we need to stop clients from crashing
- // reading them. We can try to do something more advanced in the future. rdar://27446361
- imageCount = MIN(imageCount, 8192);
-
- // read image array
- if ( allImageInfo64.infoArray == 0 ) {
- // dyld is in middle of updating image list, try again
- return NULL;
- }
- dyld_image_info_64 imageArray64[imageCount];
- if ( kern_return_t r = mach_vm_read_overwrite(task, allImageInfo64.infoArray, imageArraySize, (vm_address_t)&imageArray64, &readSize) ) {
- // if image array moved, try whole thing again
- if ( kr != NULL ) {
- *kr = r;
- }
- return NULL;
- }
- // normalize by expanding 32-bit image_infos into 64-bit ones
- if ( task_dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32 ) {
- const dyld_image_info_32* imageArray32 = (dyld_image_info_32*)&imageArray64;
- dyld_image_info_64 tempArray[imageCount];
- for (uint32_t i=0; i < imageCount; ++i) {
- tempArray[i].imageLoadAddress = imageArray32[i].imageLoadAddress;
- tempArray[i].imageFilePath = imageArray32[i].imageFilePath;
- tempArray[i].imageFileModDate = imageArray32[i].imageFileModDate;
- }
- memcpy(imageArray64, tempArray, sizeof(dyld_image_info_64)*imageCount);
- }
-
- // create object based on local copy of all image infos and image array
- dyld_process_info result = dyld_process_info_base::make(task, allImageInfo64, imageArray64, kr);
-
- // verify nothing has changed by re-reading all_image_infos struct and checking timestamp
- if ( result != NULL ) {
- dyld_all_image_infos_64 allImageInfo64again;
- readSize = task_dyld_info.all_image_info_size;
- if ( kern_return_t r = mach_vm_read_overwrite(task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size, (vm_address_t)&allImageInfo64again, &readSize) ) {
- if ( kr != NULL )
- *kr = r;
- free((void*)result);
- return NULL;
- }
- uint64_t doneTimeStamp = allImageInfo64again.infoArrayChangeTimestamp;
- if ( task_dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32 ) {
- const dyld_all_image_infos_32* allImageInfo32 = (dyld_all_image_infos_32*)&allImageInfo64again;
- doneTimeStamp = allImageInfo32->infoArrayChangeTimestamp;
+ return nullptr;
+
+ // We use a true shared memory buffer here, that way by making sure that libdyld in both processes
+ // reads and writes the the timestamp atomically we can make sure we get a coherent view of the
+ // remote process.
+ // That also means that we *MUST* directly read the memory, which is why we template the make() call
+ withRemoteBuffer(task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size, true, false, kr, ^(void *buffer, size_t size) {
+ dyld_process_info_ptr base;
+ if (task_dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32 ) {
+ const dyld_all_image_infos_32* info = (const dyld_all_image_infos_32*)buffer;
+ base = dyld_process_info_base::make<dyld_all_image_infos_32, dyld_image_info_32>(task, *info, timestamp, kr);
+ } else {
+ const dyld_all_image_infos_64* info = (const dyld_all_image_infos_64*)buffer;
+ base = dyld_process_info_base::make<dyld_all_image_infos_64, dyld_image_info_64>(task, *info, timestamp, kr);