]>
Commit | Line | Data |
---|---|---|
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- | |
2 | * | |
3 | * Copyright (c) 2004-2009 Apple Inc. All rights reserved. | |
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> | |
30 | #include <mach-o/dyld_images.h> | |
31 | #include <mach-o/dyld_process_info.h> | |
32 | ||
33 | #include <vector> | |
34 | ||
35 | #include "Tracing.h" | |
36 | #include "ImageLoader.h" | |
37 | #include "dyld2.h" | |
38 | ||
39 | extern "C" void _dyld_debugger_notification(enum dyld_notify_mode mode, unsigned long count, uint64_t machHeaders[]); | |
40 | ||
41 | #if TARGET_OS_OSX | |
42 | #define INITIAL_UUID_IMAGE_COUNT 32 | |
43 | #else | |
44 | #define INITIAL_UUID_IMAGE_COUNT 4 | |
45 | #endif | |
46 | ||
47 | VECTOR_NEVER_DESTRUCTED(dyld_image_info); | |
48 | VECTOR_NEVER_DESTRUCTED(dyld_uuid_info); | |
49 | ||
50 | static std::vector<dyld_image_info> sImageInfos; | |
51 | static std::vector<dyld_uuid_info> sImageUUIDs; | |
52 | ||
53 | #if __x86_64__ | |
54 | static std::vector<dyld_aot_image_info> sAotImageInfos; | |
55 | #endif | |
56 | ||
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 | ||
78 | ||
79 | void addImagesToAllImages(uint32_t infoCount, const dyld_image_info info[]) | |
80 | { | |
81 | // make initial size large enough that we probably won't need to re-alloc it | |
82 | if ( sImageInfos.size() == 0 ) | |
83 | sImageInfos.reserve(INITIAL_IMAGE_COUNT); | |
84 | if ( sImageUUIDs.capacity() == 0 ) | |
85 | sImageUUIDs.reserve(4); | |
86 | // set infoArray to NULL to denote it is in-use | |
87 | dyld::gProcessInfo->infoArray = NULL; | |
88 | ||
89 | // append all new images | |
90 | for (uint32_t i=0; i < infoCount; ++i) | |
91 | sImageInfos.push_back(info[i]); | |
92 | dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); | |
93 | dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time(); | |
94 | ||
95 | // set infoArray back to base address of vector (other process can now read) | |
96 | dyld::gProcessInfo->infoArray = &sImageInfos[0]; | |
97 | } | |
98 | ||
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 | ||
119 | #if TARGET_OS_SIMULATOR | |
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]; | |
131 | dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); | |
132 | } | |
133 | } | |
134 | dyld::gProcessInfo->notification(dyld_image_info_change, 0, NULL); | |
135 | } | |
136 | #endif | |
137 | ||
138 | const char* notifyGDB(enum dyld_image_states state, uint32_t infoCount, const dyld_image_info info[]) | |
139 | { | |
140 | // tell gdb that about the new images | |
141 | uint64_t t0 = mach_absolute_time(); | |
142 | dyld::gProcessInfo->notification(dyld_image_adding, infoCount, info); | |
143 | uint64_t t1 = mach_absolute_time(); | |
144 | ImageLoader::fgTotalDebuggerPausedTime += (t1-t0); | |
145 | ||
146 | // <rdar://problem/7739489> record initial count of images | |
147 | // so CrashReporter can note which images were dynamically loaded | |
148 | if ( dyld::gProcessInfo->initialImageCount == 0 ) | |
149 | dyld::gProcessInfo->initialImageCount = dyld::gProcessInfo->infoArrayCount; | |
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 | |
158 | dyld::gProcessInfo->uuidArray = NULL; | |
159 | ||
160 | // append all new images | |
161 | sImageUUIDs.push_back(info); | |
162 | dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size(); | |
163 | ||
164 | // set uuidArray back to base address of vector (other process can now read) | |
165 | dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; | |
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 | |
173 | dyld::gProcessInfo->infoArray = NULL; | |
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 | } | |
183 | dyld::gProcessInfo->infoArrayCount = (uint32_t)sImageInfos.size(); | |
184 | ||
185 | // set infoArray back to base address of vector | |
186 | dyld::gProcessInfo->infoArray = &sImageInfos[0]; | |
187 | ||
188 | ||
189 | // set uuidArrayCount to NULL to denote it is in-use | |
190 | dyld::gProcessInfo->uuidArray = NULL; | |
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 | } | |
199 | dyld::gProcessInfo->uuidArrayCount = sImageUUIDs.size(); | |
200 | dyld::gProcessInfo->infoArrayChangeTimestamp = mach_absolute_time(); | |
201 | ||
202 | // set infoArray back to base address of vector | |
203 | dyld::gProcessInfo->uuidArray = &sImageUUIDs[0]; | |
204 | ||
205 | // tell gdb that about the new images | |
206 | dyld::gProcessInfo->notification(dyld_image_removing, 1, &goingAway); | |
207 | } | |
208 | ||
209 | ||
210 | #if TARGET_OS_SIMULATOR | |
211 | namespace dyld { | |
212 | struct dyld_all_image_infos* gProcessInfo = NULL; | |
213 | } | |
214 | #else | |
215 | ||
216 | static void gdb_image_notifier(enum dyld_image_mode mode, uint32_t infoCount, const dyld_image_info info[]) | |
217 | { | |
218 | dyld3::ScopedTimer(DBG_DYLD_GDB_IMAGE_NOTIFIER, 0, 0, 0); | |
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; | |
232 | } | |
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 | } | |
249 | ||
250 | extern void* __dso_handle; | |
251 | #define STR(s) # s | |
252 | #define XSTR(s) STR(s) | |
253 | ||
254 | struct dyld_all_image_infos dyld_all_image_infos __attribute__ ((section ("__DATA,__all_image_info"))) | |
255 | = { | |
256 | 17, 0, {NULL}, &gdb_image_notifier, false, false, (const mach_header*)&__dso_handle, NULL, | |
257 | XSTR(DYLD_VERSION), NULL, 0, NULL, 0, 0, NULL, &dyld_all_image_infos, | |
258 | 0, 0, NULL, NULL, NULL, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,}, | |
259 | 0, {0}, "/usr/lib/dyld", {0}, {0}, 0, 0, NULL, 0 | |
260 | }; | |
261 | ||
262 | struct dyld_shared_cache_ranges dyld_shared_cache_ranges; | |
263 | ||
264 | namespace dyld { | |
265 | struct dyld_all_image_infos* gProcessInfo = &dyld_all_image_infos; | |
266 | } | |
267 | #endif | |
268 |