1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
30 #include <sys/param.h>
31 #include <mach/shared_region.h>
32 #include <mach/mach_vm.h>
33 #include <mach/vm_region.h>
34 #include <libkern/OSAtomic.h>
36 #include "dyld_process_info.h"
37 #include "dyld_process_info_internal.h"
38 #include "dyld_images.h"
39 #include "dyld_priv.h"
43 // Opaque object returned by _dyld_process_info_create()
46 struct __attribute__((visibility("hidden"))) dyld_process_info_base
{
47 static dyld_process_info_base
* make(task_t task
, const dyld_all_image_infos_64
& allImageInfo
, const dyld_image_info_64 imageArray
[], kern_return_t
* kr
);
48 static dyld_process_info_base
* makeSuspended(task_t task
, kern_return_t
* kr
);
50 uint32_t& retainCount() const { return _retainCount
; }
51 dyld_process_cache_info
* cacheInfo() const { return (dyld_process_cache_info
*)(((char*)this) + _cacheInfoOffset
); }
52 dyld_process_state_info
* stateInfo() const { return (dyld_process_state_info
*)(((char*)this) + _stateInfoOffset
); }
53 void forEachImage(void (^callback
)(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
)) const;
54 void forEachSegment(uint64_t machHeaderAddress
, void (^callback
)(uint64_t segmentAddress
, uint64_t segmentSize
, const char* segmentName
)) const;
61 uint32_t segmentStartIndex
;
62 uint32_t segmentsCount
;
71 dyld_process_info_base(unsigned imageCount
, size_t totalSize
);
72 void* operator new (size_t, void* buf
) { return buf
; }
74 static bool inCache(uint64_t addr
) { return (addr
> SHARED_REGION_BASE
) && (addr
< SHARED_REGION_BASE
+SHARED_REGION_SIZE
); }
75 kern_return_t
addImage(task_t task
, bool sameCacheAsThisProcess
, uint64_t imageAddress
, uint64_t imagePath
, const char* imagePathLocal
);
76 kern_return_t
addDyldImage(task_t task
, uint64_t dyldAddress
, uint64_t dyldPathAddress
, const char* localPath
);
78 bool invalid() { return ((char*)_stringRevBumpPtr
< (char*)_curSegment
); }
79 const char* copyPath(task_t task
, uint64_t pathAddr
, kern_return_t
* kr
);
80 const char* addString(const char*);
81 const char* copySegmentName(const char*);
83 void addInfoFromLoadCommands(const mach_header
* mh
, uint64_t addressInTask
, size_t size
);
85 void inspectLocalImageLoadCommands(uint64_t imageAddress
, void* func
);
86 kern_return_t
inspectRemoteImageLoadCommands(task_t task
, uint64_t imageAddress
, void* func
);
88 mutable uint32_t _retainCount
;
89 const uint32_t _cacheInfoOffset
;
90 const uint32_t _stateInfoOffset
;
91 const uint32_t _imageInfosOffset
;
92 const uint32_t _segmentInfosOffset
;
93 ImageInfo
* const _firstImage
;
95 SegmentInfo
* const _firstSegment
;
96 SegmentInfo
* _curSegment
;
97 uint32_t _curSegmentIndex
;
98 char* _stringRevBumpPtr
;
100 // dyld_process_cache_info cacheInfo;
101 // dyld_process_state_info stateInfo;
102 // ImageInfo images[];
103 // SegmentInfo segments[];
107 dyld_process_info_base::dyld_process_info_base(unsigned imageCount
, size_t totalSize
)
108 : _retainCount(1), _cacheInfoOffset(sizeof(dyld_process_info_base
)),
109 _stateInfoOffset(sizeof(dyld_process_info_base
) + sizeof(dyld_process_cache_info
)),
110 _imageInfosOffset(sizeof(dyld_process_info_base
) + sizeof(dyld_process_cache_info
) + sizeof(dyld_process_state_info
)),
111 _segmentInfosOffset(sizeof(dyld_process_info_base
) + sizeof(dyld_process_cache_info
) + sizeof(dyld_process_state_info
) + imageCount
*sizeof(ImageInfo
)),
112 _firstImage((ImageInfo
*)(((uint8_t*)this) + _imageInfosOffset
)),
113 _curImage((ImageInfo
*)(((uint8_t*)this) + _imageInfosOffset
)),
114 _firstSegment((SegmentInfo
*)(((uint8_t*)this) + _segmentInfosOffset
)),
115 _curSegment((SegmentInfo
*)(((uint8_t*)this) + _segmentInfosOffset
)),
117 _stringRevBumpPtr((char*)(this)+totalSize
)
122 dyld_process_info_base
* dyld_process_info_base::make(task_t task
, const dyld_all_image_infos_64
& allImageInfo
, const dyld_image_info_64 imageArray
[], kern_return_t
* kr
)
124 // figure out how many path strings will need to be copied and their size
125 const dyld_all_image_infos
* myInfo
= _dyld_get_all_image_infos();
126 bool sameCacheAsThisProcess
= ((memcmp(myInfo
->sharedCacheUUID
, allImageInfo
.sharedCacheUUID
, 16) == 0) && (myInfo
->sharedCacheSlide
== allImageInfo
.sharedCacheSlide
));
127 unsigned countOfPathsNeedingCopying
= 0;
128 if ( sameCacheAsThisProcess
) {
129 for (int i
=0; i
< allImageInfo
.infoArrayCount
; ++i
) {
130 if ( !inCache(imageArray
[i
].imageFilePath
) )
131 ++countOfPathsNeedingCopying
;
135 countOfPathsNeedingCopying
= allImageInfo
.infoArrayCount
+1;
137 unsigned imageCountWithDyld
= allImageInfo
.infoArrayCount
+1;
139 // allocate result object
140 size_t allocationSize
= sizeof(dyld_process_info_base
)
141 + sizeof(dyld_process_cache_info
)
142 + sizeof(dyld_process_state_info
)
143 + sizeof(ImageInfo
)*(imageCountWithDyld
)
144 + sizeof(SegmentInfo
)*imageCountWithDyld
*5
145 + countOfPathsNeedingCopying
*PATH_MAX
;
146 void* storage
= malloc(allocationSize
);
147 dyld_process_info_base
* obj
= new (storage
) dyld_process_info_base(imageCountWithDyld
, allocationSize
); // placement new()
150 dyld_process_cache_info
* cacheInfo
= obj
->cacheInfo();
151 memcpy(cacheInfo
->cacheUUID
, allImageInfo
.sharedCacheUUID
, 16);
152 cacheInfo
->cacheBaseAddress
= allImageInfo
.sharedCacheBaseAddress
;
153 cacheInfo
->privateCache
= allImageInfo
.processDetachedFromSharedRegion
;
154 // if no cache is used, allImageInfo has all zeros for cache UUID
155 cacheInfo
->noCache
= true;
156 for (int i
=0; i
< 16; ++i
) {
157 if ( cacheInfo
->cacheUUID
[i
] != 0 ) {
158 cacheInfo
->noCache
= false;
162 dyld_process_state_info
* stateInfo
= obj
->stateInfo();
163 stateInfo
->timestamp
= allImageInfo
.infoArrayChangeTimestamp
;
164 stateInfo
->imageCount
= imageCountWithDyld
;
165 stateInfo
->initialImageCount
= (uint32_t)(allImageInfo
.initialImageCount
+1);
166 if ( allImageInfo
.infoArray
!= 0 )
167 stateInfo
->dyldState
= dyld_process_state_dyld_initialized
;
168 if ( allImageInfo
.libSystemInitialized
!= 0 ) {
169 stateInfo
->dyldState
= dyld_process_state_libSystem_initialized
;
170 if ( allImageInfo
.initialImageCount
!= allImageInfo
.infoArrayCount
)
171 stateInfo
->dyldState
= dyld_process_state_program_running
;
173 if ( allImageInfo
.errorMessage
!= 0 )
174 stateInfo
->dyldState
= allImageInfo
.terminationFlags
? dyld_process_state_terminated_before_inits
: dyld_process_state_dyld_terminated
;
176 // fill in info for dyld
177 if ( allImageInfo
.dyldPath
!= 0 ) {
178 if ( kern_return_t r
= obj
->addDyldImage(task
, allImageInfo
.dyldImageLoadAddress
, allImageInfo
.dyldPath
, NULL
) ) {
185 // fill in info for each image
186 for (uint32_t i
=0; i
< allImageInfo
.infoArrayCount
; ++i
) {
187 if ( kern_return_t r
= obj
->addImage(task
, sameCacheAsThisProcess
, imageArray
[i
].imageLoadAddress
, imageArray
[i
].imageFilePath
, NULL
) ) {
194 // sanity check internal data did not overflow
195 if ( obj
->invalid() )
205 dyld_process_info_base
* dyld_process_info_base::makeSuspended(task_t task
, kern_return_t
* kr
)
208 kern_return_t result
= pid_for_task(task
, &pid
);
209 if ( result
!= KERN_SUCCESS
) {
215 unsigned imageCount
= 0; // main executable and dyld
216 uint64_t mainExecutableAddress
= 0;
217 uint64_t dyldAddress
= 0;
218 char dyldPathBuffer
[PATH_MAX
+1];
219 char mainExecutablePathBuffer
[PATH_MAX
+1];
221 for (mach_vm_address_t address
= 0; ; address
+= size
) {
222 vm_region_basic_info_data_64_t info
;
223 mach_port_t objectName
;
224 unsigned int infoCount
= VM_REGION_BASIC_INFO_COUNT_64
;
225 result
= mach_vm_region(task
, &address
, &size
, VM_REGION_BASIC_INFO
,
226 (vm_region_info_t
)&info
, &infoCount
, &objectName
);
227 if ( result
!= KERN_SUCCESS
)
229 if ( info
.protection
== (VM_PROT_READ
|VM_PROT_EXECUTE
) ) {
230 if ( mainExecutableAddress
== 0 ) {
231 mainExecutableAddress
= address
;
232 int len
= proc_regionfilename(pid
, mainExecutableAddress
, mainExecutablePathBuffer
, PATH_MAX
);
234 mainExecutablePathBuffer
[len
] = '\0';
237 else if ( dyldAddress
== 0 ) {
238 dyldAddress
= address
;
239 int len
= proc_regionfilename(pid
, dyldAddress
, dyldPathBuffer
, PATH_MAX
);
241 dyldPathBuffer
[len
] = '\0';
244 //fprintf(stderr, "vm region: addr=0x%llX, size=0x%llX, prot=0x%X\n", (uint64_t)address, (uint64_t)size, info.protection);
247 //fprintf(stderr, "dyld: addr=0x%llX, path=%s\n", dyldAddress, dyldPathBuffer);
248 //fprintf(stderr, "app: addr=0x%llX, path=%s\n", mainExecutableAddress, mainExecutablePathBuffer);
250 // allocate result object
251 size_t allocationSize
= sizeof(dyld_process_info_base
)
252 + sizeof(dyld_process_cache_info
)
253 + sizeof(dyld_process_state_info
)
254 + sizeof(ImageInfo
)*(imageCount
)
255 + sizeof(SegmentInfo
)*imageCount
*5
256 + imageCount
*PATH_MAX
;
257 void* storage
= malloc(allocationSize
);
258 dyld_process_info_base
* obj
= new (storage
) dyld_process_info_base(imageCount
, allocationSize
); // placement new()
261 dyld_process_cache_info
* cacheInfo
= obj
->cacheInfo();
262 bzero(cacheInfo
->cacheUUID
, 16);
263 cacheInfo
->cacheBaseAddress
= 0;
264 cacheInfo
->noCache
= true;
265 cacheInfo
->privateCache
= false;
267 dyld_process_state_info
* stateInfo
= obj
->stateInfo();
268 stateInfo
->timestamp
= 0;
269 stateInfo
->imageCount
= imageCount
;
270 stateInfo
->initialImageCount
= imageCount
;
271 stateInfo
->dyldState
= dyld_process_state_not_started
;
273 // fill in info for dyld
274 if ( dyldAddress
!= 0 ) {
275 if ( kern_return_t r
= obj
->addDyldImage(task
, dyldAddress
, 0, dyldPathBuffer
) ) {
283 // fill in info for each image
284 if ( mainExecutableAddress
!= 0 ) {
285 if ( kern_return_t r
= obj
->addImage(task
, false, mainExecutableAddress
, 0, mainExecutablePathBuffer
) ) {
298 const char* dyld_process_info_base::addString(const char* str
)
300 size_t len
= strlen(str
) + 1;
301 _stringRevBumpPtr
-= len
;
302 strcpy(_stringRevBumpPtr
, str
);
303 return _stringRevBumpPtr
;
306 const char* dyld_process_info_base::copyPath(task_t task
, uint64_t stringAddressInTask
, kern_return_t
* kr
)
308 char temp
[PATH_MAX
+8]; // +8 is to allow '\0' at temp[PATH_MAX]
309 mach_vm_size_t readSize
= PATH_MAX
;
310 if ( ((stringAddressInTask
& 0xFFF) + PATH_MAX
) < 4096 ) {
311 // string fits within page, only one vm_read needed
312 if ( kern_return_t r
= mach_vm_read_overwrite(task
, stringAddressInTask
, PATH_MAX
, (vm_address_t
)&temp
, &readSize
) ) {
319 // string may cross page boundary, split into two reads
320 size_t firstLen
= 4096 - (stringAddressInTask
& 0xFFF);
322 if ( kern_return_t r
= mach_vm_read_overwrite(task
, stringAddressInTask
, firstLen
, (vm_address_t
)&temp
, &readSize
) ) {
327 temp
[firstLen
] = '\0';
328 if ( strlen(temp
) >= firstLen
) {
329 readSize
= PATH_MAX
-firstLen
;
330 if ( kern_return_t r
= mach_vm_read_overwrite(task
, stringAddressInTask
+firstLen
, PATH_MAX
-firstLen
, (vm_address_t
)&temp
+firstLen
, &readSize
) ) {
334 temp
[PATH_MAX
] = '\0'; // truncate any string that is too long
340 return addString(temp
);
344 kern_return_t
dyld_process_info_base::addImage(task_t task
, bool sameCacheAsThisProcess
, uint64_t imageAddress
, uint64_t imagePath
, const char* imagePathLocal
)
346 _curImage
->loadAddress
= imageAddress
;
347 _curImage
->segmentStartIndex
= _curSegmentIndex
;
348 if ( imagePathLocal
!= NULL
) {
349 _curImage
->path
= addString(imagePathLocal
);
351 else if ( sameCacheAsThisProcess
&& inCache(imagePath
) ) {
352 _curImage
->path
= (const char*)imagePath
;
356 _curImage
->path
= copyPath(task
, imagePath
, &kr
);
360 if ( sameCacheAsThisProcess
&& inCache(imageAddress
) ) {
361 addInfoFromLoadCommands((mach_header
*)imageAddress
, imageAddress
, 32*1024);
364 mach_vm_size_t readSize
= sizeof(mach_header_64
);
365 mach_header_64 mhBuffer
;
366 if ( kern_return_t r
= mach_vm_read_overwrite(task
, imageAddress
, sizeof(mach_header_64
), (vm_address_t
)&mhBuffer
, &readSize
) ) {
369 size_t headerPagesSize
= (sizeof(mach_header_64
) + mhBuffer
.sizeofcmds
+ 4095) & (-4096);
370 vm_address_t localCopyBuffer
;
371 unsigned int localCopyBufferSize
;
372 if ( kern_return_t r
= mach_vm_read(task
, imageAddress
, headerPagesSize
, &localCopyBuffer
, &localCopyBufferSize
) ) {
375 addInfoFromLoadCommands((mach_header
*)localCopyBuffer
, imageAddress
, localCopyBufferSize
);
376 vm_deallocate(mach_task_self(), localCopyBuffer
, localCopyBufferSize
);
378 _curImage
->segmentsCount
= _curSegmentIndex
- _curImage
->segmentStartIndex
;
384 kern_return_t
dyld_process_info_base::addDyldImage(task_t task
, uint64_t dyldAddress
, uint64_t dyldPathAddress
, const char* localPath
)
387 _curImage
->loadAddress
= dyldAddress
;
388 _curImage
->segmentStartIndex
= _curSegmentIndex
;
389 if ( localPath
!= NULL
) {
390 _curImage
->path
= addString(localPath
);
393 _curImage
->path
= copyPath(task
, dyldPathAddress
, &kr
);
398 mach_vm_size_t readSize
= sizeof(mach_header_64
);
399 mach_header_64 mhBuffer
;
400 if ( kern_return_t r
= mach_vm_read_overwrite(task
, dyldAddress
, sizeof(mach_header_64
), (vm_address_t
)&mhBuffer
, &readSize
) ) {
403 size_t headerPagesSize
= (sizeof(mach_header_64
) + mhBuffer
.sizeofcmds
+ 4095) & (-4096);
404 vm_address_t localCopyBuffer
;
405 unsigned int localCopyBufferSize
;
406 if ( kern_return_t r
= mach_vm_read(task
, dyldAddress
, headerPagesSize
, &localCopyBuffer
, &localCopyBufferSize
) ) {
409 addInfoFromLoadCommands((mach_header
*)localCopyBuffer
, dyldAddress
, localCopyBufferSize
);
410 vm_deallocate(mach_task_self(), localCopyBuffer
, localCopyBufferSize
);
411 _curImage
->segmentsCount
= _curSegmentIndex
- _curImage
->segmentStartIndex
;
417 void dyld_process_info_base::addInfoFromLoadCommands(const mach_header
* mh
, uint64_t addressInTask
, size_t size
)
419 const load_command
* startCmds
= NULL
;
420 if ( mh
->magic
== MH_MAGIC_64
)
421 startCmds
= (load_command
*)((char *)mh
+ sizeof(mach_header_64
));
422 else if ( mh
->magic
== MH_MAGIC
)
423 startCmds
= (load_command
*)((char *)mh
+ sizeof(mach_header
));
425 return; // not a mach-o file, or wrong endianness
427 const load_command
* const cmdsEnd
= (load_command
*)((char*)startCmds
+ mh
->sizeofcmds
);
428 const load_command
* cmd
= startCmds
;
429 for(uint32_t i
= 0; i
< mh
->ncmds
; ++i
) {
430 const load_command
* nextCmd
= (load_command
*)((char *)cmd
+ cmd
->cmdsize
);
431 if ( (cmd
->cmdsize
< 8) || (nextCmd
> cmdsEnd
) || (nextCmd
< startCmds
) ) {
432 return; // malformed load command
434 if ( cmd
->cmd
== LC_UUID
) {
435 const uuid_command
* uuidCmd
= (uuid_command
*)cmd
;
436 memcpy(_curImage
->uuid
, uuidCmd
->uuid
, 16);
438 else if ( cmd
->cmd
== LC_SEGMENT
) {
439 const segment_command
* segCmd
= (segment_command
*)cmd
;
440 _curSegment
->name
= copySegmentName(segCmd
->segname
);
441 _curSegment
->addr
= segCmd
->vmaddr
;
442 _curSegment
->size
= segCmd
->vmsize
;
446 else if ( cmd
->cmd
== LC_SEGMENT_64
) {
447 const segment_command_64
* segCmd
= (segment_command_64
*)cmd
;
448 _curSegment
->name
= copySegmentName(segCmd
->segname
);
449 _curSegment
->addr
= segCmd
->vmaddr
;
450 _curSegment
->size
= segCmd
->vmsize
;
458 const char* dyld_process_info_base::copySegmentName(const char* name
)
460 // don't copy names of standard segments into string pool
461 static const char* stdSegNames
[] = {"__TEXT", "__DATA", "__LINKEDIT", "__DATA_DIRTY", "__DATA_CONST", "__OBJC", NULL
};
462 for (const char** s
=stdSegNames
; *s
!= NULL
; ++s
) {
463 if ( strcmp(name
, *s
) == 0 )
466 // copy custom segment names into string pool
467 return addString(name
);
470 void dyld_process_info_base::forEachImage(void (^callback
)(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
)) const
472 for (const ImageInfo
* p
= _firstImage
; p
< _curImage
; ++p
) {
473 callback(p
->loadAddress
, p
->uuid
, p
->path
);
477 void dyld_process_info_base::forEachSegment(uint64_t machHeaderAddress
, void (^callback
)(uint64_t segmentAddress
, uint64_t segmentSize
, const char* segmentName
)) const
479 for (const ImageInfo
* p
= _firstImage
; p
< _curImage
; ++p
) {
480 if ( p
->loadAddress
== machHeaderAddress
) {
482 for (int i
=0; i
< p
->segmentsCount
; ++i
) {
483 const SegmentInfo
* seg
= &_firstSegment
[p
->segmentStartIndex
+i
];
484 if ( strcmp(seg
->name
, "__TEXT") == 0 ) {
485 slide
= machHeaderAddress
- seg
->addr
;
489 for (int i
=0; i
< p
->segmentsCount
; ++i
) {
490 const SegmentInfo
* seg
= &_firstSegment
[p
->segmentStartIndex
+i
];
491 callback(seg
->addr
+ slide
, seg
->size
, seg
->name
);
502 // Implementation that works with existing dyld data structures
503 dyld_process_info
_dyld_process_info_create(task_t task
, uint64_t timestamp
, kern_return_t
* kr
)
508 task_dyld_info_data_t task_dyld_info
;
509 mach_msg_type_number_t count
= TASK_DYLD_INFO_COUNT
;
510 if ( kern_return_t r
= task_info(task
, TASK_DYLD_INFO
, (task_info_t
)&task_dyld_info
, &count
) ) {
516 //The kernel will return MACH_VM_MIN_ADDRESS for an executable that has not had dyld loaded
517 if (task_dyld_info
.all_image_info_addr
== MACH_VM_MIN_ADDRESS
)
520 if ( task_dyld_info
.all_image_info_size
> sizeof(dyld_all_image_infos_64
) )
523 // read all_image_infos struct
524 dyld_all_image_infos_64 allImageInfo64
;
525 mach_vm_size_t readSize
= task_dyld_info
.all_image_info_size
;
526 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
) ) {
531 if ( allImageInfo64
.infoArrayCount
== 0 ) {
532 // could be task was launch suspended or still launching, wait a moment to see
533 usleep(1000 * 50); // 50ms
534 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
) ) {
539 // if infoArrayCount is still zero, then target was most likely launched suspended
540 if ( allImageInfo64
.infoArrayCount
== 0 )
541 return dyld_process_info_base::makeSuspended(task
, kr
);
544 // bail out of dyld is too old
545 if ( allImageInfo64
.version
< 15 ) {
547 *kr
= KERN_INVALID_HOST
;
551 // normalize by expanding 32-bit all_image_infos into 64-bit one
552 uint32_t imageCount
= allImageInfo64
.infoArrayCount
;
553 size_t imageArraySize
= imageCount
* sizeof(dyld_image_info_64
);
554 if ( task_dyld_info
.all_image_info_format
== TASK_DYLD_ALL_IMAGE_INFO_32
) {
555 const dyld_all_image_infos_32
* allImageInfo32
= (dyld_all_image_infos_32
*)&allImageInfo64
;
556 dyld_all_image_infos_64 info64
;
557 bzero(&info64
, sizeof(info64
));
558 info64
.version
= allImageInfo32
->version
;
559 info64
.infoArrayCount
= allImageInfo32
->infoArrayCount
;
560 info64
.infoArray
= allImageInfo32
->infoArray
;
561 info64
.processDetachedFromSharedRegion
= allImageInfo32
->processDetachedFromSharedRegion
;
562 info64
.libSystemInitialized
= allImageInfo32
->libSystemInitialized
;
563 info64
.dyldImageLoadAddress
= allImageInfo32
->dyldImageLoadAddress
;
564 info64
.initialImageCount
= allImageInfo32
->initialImageCount
;
565 info64
.uuidArrayCount
= allImageInfo32
->uuidArrayCount
;
566 info64
.uuidArray
= allImageInfo32
->uuidArray
;
567 info64
.dyldAllImageInfosAddress
= allImageInfo32
->dyldAllImageInfosAddress
;
568 info64
.sharedCacheSlide
= allImageInfo32
->sharedCacheSlide
;
569 info64
.infoArrayChangeTimestamp
= allImageInfo32
->infoArrayChangeTimestamp
;
570 info64
.sharedCacheBaseAddress
= allImageInfo32
->sharedCacheBaseAddress
;
571 info64
.dyldPath
= allImageInfo32
->dyldPath
;
572 memcpy((void*)(info64
.sharedCacheUUID
), (void*)(allImageInfo32
->sharedCacheUUID
), 16);
573 allImageInfo64
= info64
;
574 imageCount
= allImageInfo64
.infoArrayCount
;
575 imageArraySize
= imageCount
* sizeof(dyld_image_info_32
);
578 // don't do any (more) work if target process's dyld timestamp has not changed since previous query
579 if ( (timestamp
!= 0) && (timestamp
== allImageInfo64
.infoArrayChangeTimestamp
) ) {
585 // For the moment we are going to truncate any image list longer than 8192 because some programs do
586 // terrible things that corrupt their own image lists and we need to stop clients from crashing
587 // reading them. We can try to do something more advanced in the future. rdar://27446361
588 imageCount
= MIN(imageCount
, 8192);
591 dyld_image_info_64 imageArray64
[imageCount
];
592 if ( kern_return_t r
= mach_vm_read_overwrite(task
, allImageInfo64
.infoArray
, imageArraySize
, (vm_address_t
)&imageArray64
, &readSize
) ) {
597 // normalize by expanding 32-bit image_infos into 64-bit ones
598 if ( task_dyld_info
.all_image_info_format
== TASK_DYLD_ALL_IMAGE_INFO_32
) {
599 const dyld_image_info_32
* imageArray32
= (dyld_image_info_32
*)&imageArray64
;
600 dyld_image_info_64 tempArray
[imageCount
];
601 for (uint32_t i
=0; i
< imageCount
; ++i
) {
602 tempArray
[i
].imageLoadAddress
= imageArray32
[i
].imageLoadAddress
;
603 tempArray
[i
].imageFilePath
= imageArray32
[i
].imageFilePath
;
604 tempArray
[i
].imageFileModDate
= imageArray32
[i
].imageFileModDate
;
606 memcpy(imageArray64
, tempArray
, sizeof(dyld_image_info_64
)*imageCount
);
609 // create object based on local copy of all image infos and image array
610 return dyld_process_info_base::make(task
, allImageInfo64
, imageArray64
, kr
);
614 void _dyld_process_info_get_state(dyld_process_info info
, dyld_process_state_info
* stateInfo
)
616 *stateInfo
= *info
->stateInfo();
619 void _dyld_process_info_get_cache(dyld_process_info info
, dyld_process_cache_info
* cacheInfo
)
621 *cacheInfo
= *info
->cacheInfo();
624 void _dyld_process_info_retain(dyld_process_info info
)
626 info
->retainCount() += 1;
629 void _dyld_process_info_release(dyld_process_info info
)
631 info
->retainCount() -= 1;
632 if ( info
->retainCount() == 0 )
636 void _dyld_process_info_for_each_image(dyld_process_info info
, void (^callback
)(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
))
638 info
->forEachImage(callback
);
642 void _dyld_process_info_for_each_segment(dyld_process_info info
, uint64_t machHeaderAddress
, void (^callback
)(uint64_t segmentAddress
, uint64_t segmentSize
, const char* segmentName
))
644 info
->forEachSegment(machHeaderAddress
, callback
);