]>
Commit | Line | Data |
---|---|---|
0959b6d4 A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
39a8cd10 | 3 | * Copyright (c) 2004-2009 Apple Inc. All rights reserved. |
0959b6d4 A |
4 | * |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
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 | |
12 | * file. | |
13 | * | |
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. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | #include <stddef.h> | |
26 | #include <stdint.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | #include <mach-o/loader.h> | |
cf998323 A |
30 | #include <mach-o/dyld_images.h> |
31 | #include <mach-o/dyld_process_info.h> | |
0959b6d4 A |
32 | |
33 | #include <vector> | |
34 | ||
6cae9b63 | 35 | #include "Tracing.h" |
39a8cd10 | 36 | #include "ImageLoader.h" |
cf998323 | 37 | #include "dyld2.h" |
0959b6d4 | 38 | |
10b92d3b A |
39 | extern "C" void _dyld_debugger_notification(enum dyld_notify_mode mode, unsigned long count, uint64_t machHeaders[]); |
40 | ||
bc3b7c8c | 41 | #if TARGET_OS_OSX |
412ebb8e | 42 | #define INITIAL_UUID_IMAGE_COUNT 32 |
bc3b7c8c A |
43 | #else |
44 | #define INITIAL_UUID_IMAGE_COUNT 4 | |
412ebb8e | 45 | #endif |
0959b6d4 | 46 | |
2fd3f4e8 A |
47 | VECTOR_NEVER_DESTRUCTED(dyld_image_info); |
48 | VECTOR_NEVER_DESTRUCTED(dyld_uuid_info); | |
49 | ||
0959b6d4 | 50 | static std::vector<dyld_image_info> sImageInfos; |
412ebb8e | 51 | static std::vector<dyld_uuid_info> sImageUUIDs; |
0959b6d4 | 52 | |
bc3b7c8c A |
53 | #if __x86_64__ |
54 | static std::vector<dyld_aot_image_info> sAotImageInfos; | |
55 | #endif | |
56 | ||
9f83892a A |
57 | size_t allImagesCount() |
58 | { | |
59 | return sImageInfos.size(); | |
60 | } | |
61 | ||
62 | const mach_header* allImagesIndexedMachHeader(uint32_t index) | |
63 | { | |
64 | if ( index < sImageInfos.size() ) | |
65 | return sImageInfos[index].imageLoadAddress; | |
66 | else | |
67 | return NULL; | |
68 | } | |
69 | ||
70 | const char* allImagesIndexedPath(uint32_t index) | |
71 | { | |
72 | if ( index < sImageInfos.size() ) | |
73 | return sImageInfos[index].imageFilePath; | |
74 | else | |
75 | return NULL; | |
76 | } | |
77 | ||
2fd3f4e8 | 78 | |
0959b6d4 A |
79 | void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]) |
80 | { | |
412ebb8e | 81 | // make initial size large enough that we probably won't need to re-alloc it |
bac542e6 | 82 | if ( sImageInfos.size() == 0 ) |
39a8cd10 | 83 | sImageInfos.reserve(INITIAL_IMAGE_COUNT); |
412ebb8e A |
84 | if ( sImageUUIDs.capacity() == 0 ) |
85 | sImageUUIDs.reserve(4); | |
0959b6d4 | 86 | // set infoArray to NULL to denote it is in-use |
2fd3f4e8 | 87 | dyld::gProcessInfo->infoArray = NULL; |
0959b6d4 A |
88 | |
89 | // append all new images | |
90 | for (uint32_t i=0; i < infoCount; ++i) | |
91 | sImageInfos.push_back(info[i]); | |
19894a12 | 92 | dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); |
9f83892a A |
93 | dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time(); |
94 | ||
412ebb8e | 95 | // set infoArray back to base address of vector (other process can now read) |
2fd3f4e8 | 96 | dyld::gProcessInfo->infoArray = &sImageInfos[0]; |
412ebb8e | 97 | } |
0959b6d4 | 98 | |
bc3b7c8c A |
99 | #if __x86_64__ |
100 | void addAotImagesToAllAotImages(uint32_t aotInfoCount, const dyld_aot_image_info aotInfo[]) | |
101 | { | |
102 | if (sAotImageInfos.size() == 0) { | |
103 | sAotImageInfos.reserve(INITIAL_IMAGE_COUNT); | |
104 | } | |
105 | // set aotInfoArray to NULL to denote it is in-use | |
106 | dyld::gProcessInfo->aotInfoArray = NULL; | |
107 | ||
108 | for (uint32_t i = 0; i < aotInfoCount; ++i) { | |
109 | sAotImageInfos.push_back(aotInfo[i]); | |
110 | } | |
111 | dyld::gProcessInfo->aotInfoCount = (uint32_t)sAotImageInfos.size(); | |
112 | dyld::gProcessInfo->aotInfoArrayChangeTimestamp = mach_absolute_time(); | |
113 | ||
114 | // set aotInfoArray back to base address of vector (other process can now read) | |
115 | dyld::gProcessInfo->aotInfoArray = &sAotImageInfos[0]; | |
116 | } | |
117 | #endif | |
118 | ||
cf998323 | 119 | #if TARGET_OS_SIMULATOR |
2fd3f4e8 A |
120 | // called once in dyld_sim start up to copy image list from host dyld to sImageInfos |
121 | void syncProcessInfo() | |
122 | { | |
123 | // may want to set version field of gProcessInfo if it might be different than host | |
124 | if ( sImageInfos.size() == 0 ) { | |
125 | sImageInfos.reserve(INITIAL_IMAGE_COUNT); | |
126 | if ( dyld::gProcessInfo->infoArray != NULL ) { | |
127 | for (uint32_t i=0; i < dyld::gProcessInfo->infoArrayCount; ++i) { | |
128 | sImageInfos.push_back(dyld::gProcessInfo->infoArray[i]); | |
129 | } | |
130 | dyld::gProcessInfo->infoArray = &sImageInfos[0]; | |
19894a12 | 131 | dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); |
2fd3f4e8 A |
132 | } |
133 | } | |
134 | dyld::gProcessInfo->notification(dyld_image_info_change, 0, NULL); | |
135 | } | |
136 | #endif | |
412ebb8e A |
137 | |
138 | const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[]) | |
139 | { | |
0959b6d4 | 140 | // tell gdb that about the new images |
9f83892a | 141 | uint64_t t0 = mach_absolute_time(); |
2fd3f4e8 | 142 | dyld::gProcessInfo->notification(dyld_image_adding, infoCount, info); |
9f83892a A |
143 | uint64_t t1 = mach_absolute_time(); |
144 | ImageLoader::fgTotalDebuggerPausedTime += (t1-t0); | |
145 | ||
412ebb8e A |
146 | // <rdar://problem/7739489> record initial count of images |
147 | // so CrashReporter can note which images were dynamically loaded | |
2fd3f4e8 | 148 | if ( dyld::gProcessInfo->initialImageCount == 0 ) |
9f83892a | 149 | dyld::gProcessInfo->initialImageCount = dyld::gProcessInfo->infoArrayCount; |
412ebb8e A |
150 | return NULL; |
151 | } | |
152 | ||
153 | ||
154 | ||
155 | void addNonSharedCacheImageUUID(const dyld_uuid_info& info) | |
156 | { | |
157 | // set uuidArray to NULL to denote it is in-use | |
2fd3f4e8 | 158 | dyld::gProcessInfo->uuidArray = NULL; |
412ebb8e A |
159 | |
160 | // append all new images | |
161 | sImageUUIDs.push_back(info); | |
2fd3f4e8 | 162 | dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size(); |
412ebb8e A |
163 | |
164 | // set uuidArray back to base address of vector (other process can now read) | |
2fd3f4e8 | 165 | dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; |
0959b6d4 A |
166 | } |
167 | ||
168 | void removeImageFromAllImages(const struct mach_header* loadAddress) | |
169 | { | |
170 | dyld_image_info goingAway; | |
171 | ||
172 | // set infoArray to NULL to denote it is in-use | |
2fd3f4e8 | 173 | dyld::gProcessInfo->infoArray = NULL; |
0959b6d4 A |
174 | |
175 | // remove image from infoArray | |
176 | for (std::vector<dyld_image_info>::iterator it=sImageInfos.begin(); it != sImageInfos.end(); it++) { | |
177 | if ( it->imageLoadAddress == loadAddress ) { | |
178 | goingAway = *it; | |
179 | sImageInfos.erase(it); | |
180 | break; | |
181 | } | |
182 | } | |
19894a12 | 183 | dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); |
0959b6d4 A |
184 | |
185 | // set infoArray back to base address of vector | |
2fd3f4e8 | 186 | dyld::gProcessInfo->infoArray = &sImageInfos[0]; |
0959b6d4 | 187 | |
412ebb8e A |
188 | |
189 | // set uuidArrayCount to NULL to denote it is in-use | |
2fd3f4e8 | 190 | dyld::gProcessInfo->uuidArray = NULL; |
412ebb8e A |
191 | |
192 | // remove image from infoArray | |
193 | for (std::vector<dyld_uuid_info>::iterator it=sImageUUIDs.begin(); it != sImageUUIDs.end(); it++) { | |
194 | if ( it->imageLoadAddress == loadAddress ) { | |
195 | sImageUUIDs.erase(it); | |
196 | break; | |
197 | } | |
198 | } | |
2fd3f4e8 | 199 | dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size(); |
9f83892a A |
200 | dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time(); |
201 | ||
412ebb8e | 202 | // set infoArray back to base address of vector |
2fd3f4e8 | 203 | dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; |
412ebb8e | 204 | |
0959b6d4 | 205 | // tell gdb that about the new images |
2fd3f4e8 | 206 | dyld::gProcessInfo->notification(dyld_image_removing, 1, &goingAway); |
0959b6d4 A |
207 | } |
208 | ||
0959b6d4 | 209 | |
cf998323 | 210 | #if TARGET_OS_SIMULATOR |
2fd3f4e8 A |
211 | namespace dyld { |
212 | struct dyld_all_image_infos* gProcessInfo = NULL; | |
213 | } | |
214 | #else | |
39a8cd10 | 215 | |
9f83892a A |
216 | static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]) |
217 | { | |
6cae9b63 | 218 | dyld3::ScopedTimer(DBG_DYLD_GDB_IMAGE_NOTIFIER, 0, 0, 0); |
9f83892a A |
219 | uint64_t machHeaders[infoCount]; |
220 | for (uint32_t i=0; i < infoCount; ++i) { | |
221 | machHeaders[i] = (uintptr_t)(info[i].imageLoadAddress); | |
222 | } | |
223 | switch ( mode ) { | |
224 | case dyld_image_adding: | |
225 | _dyld_debugger_notification(dyld_notify_adding, infoCount, machHeaders); | |
226 | break; | |
227 | case dyld_image_removing: | |
228 | _dyld_debugger_notification(dyld_notify_removing, infoCount, machHeaders); | |
229 | break; | |
230 | default: | |
231 | break; | |
2fd3f4e8 | 232 | } |
9f83892a A |
233 | // do nothing |
234 | // gdb sets a break point here to catch notifications | |
235 | //dyld::log("dyld: gdb_image_notifier(%s, %d, ...)\n", mode ? "dyld_image_removing" : "dyld_image_adding", infoCount); | |
236 | //for (uint32_t i=0; i < infoCount; ++i) | |
237 | // dyld::log("dyld: %d loading at %p %s\n", i, info[i].imageLoadAddress, info[i].imageFilePath); | |
238 | //for (uint32_t i=0; i < dyld::gProcessInfo->infoArrayCount; ++i) | |
239 | // dyld::log("dyld: %d loading at %p %s\n", i, dyld::gProcessInfo->infoArray[i].imageLoadAddress, dyld::gProcessInfo->infoArray[i].imageFilePath); | |
240 | } | |
241 | ||
242 | // only used with accelerator tables and ASan which images need to be re-loaded | |
243 | void resetAllImages() | |
244 | { | |
245 | sImageInfos.clear(); | |
246 | sImageUUIDs.clear(); | |
247 | _dyld_debugger_notification(dyld_notify_remove_all, 0, NULL); | |
248 | } | |
2fd3f4e8 A |
249 | |
250 | extern void* __dso_handle; | |
251 | #define STR(s) # s | |
252 | #define XSTR(s) STR(s) | |
0959b6d4 | 253 | |
2fd3f4e8 A |
254 | struct dyld_all_image_infos dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info"))) |
255 | = { | |
bc3b7c8c | 256 | 17, 0, {NULL}, &gdb_image_notifier, false, false, (const mach_header*)&__dso_handle, NULL, |
6cae9b63 | 257 | XSTR(DYLD_VERSION), NULL, 0, NULL, 0, 0, NULL, &dyld_all_image_infos, |
9f83892a | 258 | 0, 0, NULL, NULL, NULL, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, |
bc3b7c8c | 259 | 0, {0}, "/usr/lib/dyld", {0}, {0}, 0, 0, NULL, 0 |
2fd3f4e8 | 260 | }; |
0959b6d4 | 261 | |
2fd3f4e8 | 262 | struct dyld_shared_cache_ranges dyld_shared_cache_ranges; |
39a8cd10 | 263 | |
2fd3f4e8 A |
264 | namespace dyld { |
265 | struct dyld_all_image_infos* gProcessInfo = &dyld_all_image_infos; | |
266 | } | |
267 | #endif | |
0959b6d4 | 268 |