1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2009-2012 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@
27 #include <Availability.h>
30 #include "dsc_iterator.h"
31 #include "dyld_cache_format.h"
33 #include "Architectures.hpp"
34 #include "MachOFileAbstraction.hpp"
35 #include "CacheFileAbstraction.hpp"
41 // convert an address in the shared region where the cache would normally be mapped, into an address where the cache is currently mapped
43 const uint8_t* mappedAddress(const uint8_t* cache
, const uint8_t* cacheEnd
, uint64_t addr
)
45 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
46 const dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&cache
[header
->mappingOffset()];
47 for (uint32_t i
=0; i
< header
->mappingCount(); ++i
) {
48 if ( (mappings
[i
].address() <= addr
) && (addr
< (mappings
[i
].address() + mappings
[i
].size())) ) {
49 uint64_t cacheOffset
= mappings
[i
].file_offset() + addr
- mappings
[i
].address();
50 const uint8_t* result
= &cache
[cacheOffset
];
51 if ( result
< cacheEnd
)
60 // call the callback block on each segment in this image
62 int walkSegments(const uint8_t* cache
, const uint8_t* cacheEnd
, const uint8_t* firstSeg
, const char* dylibPath
, uint64_t inode
,uint64_t modTime
, const uint8_t* machHeader
, uint64_t cache_unslid_base_address
,
63 void (^callback
)(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
))
65 typedef typename
A::P P
;
66 typedef typename
A::P::E E
;
67 dyld_shared_cache_dylib_info dylibInfo
;
68 dyld_shared_cache_segment_info segInfo
;
69 dylibInfo
.version
= 2;
70 dylibInfo
.isAlias
= (dylibPath
< (char*)firstSeg
); // paths for aliases are store between cache header and first segment
71 dylibInfo
.machHeader
= machHeader
;
72 dylibInfo
.path
= dylibPath
;
73 dylibInfo
.inode
= inode
;
74 dylibInfo
.modTime
= modTime
;
75 const macho_header
<P
>* mh
= (const macho_header
<P
>*)machHeader
;
76 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)(machHeader
+ sizeof(macho_header
<P
>));
77 if ( (machHeader
+ mh
->sizeofcmds()) > cacheEnd
)
79 const uint32_t cmd_count
= mh
->ncmds();
80 const macho_load_command
<P
>* cmd
= cmds
;
82 dylibInfo
.uuid
= NULL
;
83 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
84 if ( cmd
->cmd() == LC_UUID
) {
85 const uuid_command
* uc
= (const uuid_command
*)cmd
;
86 dylibInfo
.uuid
= &uc
->uuid
;
89 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
91 // callback for each LC_SEGMENT
93 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
94 if ( cmd
->cmd() == macho_segment_command
<P
>::CMD
) {
95 macho_segment_command
<P
>* segCmd
= (macho_segment_command
<P
>*)cmd
;
96 uint64_t fileOffset
= segCmd
->fileoff();
97 // work around until <rdar://problem/7022345> is fixed
98 if ( fileOffset
== 0 ) {
99 fileOffset
= (machHeader
- cache
);
101 uint64_t sizem
= segCmd
->vmsize();
102 if ( strcmp(segCmd
->segname(), "__LINKEDIT") == 0 ) {
103 // clip LINKEDIT size if bigger than cache file
104 if ( (fileOffset
+sizem
) > (uint64_t)(cacheEnd
-cache
) )
105 sizem
= (cacheEnd
-cache
)-fileOffset
;
108 segInfo
.name
= segCmd
->segname();
109 segInfo
.fileOffset
= fileOffset
;
110 segInfo
.fileSize
= sizem
;
111 if ( segCmd
->filesize() > segCmd
->vmsize() )
113 segInfo
.address
= segCmd
->vmaddr();
114 segInfo
.addressOffset
= segInfo
.address
- cache_unslid_base_address
;
115 callback(&dylibInfo
, &segInfo
);
117 cmd
= (const macho_load_command
<P
>*)(((uint8_t*)cmd
)+cmd
->cmdsize());
123 // call walkSegments on each image in the cache
124 template <typename A
>
125 int walkImages(const uint8_t* cache
, uint32_t size
, void (^callback
)(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
))
127 // Sanity check there is at least a header
128 if ( (size
> 0) && (size
< 0x7000) )
130 typedef typename
A::P::E E
;
131 typedef typename
A::P P
;
132 const dyldCacheHeader
<E
>* header
= (dyldCacheHeader
<E
>*)cache
;
133 const dyldCacheImageInfo
<E
>* dylibs
= (dyldCacheImageInfo
<E
>*)&cache
[header
->imagesOffset()];
134 const dyldCacheFileMapping
<E
>* mappings
= (dyldCacheFileMapping
<E
>*)&cache
[header
->mappingOffset()];
135 uint64_t unslid_base_address
= mappings
[0].address();
136 uint64_t greatestMappingOffset
= 0;
137 for (uint32_t i
=0; i
< header
->mappingCount(); ++i
) {
138 if ( (size
!= 0) && (mappings
[i
].file_offset() > size
) )
140 uint64_t endOffset
= mappings
[i
].file_offset()+mappings
[i
].size();
141 if ( (size
!= 0) && (endOffset
> size
) )
143 if ( endOffset
> greatestMappingOffset
)
144 greatestMappingOffset
= endOffset
;
146 const uint8_t* cacheEnd
= &cache
[size
];
148 // Zero size means old API is being used, assume all mapped
149 cacheEnd
= &cache
[greatestMappingOffset
];
152 // verifiy mappings are not bigger than size
153 if ( size
< greatestMappingOffset
)
156 // verify all image infos are mapped
157 if ( (const uint8_t*)&dylibs
[header
->imagesCount()] > cacheEnd
)
159 const uint8_t* firstSeg
= NULL
;
160 for (uint32_t i
=0; i
< header
->imagesCount(); ++i
) {
161 const char* dylibPath
= (char*)cache
+ dylibs
[i
].pathFileOffset();
162 uint64_t inode
= dylibs
[i
].inode();
163 uint64_t modTime
= dylibs
[i
].modTime();
164 if ( (const uint8_t*)dylibPath
> cacheEnd
)
166 const uint8_t* machHeader
= mappedAddress
<E
>(cache
, cacheEnd
, dylibs
[i
].address());
167 if ( machHeader
== NULL
)
169 if ( machHeader
> cacheEnd
)
171 if ( firstSeg
== NULL
)
172 firstSeg
= machHeader
;
173 int result
= walkSegments
<A
>(cache
, cacheEnd
, firstSeg
, dylibPath
, inode
, modTime
, machHeader
, unslid_base_address
, callback
);
183 // Given a pointer to an in-memory copy of a dyld shared cache file,
184 // this routine will call the callback block once for each segment
185 // in each dylib in the shared cache file.
186 // Returns -1 if there was an error, otherwise 0.
187 extern int dyld_shared_cache_iterate(const void* shared_cache_file
, uint32_t shared_cache_size
,
188 void (^callback
)(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
)) {
189 const uint8_t* cache
= (uint8_t*)shared_cache_file
;
190 if ( strcmp((char*)cache
, "dyld_v1 i386") == 0 )
191 return dyld::walkImages
<x86
>(cache
, shared_cache_size
, callback
);
192 else if ( strcmp((char*)cache
, "dyld_v1 x86_64") == 0 )
193 return dyld::walkImages
<x86_64
>(cache
, shared_cache_size
, callback
);
194 else if ( strcmp((char*)cache
, "dyld_v1 x86_64h") == 0 )
195 return dyld::walkImages
<x86_64
>(cache
, shared_cache_size
, callback
);
196 else if ( strcmp((char*)cache
, "dyld_v1 armv5") == 0 )
197 return dyld::walkImages
<arm
>(cache
, shared_cache_size
, callback
);
198 else if ( strcmp((char*)cache
, "dyld_v1 armv6") == 0 )
199 return dyld::walkImages
<arm
>(cache
, shared_cache_size
, callback
);
200 else if ( strcmp((char*)cache
, "dyld_v1 armv7") == 0 )
201 return dyld::walkImages
<arm
>(cache
, shared_cache_size
, callback
);
202 else if ( strncmp((char*)cache
, "dyld_v1 armv7", 14) == 0 )
203 return dyld::walkImages
<arm
>(cache
, shared_cache_size
, callback
);
204 else if ( strcmp((char*)cache
, "dyld_v1 arm64") == 0 )
205 return dyld::walkImages
<arm64
>(cache
, shared_cache_size
, callback
);
206 else if ( strcmp((char*)cache
, "dyld_v1 arm64e") == 0 )
207 return dyld::walkImages
<arm64
>(cache
, shared_cache_size
, callback
);
213 // implement old version by calling new version
214 int dyld_shared_cache_iterate_segments_with_slide(const void* shared_cache_file
, dyld_shared_cache_iterator_slide_t callback
)
216 return dyld_shared_cache_iterate(shared_cache_file
, 0, ^(const dyld_shared_cache_dylib_info
* dylibInfo
, const dyld_shared_cache_segment_info
* segInfo
) {
217 callback(dylibInfo
->path
, segInfo
->name
, segInfo
->fileOffset
, segInfo
->fileSize
, segInfo
->address
, 0);
221 // implement non-block version by calling block version
222 int dyld_shared_cache_iterate_segments_with_slide_nb(const void* shared_cache_file
, dyld_shared_cache_iterator_slide_nb_t func
, void* userData
)
224 return dyld_shared_cache_iterate_segments_with_slide(shared_cache_file
, ^(const char* dylibName
, const char* segName
,
225 uint64_t offset
, uint64_t size
, uint64_t mappedddress
, uint64_t slide
) {
226 (*func
)(dylibName
, segName
, offset
, size
, mappedddress
, slide
, userData
);
231 // implement non-slide version by wrapping slide version in block
232 int dyld_shared_cache_iterate_segments(const void* shared_cache_file
, dyld_shared_cache_iterator_t callback
)
234 dyld_shared_cache_iterator_slide_t wrapper_cb
= ^(const char* dylibName
, const char* segName
, uint64_t offset
,
235 uint64_t size
, uint64_t mappedddress
, uint64_t slide
) {
236 callback(dylibName
, segName
, offset
, size
, mappedddress
);
238 return dyld_shared_cache_iterate_segments_with_slide(shared_cache_file
, wrapper_cb
);
241 // implement non-slide,non-block version by wrapping slide version in block
242 int dyld_shared_cache_iterate_segments_nb(const void* shared_cache_file
, dyld_shared_cache_iterator_nb_t func
, void* userData
)
244 return dyld_shared_cache_iterate_segments_with_slide(shared_cache_file
, ^(const char* dylibName
, const char* segName
,
245 uint64_t offset
, uint64_t size
, uint64_t mappedddress
, uint64_t slide
) {
246 (*func
)(dylibName
, segName
, offset
, size
, mappedddress
, userData
);