]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime.m
objc4-371.1.tar.gz
[apple/objc4.git] / runtime / objc-runtime.m
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /***********************************************************************
24 * objc-runtime.m
25 * Copyright 1988-1996, NeXT Software, Inc.
26 * Author: s. naroff
27 *
28 **********************************************************************/
29
30
31
32 /***********************************************************************
33 * Imports.
34 **********************************************************************/
35
36 #include <mach-o/ldsyms.h>
37 #include <mach-o/dyld.h>
38 #include <mach-o/dyld_gdb.h>
39 #include <mach-o/dyld_priv.h>
40 #include <mach/mach.h>
41 #include <mach/mach_error.h>
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <crt_externs.h>
48 #include <libgen.h>
49
50 #include <crt_externs.h>
51 #include <libgen.h>
52
53 #import "objc-private.h"
54 #import "hashtable2.h"
55 #import "maptable.h"
56 #import "Object.h"
57 #import "objc-rtp.h"
58 #import "objc-auto.h"
59 #import "objc-loadmethod.h"
60
61 OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
62
63
64 /***********************************************************************
65 * Exports.
66 **********************************************************************/
67
68 // Settings from environment variables
69 __private_extern__ int PrintImages = -1; // env OBJC_PRINT_IMAGES
70 __private_extern__ int PrintLoading = -1; // env OBJC_PRINT_LOAD_METHODS
71 __private_extern__ int PrintInitializing = -1; // env OBJC_PRINT_INITIALIZE_METHODS
72 __private_extern__ int PrintResolving = -1; // env OBJC_PRINT_RESOLVED_METHODS
73 __private_extern__ int PrintConnecting = -1; // env OBJC_PRINT_CLASS_SETUP
74 __private_extern__ int PrintProtocols = -1; // env OBJC_PRINT_PROTOCOL_SETUP
75 __private_extern__ int PrintIvars = -1; // env OBJC_PRINT_IVAR_SETUP
76 __private_extern__ int PrintFuture = -1; // env OBJC_PRINT_FUTURE_CLASSES
77 __private_extern__ int PrintRTP = -1; // env OBJC_PRINT_RTP
78 __private_extern__ int PrintGC = -1; // env OBJC_PRINT_GC
79 __private_extern__ int PrintSharing = -1; // env OBJC_PRINT_SHARING
80 __private_extern__ int PrintCxxCtors = -1; // env OBJC_PRINT_CXX_CTORS
81 __private_extern__ int PrintExceptions = -1; // env OBJC_PRINT_EXCEPTIONS
82 __private_extern__ int PrintAltHandlers = -1; // env OBJC_PRINT_ALT_HANDLERS
83 __private_extern__ int PrintDeprecation = -1;// env OBJC_PRINT_DEPRECATION_WARNINGS
84 __private_extern__ int PrintReplacedMethods = -1; // env OBJC_PRINT_REPLACED_METHODS
85 __private_extern__ int PrintCacheCollection = -1; // env OBJC_PRINT_CACHE_COLLECTION
86
87 __private_extern__ int UseInternalZone = -1; // env OBJC_USE_INTERNAL_ZONE
88 __private_extern__ int AllowInterposing = -1;// env OBJC_ALLOW_INTERPOSING
89
90 __private_extern__ int DebugUnload = -1; // env OBJC_DEBUG_UNLOAD
91 __private_extern__ int DebugFragileSuperclasses = -1; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES
92 __private_extern__ int DebugNilSync = -1; // env OBJC_DEBUG_NIL_SYNC
93
94 __private_extern__ int DisableGC = -1; // env OBJC_DISABLE_GC
95 __private_extern__ int DebugFinalizers = -1; // env OBJC_DEBUG_FINALIZERS
96
97
98 // objc's key for pthread_getspecific
99 static pthread_key_t _objc_pthread_key = 0;
100
101 // Selectors for which @selector() doesn't work
102 __private_extern__ SEL cxx_construct_sel = NULL;
103 __private_extern__ SEL cxx_destruct_sel = NULL;
104 __private_extern__ const char *cxx_construct_name = ".cxx_construct";
105 __private_extern__ const char *cxx_destruct_name = ".cxx_destruct";
106
107
108 /***********************************************************************
109 * Function prototypes internal to this module.
110 **********************************************************************/
111
112 static void _objc_unmap_image(header_info *hi);
113
114
115 /***********************************************************************
116 * Static data internal to this module.
117 **********************************************************************/
118
119 // we keep a linked list of header_info's describing each image as told to us by dyld
120 static header_info *FirstHeader NOBSS = 0; // NULL means empty list
121 static header_info *LastHeader NOBSS = 0; // NULL means invalid; recompute it
122 static int HeaderCount NOBSS = 0;
123
124
125 /***********************************************************************
126 * objc_getClass. Return the id of the named class. If the class does
127 * not exist, call _objc_classLoader and then objc_classHandler, either of
128 * which may create a new class.
129 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
130 **********************************************************************/
131 id objc_getClass(const char *aClassName)
132 {
133 if (!aClassName) return Nil;
134
135 // NO unconnected, YES class handler
136 return look_up_class(aClassName, NO, YES);
137 }
138
139
140 /***********************************************************************
141 * objc_getRequiredClass.
142 * Same as objc_getClass, but kills the process if the class is not found.
143 * This is used by ZeroLink, where failing to find a class would be a
144 * compile-time link error without ZeroLink.
145 **********************************************************************/
146 id objc_getRequiredClass(const char *aClassName)
147 {
148 id cls = objc_getClass(aClassName);
149 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
150 return cls;
151 }
152
153
154 /***********************************************************************
155 * objc_lookUpClass. Return the id of the named class.
156 * If the class does not exist, call _objc_classLoader, which may create
157 * a new class.
158 *
159 * Formerly objc_getClassWithoutWarning ()
160 **********************************************************************/
161 id objc_lookUpClass(const char *aClassName)
162 {
163 if (!aClassName) return Nil;
164
165 // NO unconnected, NO class handler
166 return look_up_class(aClassName, NO, NO);
167 }
168
169 /***********************************************************************
170 * objc_getFutureClass. Return the id of the named class.
171 * If the class does not exist, return an uninitialized class
172 * structure that will be used for the class when and if it
173 * does get loaded.
174 * Not thread safe.
175 **********************************************************************/
176 Class objc_getFutureClass(const char *name)
177 {
178 Class cls;
179
180 // YES unconnected, NO class handler
181 // (unconnected is OK because it will someday be the real class)
182 cls = look_up_class(name, YES, NO);
183 if (cls) {
184 if (PrintFuture) {
185 _objc_inform("FUTURE: found %p already in use for %s", cls, name);
186 }
187 return cls;
188 }
189
190 // No class or future class with that name yet. Make one.
191 // fixme not thread-safe with respect to
192 // simultaneous library load or getFutureClass.
193 return _objc_allocateFutureClass(name);
194 }
195
196
197 /***********************************************************************
198 * objc_getMetaClass. Return the id of the meta class the named class.
199 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
200 **********************************************************************/
201 id objc_getMetaClass(const char *aClassName)
202 {
203 Class cls;
204
205 if (!aClassName) return Nil;
206
207 cls = objc_getClass (aClassName);
208 if (!cls)
209 {
210 _objc_inform ("class `%s' not linked into application", aClassName);
211 return Nil;
212 }
213
214 return ((id)cls)->isa;
215 }
216
217
218 #if !__LP64__
219 // Not updated for 64-bit ABI
220
221 /***********************************************************************
222 * _headerForAddress.
223 * addr can be a class or a category
224 **********************************************************************/
225 static const header_info *_headerForAddress(void *addr)
226 {
227 unsigned long size;
228 unsigned long seg;
229 header_info * hInfo;
230
231 // Check all headers in the vector
232 for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next)
233 {
234 // Locate header data, if any
235 if (!hInfo->objcSegmentHeader) continue;
236 seg = hInfo->objcSegmentHeader->vmaddr + hInfo->image_slide;
237 size = hInfo->objcSegmentHeader->filesize;
238
239 // Is the class in this header?
240 if ((seg <= (unsigned long) addr) &&
241 ((unsigned long) addr < (seg + size)))
242 return hInfo;
243 }
244
245 // Not found
246 return 0;
247 }
248
249
250 /***********************************************************************
251 * _headerForClass
252 * Return the image header containing this class, or NULL.
253 * Returns NULL on runtime-constructed classes, and the NSCF classes.
254 **********************************************************************/
255 __private_extern__ const header_info *_headerForClass(Class cls)
256 {
257 return _headerForAddress(cls);
258 }
259
260 // !__LP64__
261 #endif
262
263
264 /***********************************************************************
265 * _nameForHeader.
266 **********************************************************************/
267 __private_extern__ const char *_nameForHeader(const headerType *header)
268 {
269 return _getObjcHeaderName ((headerType *) header);
270 }
271
272
273 /***********************************************************************
274 * _gcForHInfo.
275 **********************************************************************/
276 __private_extern__ const char *_gcForHInfo(const header_info *hinfo)
277 {
278 if (_objcHeaderRequiresGC(hinfo)) return "requires GC";
279 else if (_objcHeaderSupportsGC(hinfo)) return "supports GC";
280 else return "does not support GC";
281 }
282 __private_extern__ const char *_gcForHInfo2(const header_info *hinfo)
283 {
284 if (_objcHeaderRequiresGC(hinfo)) return " (requires GC)";
285 else if (_objcHeaderSupportsGC(hinfo)) return " (supports GC)";
286 else return "";
287 }
288
289
290 /***********************************************************************
291 * bad_magic.
292 * Return YES if the header has invalid Mach-o magic.
293 **********************************************************************/
294 static BOOL bad_magic(const headerType *mhdr)
295 {
296 return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
297 mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
298 }
299
300
301 /***********************************************************************
302 * _objc_headerStart. Return what headers we know about.
303 **********************************************************************/
304 __private_extern__ header_info *_objc_headerStart(void)
305 {
306 // Take advatage of our previous work
307 return FirstHeader;
308 }
309
310
311 /***********************************************************************
312 * _objc_addHeader.
313 * Returns NULL if the header has no ObjC metadata.
314 **********************************************************************/
315
316 // tested with 2; typical case is 4, but OmniWeb & Mail push it towards 20
317 #define HINFO_SIZE 16
318
319 static int HeaderInfoCounter NOBSS = 0;
320 static header_info HeaderInfoTable[HINFO_SIZE] NOBSS = { {0} };
321
322 static header_info * _objc_addHeader(const headerType *header)
323 {
324 size_t info_size = 0;
325 const segmentType *objc_segment;
326 const segmentType *objc2_segment;
327 const objc_image_info *image_info;
328 const segmentType *data_segment;
329 header_info *result;
330 ptrdiff_t image_slide;
331
332 // Weed out duplicates
333 for (result = FirstHeader; result; result = result->next) {
334 if (header == result->mhdr) return NULL;
335 }
336
337 // Locate the __OBJC segment
338 image_slide = _getImageSlide(header);
339 image_info = _getObjcImageInfo(header, image_slide, &info_size);
340 objc_segment = getsegbynamefromheader(header, SEG_OBJC);
341 objc2_segment = getsegbynamefromheader(header, SEG_OBJC2);
342 data_segment = getsegbynamefromheader(header, SEG_DATA);
343 if (!objc_segment && !image_info && !objc2_segment) return NULL;
344
345 // Find or allocate a header_info entry.
346 if (HeaderInfoCounter < HINFO_SIZE) {
347 result = &HeaderInfoTable[HeaderInfoCounter++];
348 } else {
349 result = _malloc_internal(sizeof(header_info));
350 }
351
352 // Set up the new header_info entry.
353 result->mhdr = header;
354 result->image_slide = image_slide;
355 result->objcSegmentHeader = objc_segment;
356 result->dataSegmentHeader = data_segment;
357 #if !__OBJC2__
358 result->mod_count = 0;
359 result->mod_ptr = _getObjcModules(header, result->image_slide, &result->mod_count);
360 #endif
361 result->info = image_info;
362 dladdr(result->mhdr, &result->dl_info);
363 result->allClassesRealized = NO;
364
365 // dylibs are not allowed to unload
366 if (result->mhdr->filetype == MH_DYLIB) {
367 dlopen(result->dl_info.dli_fname, RTLD_NOLOAD);
368 }
369
370 // Make sure every copy of objc_image_info in this image is the same.
371 // This means same version and same bitwise contents.
372 if (result->info) {
373 const objc_image_info *start = result->info;
374 const objc_image_info *end =
375 (objc_image_info *)(info_size + (uint8_t *)start);
376 const objc_image_info *info = start;
377 while (info < end) {
378 // version is byte size, except for version 0
379 size_t struct_size = info->version;
380 if (struct_size == 0) struct_size = 2 * sizeof(uint32_t);
381 if (info->version != start->version ||
382 0 != memcmp(info, start, struct_size))
383 {
384 _objc_inform("'%s' has inconsistently-compiled Objective-C "
385 "code. Please recompile all code in it.",
386 _nameForHeader(header));
387 }
388 info = (objc_image_info *)(struct_size + (uint8_t *)info);
389 }
390 }
391
392 // Add the header to the header list.
393 // The header is appended to the list, to preserve the bottom-up order.
394 HeaderCount++;
395 result->next = NULL;
396 if (!FirstHeader) {
397 // list is empty
398 FirstHeader = LastHeader = result;
399 } else {
400 if (!LastHeader) {
401 // list is not empty, but LastHeader is invalid - recompute it
402 LastHeader = FirstHeader;
403 while (LastHeader->next) LastHeader = LastHeader->next;
404 }
405 // LastHeader is now valid
406 LastHeader->next = result;
407 LastHeader = result;
408 }
409
410 return result;
411 }
412
413
414 /***********************************************************************
415 * _objc_RemoveHeader
416 * Remove the given header from the header list.
417 * FirstHeader is updated.
418 * LastHeader is set to NULL. Any code that uses LastHeader must
419 * detect this NULL and recompute LastHeader by traversing the list.
420 **********************************************************************/
421 static void _objc_removeHeader(header_info *hi)
422 {
423 header_info **hiP;
424
425 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
426 if (*hiP == hi) {
427 header_info *deadHead = *hiP;
428
429 // Remove from the linked list (updating FirstHeader if necessary).
430 *hiP = (**hiP).next;
431
432 // Update LastHeader if necessary.
433 if (LastHeader == deadHead) {
434 LastHeader = NULL; // will be recomputed next time it's used
435 }
436
437 // Free the memory, unless it was in the static HeaderInfoTable.
438 if (deadHead < HeaderInfoTable ||
439 deadHead >= HeaderInfoTable + HINFO_SIZE)
440 {
441 _free_internal(deadHead);
442 }
443
444 HeaderCount--;
445
446 break;
447 }
448 }
449 }
450
451
452 /***********************************************************************
453 * check_gc
454 * Check whether the executable supports or requires GC, and make sure
455 * all already-loaded libraries support the executable's GC mode.
456 * Returns TRUE if the executable wants GC on.
457 **********************************************************************/
458 static BOOL check_wants_gc(void)
459 {
460 const header_info *hi;
461 BOOL appWantsGC;
462
463 // Environment variables can override the following.
464 if (DisableGC) {
465 _objc_inform("GC: forcing GC OFF because OBJC_DISABLE_GC is set");
466 appWantsGC = NO;
467 }
468 else {
469 // Find the executable and check its GC bits.
470 // If the executable cannot be found, default to NO.
471 // (The executable will not be found if the executable contains
472 // no Objective-C code.)
473 appWantsGC = NO;
474 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
475 if (hi->mhdr->filetype == MH_EXECUTE) {
476 appWantsGC = _objcHeaderSupportsGC(hi) ? YES : NO;
477 if (PrintGC) {
478 _objc_inform("GC: executable '%s' %s",
479 _nameForHeader(hi->mhdr), _gcForHInfo(hi));
480 }
481 }
482 }
483 }
484 return appWantsGC;
485 }
486
487 /***********************************************************************
488 * verify_gc_readiness
489 * if we want gc, verify that every header describes files compiled
490 * and presumably ready for gc.
491 ************************************************************************/
492
493 static void verify_gc_readiness(BOOL wantsGC, header_info **hList,
494 uint32_t hCount)
495 {
496 BOOL busted = NO;
497 uint32_t i;
498
499 // Find the libraries and check their GC bits against the app's request
500 for (i = 0; i < hCount; i++) {
501 header_info *hi = hList[i];
502 if (hi->mhdr->filetype == MH_EXECUTE) {
503 continue;
504 }
505 else if (hi->mhdr == &_mh_dylib_header) {
506 // libobjc itself works with anything even though it is not
507 // compiled with -fobjc-gc (fixme should it be?)
508 }
509 else if (wantsGC && ! _objcHeaderSupportsGC(hi)) {
510 // App wants GC but library does not support it - bad
511 _objc_inform_now_and_on_crash
512 ("'%s' was not compiled with -fobjc-gc or -fobjc-gc-only, "
513 "but the application requires GC",
514 _nameForHeader(hi->mhdr));
515 busted = YES;
516 }
517 else if (!wantsGC && _objcHeaderRequiresGC(hi)) {
518 // App doesn't want GC but library requires it - bad
519 _objc_inform_now_and_on_crash
520 ("'%s' was compiled with -fobjc-gc-only, "
521 "but the application does not support GC",
522 _nameForHeader(hi->mhdr));
523 busted = YES;
524 }
525
526 if (PrintGC) {
527 _objc_inform("GC: library '%s' %s",
528 _nameForHeader(hi->mhdr), _gcForHInfo(hi));
529 }
530 }
531
532 if (busted) {
533 // GC state is not consistent.
534 // Kill the process unless one of the forcing flags is set.
535 if (!DisableGC) {
536 _objc_fatal("*** GC capability of application and some libraries did not match");
537 }
538 }
539 }
540
541
542 /***********************************************************************
543 * objc_setConfiguration
544 * Read environment variables that affect the runtime.
545 * Also print environment variable help, if requested.
546 **********************************************************************/
547 static void objc_setConfiguration() {
548 int PrintHelp = (getenv("OBJC_HELP") != NULL);
549 int PrintOptions = (getenv("OBJC_PRINT_OPTIONS") != NULL);
550 int secure = issetugid();
551
552 if (secure) {
553 // All environment variables are ignored when setuid or setgid.
554 if (PrintHelp) _objc_inform("OBJC_HELP ignored when running setuid or setgid");
555 if (PrintOptions) _objc_inform("OBJC_PRINT_OPTIONS ignored when running setuid or setgid");
556 }
557 else {
558 if (PrintHelp) {
559 _objc_inform("OBJC_HELP: describe Objective-C runtime environment variables");
560 if (PrintOptions) {
561 _objc_inform("OBJC_HELP is set");
562 }
563 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
564 }
565 if (PrintOptions) {
566 _objc_inform("OBJC_PRINT_OPTIONS is set");
567 }
568 }
569
570 #define OPTION(var, env, help) \
571 if ( var == -1 ) { \
572 char *value = getenv(#env); \
573 var = value != NULL && !strcmp("YES", value); \
574 if (secure) { \
575 if (var) _objc_inform(#env " ignored when running setuid or setgid"); \
576 var = 0; \
577 } else { \
578 if (PrintHelp) _objc_inform(#env ": " help); \
579 if (PrintOptions && var) _objc_inform(#env " is set"); \
580 } \
581 }
582
583 OPTION(PrintImages, OBJC_PRINT_IMAGES,
584 "log image and library names as they are loaded");
585 OPTION(PrintLoading, OBJC_PRINT_LOAD_METHODS,
586 "log calls to class and category +load methods");
587 OPTION(PrintInitializing, OBJC_PRINT_INITIALIZE_METHODS,
588 "log calls to class +initialize methods");
589 OPTION(PrintResolving, OBJC_PRINT_RESOLVED_METHODS,
590 "log methods created by +resolveClassMethod: and +resolveInstanceMethod:");
591 OPTION(PrintConnecting, OBJC_PRINT_CLASS_SETUP,
592 "log progress of class and category setup");
593 OPTION(PrintProtocols, OBJC_PRINT_PROTOCOL_SETUP,
594 "log progresso of protocol setup");
595 OPTION(PrintIvars, OBJC_PRINT_IVAR_SETUP,
596 "log processing of non-fragile ivars");
597 OPTION(PrintFuture, OBJC_PRINT_FUTURE_CLASSES,
598 "log use of future classes for toll-free bridging");
599 OPTION(PrintRTP, OBJC_PRINT_RTP,
600 "log initialization of the Objective-C runtime pages");
601 OPTION(PrintGC, OBJC_PRINT_GC,
602 "log some GC operations");
603 OPTION(PrintSharing, OBJC_PRINT_SHARING,
604 "log cross-process memory sharing");
605 OPTION(PrintCxxCtors, OBJC_PRINT_CXX_CTORS,
606 "log calls to C++ ctors and dtors for instance variables");
607 OPTION(PrintExceptions, OBJC_PRINT_EXCEPTIONS,
608 "log exception handling");
609 OPTION(PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS,
610 "log processing of exception alt handlers");
611 OPTION(PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS,
612 "log methods replaced by category implementations");
613 OPTION(PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS,
614 "warn about calls to deprecated runtime functions");
615 OPTION(PrintCacheCollection, OBJC_PRINT_CACHE_COLLECTION,
616 "log cleanup of stale method caches");
617
618 OPTION(DebugUnload, OBJC_DEBUG_UNLOAD,
619 "warn about poorly-behaving bundles when unloaded");
620 OPTION(DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES,
621 "warn about subclasses that may have been broken by subsequent changes to superclasses");
622 OPTION(DebugFinalizers, OBJC_DEBUG_FINALIZERS,
623 "warn about classes that implement -dealloc but not -finalize");
624 OPTION(DebugNilSync, OBJC_DEBUG_NIL_SYNC,
625 "warn about @synchronized(nil), which does no synchronization");
626
627 OPTION(UseInternalZone, OBJC_USE_INTERNAL_ZONE,
628 "allocate runtime data in a dedicated malloc zone");
629 OPTION(AllowInterposing, OBJC_ALLOW_INTERPOSING,
630 "allow function interposing of objc_msgSend()");
631
632 OPTION(DisableGC, OBJC_DISABLE_GC,
633 "force GC OFF, even if the executable wants it on");
634
635 #undef OPTION
636 }
637
638
639 /***********************************************************************
640 * objc_setMultithreaded.
641 **********************************************************************/
642 void objc_setMultithreaded (BOOL flag)
643 {
644 OBJC_WARN_DEPRECATED;
645
646 // Nothing here. Thread synchronization in the runtime is always active.
647 }
648
649
650 /***********************************************************************
651 * _objc_fetch_pthread_data
652 * Fetch objc's pthread data for this thread.
653 * If the data doesn't exist yet and create is NO, return NULL.
654 * If the data doesn't exist yet and create is YES, allocate and return it.
655 **********************************************************************/
656 __private_extern__ _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
657 {
658 _objc_pthread_data *data;
659
660 data = pthread_getspecific(_objc_pthread_key);
661 if (!data && create) {
662 data = _calloc_internal(1, sizeof(_objc_pthread_data));
663 pthread_setspecific(_objc_pthread_key, data);
664 }
665
666 return data;
667 }
668
669
670 /***********************************************************************
671 * _objc_pthread_destroyspecific
672 * Destructor for objc's per-thread data.
673 * arg shouldn't be NULL, but we check anyway.
674 **********************************************************************/
675 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
676 __private_extern__ void _objc_pthread_destroyspecific(void *arg)
677 {
678 _objc_pthread_data *data = (_objc_pthread_data *)arg;
679 if (data != NULL) {
680 _destroyInitializingClassList(data->initializingClasses);
681 _destroyLockList(data->lockList);
682 _destroySyncCache(data->syncCache);
683 _destroyAltHandlerList(data->handlerList);
684
685 // add further cleanup here...
686
687 _free_internal(data);
688 }
689 }
690
691
692 /***********************************************************************
693 * _objcInit
694 * Former library initializer. This function is now merely a placeholder
695 * for external callers. All runtime initialization has now been moved
696 * to map_images() and _objc_init.
697 **********************************************************************/
698 void _objcInit(void)
699 {
700 // do nothing
701 }
702
703
704 /***********************************************************************
705 * gc_enforcer
706 * Make sure that images about to be loaded by dyld are GC-acceptable.
707 * Images linked to the executable are always permitted; they are
708 * enforced inside map_images() itself.
709 **********************************************************************/
710 static BOOL InitialDyldRegistration = NO;
711 static const char *gc_enforcer(enum dyld_image_states state,
712 uint32_t infoCount,
713 const struct dyld_image_info info[])
714 {
715 uint32_t i;
716
717 // Linked images get a free pass
718 if (InitialDyldRegistration) return NULL;
719
720 if (PrintImages) {
721 _objc_inform("IMAGES: checking %d images for compatibility...",
722 infoCount);
723 }
724
725 for (i = 0; i < infoCount; i++) {
726 const headerType *mhdr = (const headerType *)info[i].imageLoadAddress;
727 if (bad_magic(mhdr)) continue;
728
729 objc_image_info *image_info;
730 size_t size;
731
732 if (mhdr == &_mh_dylib_header) {
733 // libobjc itself - OK
734 continue;
735 }
736
737 #if !__LP64__
738 // 32-bit: __OBJC seg but no image_info means no GC support
739 if (!getsegbynamefromheader(mhdr, SEG_OBJC)) {
740 // not objc - assume OK
741 continue;
742 }
743 image_info = _getObjcImageInfo(mhdr, _getImageSlide(mhdr), &size);
744 if (!image_info) {
745 // No image_info - assume GC unsupported
746 if (!UseGC) {
747 // GC is OFF - ok
748 continue;
749 } else {
750 // GC is ON - bad
751 if (PrintImages || PrintGC) {
752 _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC (no image_info)", infoCount, info[i].imageFilePath);
753 }
754 return "GC capability mismatch";
755 }
756 }
757 #else
758 // 64-bit: no image_info means no objc at all
759 image_info = _getObjcImageInfo(mhdr, _getImageSlide(mhdr), &size);
760 if (!image_info) {
761 // not objc - assume OK
762 continue;
763 }
764 #endif
765
766 if (UseGC && !_objcInfoSupportsGC(image_info)) {
767 // GC is ON, but image does not support GC
768 if (PrintImages || PrintGC) {
769 _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC", infoCount, info[i].imageFilePath);
770 }
771 return "GC capability mismatch";
772 }
773 if (!UseGC && _objcInfoRequiresGC(image_info)) {
774 // GC is OFF, but image requires GC
775 if (PrintImages || PrintGC) {
776 _objc_inform("IMAGES: rejecting %d images because %s requires GC", infoCount, info[i].imageFilePath);
777 }
778 return "GC capability mismatch";
779 }
780 }
781
782 return NULL;
783 }
784
785
786 /***********************************************************************
787 * map_images
788 * Process the given images which are being mapped in by dyld.
789 * All class registration and fixups are performed (or deferred pending
790 * discovery of missing superclasses etc), and +load methods are called.
791 *
792 * info[] is in bottom-up order i.e. libobjc will be earlier in the
793 * array than any library that links to libobjc.
794 **********************************************************************/
795 static const char *map_images(enum dyld_image_states state, uint32_t infoCount,
796 const struct dyld_image_info infoList[])
797 {
798 static BOOL firstTime = YES;
799 static BOOL wantsGC NOBSS = NO;
800 uint32_t i;
801 header_info *hInfo;
802 header_info *hList[infoCount];
803 uint32_t hCount;
804
805 // Perform first-time initialization if necessary.
806 // This function is called before ordinary library initializers.
807 if (firstTime) {
808 extern SEL FwdSel; // in objc-msg-*.s
809 // workaround for rdar://5198739
810 pthread_key_t unused;
811 pthread_key_create(&unused, NULL);
812 pthread_key_create(&_objc_pthread_key, _objc_pthread_destroyspecific);
813 objc_setConfiguration(); // read environment variables
814 // grab selectors for which @selector() doesn't work
815 cxx_construct_sel = sel_registerName(cxx_construct_name);
816 cxx_destruct_sel = sel_registerName(cxx_destruct_name);
817 FwdSel = sel_registerName("forward::"); // in objc-msg-*.s
818 exception_init();
819
820 InitialDyldRegistration = YES;
821 dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* batch */, &gc_enforcer);
822 InitialDyldRegistration = NO;
823 }
824
825 if (PrintImages) {
826 _objc_inform("IMAGES: processing %u newly-mapped images...\n", infoCount);
827 }
828
829
830 // Find all images with Objective-C metadata.
831 hCount = 0;
832 i = infoCount;
833 while (i--) {
834 const headerType *mhdr = (headerType *)infoList[i].imageLoadAddress;
835 if (bad_magic(mhdr)) continue;
836
837 hInfo = _objc_addHeader(mhdr);
838 if (!hInfo) {
839 // no objc data in this entry
840 continue;
841 }
842
843 hList[hCount++] = hInfo;
844
845 if (PrintImages) {
846 _objc_inform("IMAGES: loading image for %s%s%s%s\n",
847 _nameForHeader(mhdr),
848 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
849 _objcHeaderIsReplacement(hInfo) ? " (replacement)":"",
850 _gcForHInfo2(hInfo));
851 }
852 }
853
854 // Perform one-time runtime initialization that must be deferred until
855 // the executable itself is found. This needs to be done before
856 // further initialization.
857 // (The executable may not be present in this infoList if the
858 // executable does not contain Objective-C code but Objective-C
859 // is dynamically loaded later. In that case, check_wants_gc()
860 // will do the right thing.)
861 if (firstTime) {
862 wantsGC = check_wants_gc();
863
864 verify_gc_readiness(wantsGC, hList, hCount);
865
866 gc_init(wantsGC); // needs executable for GC decision
867 rtp_init(); // needs GC decision first
868 } else {
869 verify_gc_readiness(wantsGC, hList, hCount);
870 }
871
872 _read_images(hList, hCount);
873
874 firstTime = NO;
875
876 return NULL;
877 }
878
879
880 static const char *load_images(enum dyld_image_states state,uint32_t infoCount,
881 const struct dyld_image_info infoList[])
882 {
883 BOOL found = NO;
884 uint32_t i;
885
886 i = infoCount;
887 while (i--) {
888 header_info *hi;
889 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
890 const headerType *mhdr = (headerType*)infoList[i].imageLoadAddress;
891 if (hi->mhdr == mhdr) {
892 prepare_load_methods(hi);
893 found = YES;
894 }
895 }
896 }
897
898 if (found) call_load_methods();
899
900 return NULL;
901 }
902
903 /***********************************************************************
904 * unmap_image
905 * Process the given image which is about to be unmapped by dyld.
906 * mh is mach_header instead of headerType because that's what
907 * dyld_priv.h says even for 64-bit.
908 **********************************************************************/
909 static void unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide)
910 {
911 if (PrintImages) {
912 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
913 }
914
915 header_info *hi;
916
917 // Find the runtime's header_info struct for the image
918 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
919 if (hi->mhdr == (const headerType *)mh) {
920 _objc_unmap_image(hi);
921 return;
922 }
923 }
924
925 // no objc data for this image
926 }
927
928
929 /***********************************************************************
930 * _objc_init
931 * Static initializer. Registers our image notifier with dyld.
932 * fixme move map_images' firstTime code here - but GC code might need
933 * another earlier image notifier
934 **********************************************************************/
935 static __attribute__((constructor))
936 void _objc_init(void)
937 {
938 // Register for unmap first, in case some +load unmaps something
939 _dyld_register_func_for_remove_image(&unmap_image);
940 dyld_register_image_state_change_handler(dyld_image_state_bound,
941 1/*batch*/, &map_images);
942 dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized, 0/*not batch*/, &load_images);
943 }
944
945
946 /***********************************************************************
947 * _objc_unmap_image.
948 * Destroy any Objective-C data for the given image, which is about to
949 * be unloaded by dyld.
950 * Note: not thread-safe, but image loading isn't either.
951 **********************************************************************/
952 static void _objc_unmap_image(header_info *hi)
953 {
954 if (PrintImages) {
955 _objc_inform("IMAGES: unloading image for %s%s%s%s\n",
956 _nameForHeader(hi->mhdr),
957 hi->mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
958 _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
959 _gcForHInfo2(hi));
960 }
961
962 _unload_image(hi);
963
964 // Remove header_info from header list
965 _objc_removeHeader(hi);
966 }
967
968
969 /***********************************************************************
970 * _objc_setNilReceiver
971 **********************************************************************/
972 id _objc_setNilReceiver(id newNilReceiver)
973 {
974 id oldNilReceiver;
975
976 oldNilReceiver = _objc_nilReceiver;
977 _objc_nilReceiver = newNilReceiver;
978
979 return oldNilReceiver;
980 }
981
982 /***********************************************************************
983 * _objc_getNilReceiver
984 **********************************************************************/
985 id _objc_getNilReceiver(void)
986 {
987 return _objc_nilReceiver;
988 }
989
990
991 /***********************************************************************
992 * objc_setForwardHandler
993 **********************************************************************/
994 void objc_setForwardHandler(void *fwd, void *fwd_stret)
995 {
996 _objc_forward_handler = fwd;
997 _objc_forward_stret_handler = fwd_stret;
998 }
999
1000
1001 #if defined(__ppc__) || defined(__ppc64__)
1002
1003 // Test to see if either the displacement or destination is within
1004 // the +/- 2^25 range needed for a PPC branch immediate instruction.
1005 // Shifting the high bit of the displacement (or destination)
1006 // left 6 bits and then 6 bits arithmetically to the right does a
1007 // sign extend of the 26th bit. If that result is equivalent to the
1008 // original value, then the displacement (or destination) will fit
1009 // into a simple branch. Otherwise a larger branch sequence is required.
1010 // ppc64: max displacement is still +/- 2^25, but intptr_t is bigger
1011
1012 // tiny: bc*
1013 // small: b, ba (unconditional only)
1014 // 32: bctr with lis+ori only
1015 static BOOL ppc_tiny_displacement(intptr_t displacement)
1016 {
1017 size_t shift = sizeof(intptr_t) - 16; // ilp32=16, lp64=48
1018 return (((displacement << shift) >> shift) == displacement);
1019 }
1020
1021 static BOOL ppc_small_displacement(intptr_t displacement)
1022 {
1023 size_t shift = sizeof(intptr_t) - 26; // ilp32=6, lp64=38
1024 return (((displacement << shift) >> shift) == displacement);
1025 }
1026
1027 #if defined(__ppc64__)
1028 // Same as ppc_small_displacement, but decides whether 32 bits is big enough.
1029 static BOOL ppc_32bit_displacement(intptr_t displacement)
1030 {
1031 size_t shift = sizeof(intptr_t) - 32;
1032 return (((displacement << shift) >> shift) == displacement);
1033 }
1034 #endif
1035
1036 /**********************************************************************
1037 * objc_branch_size
1038 * Returns the number of instructions needed
1039 * for a branch from entry to target.
1040 **********************************************************************/
1041 __private_extern__ size_t objc_branch_size(void *entry, void *target)
1042 {
1043 return objc_cond_branch_size(entry, target, COND_ALWAYS);
1044 }
1045
1046 __private_extern__ size_t
1047 objc_cond_branch_size(void *entry, void *target, unsigned cond)
1048 {
1049 intptr_t destination = (intptr_t)target;
1050 intptr_t displacement = (intptr_t)destination - (intptr_t)entry;
1051
1052 if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
1053 // fits in unconditional relative branch immediate
1054 return 1;
1055 }
1056 if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
1057 // fits in unconditional absolute branch immediate
1058 return 1;
1059 }
1060 if (ppc_tiny_displacement(displacement)) {
1061 // fits in conditional relative branch immediate
1062 return 1;
1063 }
1064 if (ppc_tiny_displacement(destination)) {
1065 // fits in conditional absolute branch immediate
1066 return 1;
1067 }
1068 #if defined(__ppc64__)
1069 if (!ppc_32bit_displacement(destination)) {
1070 // fits in 64-bit absolute branch through CTR
1071 return 7;
1072 }
1073 #endif
1074
1075 // fits in 32-bit absolute branch through CTR
1076 return 4;
1077 }
1078
1079 /**********************************************************************
1080 * objc_write_branch
1081 * Writes at entry a PPC branch instruction sequence that branches to target.
1082 * The sequence written will be objc_branch_size(entry, target) instructions.
1083 * Returns the number of instructions written.
1084 **********************************************************************/
1085 __private_extern__ size_t objc_write_branch(void *entry, void *target)
1086 {
1087 return objc_write_cond_branch(entry, target, COND_ALWAYS);
1088 }
1089
1090 __private_extern__ size_t
1091 objc_write_cond_branch(void *entry, void *target, unsigned cond)
1092 {
1093 unsigned *address = (unsigned *)entry; // location to store the 32 bit PPC instructions
1094 intptr_t destination = (intptr_t)target; // destination as an absolute address
1095 intptr_t displacement = (intptr_t)destination - (intptr_t)address; // destination as a branch relative offset
1096
1097 if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
1098 // use unconditional relative branch with the displacement
1099 address[0] = 0x48000000 | (unsigned)(displacement & 0x03fffffc); // b *+displacement
1100 // issued 1 instruction
1101 return 1;
1102 }
1103 if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
1104 // use unconditional absolute branch with the destination
1105 address[0] = 0x48000000 | (unsigned)(destination & 0x03fffffc) | 2; // ba destination (2 is the absolute flag)
1106 // issued 1 instruction
1107 return 1;
1108 }
1109
1110 if (ppc_tiny_displacement(displacement)) {
1111 // use conditional relative branch with the displacement
1112 address[0] = 0x40000000 | cond | (unsigned)(displacement & 0x0000fffc); // b *+displacement
1113 // issued 1 instruction
1114 return 1;
1115 }
1116 if (ppc_tiny_displacement(destination)) {
1117 // use conditional absolute branch with the destination
1118 address[0] = 0x40000000 | cond | (unsigned)(destination & 0x0000fffc) | 2; // ba destination (2 is the absolute flag)
1119 // issued 1 instruction
1120 return 1;
1121 }
1122
1123
1124 // destination is large and far away.
1125 // Use an absolute branch via CTR.
1126
1127 #if defined(__ppc64__)
1128 if (!ppc_32bit_displacement(destination)) {
1129 uint16_t lo = destination & 0xffff;
1130 uint16_t hi = (destination >> 16) & 0xffff;
1131 uint16_t hi2 = (destination >> 32) & 0xffff;
1132 uint16_t hi3 = (destination >> 48) & 0xffff;
1133
1134 address[0] = 0x3d800000 | hi3; // lis r12, hi3
1135 address[1] = 0x618c0000 | hi2; // ori r12, r12, hi2
1136 address[2] = 0x798c07c6; // sldi r12, r12, 32
1137 address[3] = 0x658c0000 | hi; // oris r12, r12, hi
1138 address[4] = 0x618c0000 | lo; // ori r12, r12, lo
1139 address[5] = 0x7d8903a6; // mtctr r12
1140 address[6] = 0x4c000420 | cond; // bctr
1141 // issued 7 instructions
1142 return 7;
1143 }
1144 #endif
1145
1146 {
1147 uint16_t lo = destination & 0xffff;
1148 uint16_t hi = (destination >> 16) & 0xffff;
1149
1150 address[0] = 0x3d800000 | hi; // lis r12,hi
1151 address[1] = 0x618c0000 | lo; // ori r12,r12,lo
1152 address[2] = 0x7d8903a6; // mtctr r12
1153 address[3] = 0x4c000420 | cond; // bctr
1154 // issued 4 instructions
1155 return 4;
1156 }
1157 }
1158
1159 // defined(__ppc__) || defined(__ppc64__)
1160 #endif
1161
1162 #if defined(__i386__) || defined(__x86_64__)
1163
1164 /**********************************************************************
1165 * objc_branch_size
1166 * Returns the number of BYTES needed
1167 * for a branch from entry to target.
1168 **********************************************************************/
1169 __private_extern__ size_t objc_branch_size(void *entry, void *target)
1170 {
1171 return objc_cond_branch_size(entry, target, COND_ALWAYS);
1172 }
1173
1174 __private_extern__ size_t
1175 objc_cond_branch_size(void *entry, void *target, unsigned cond)
1176 {
1177 // For simplicity, always use 32-bit relative jumps.
1178 if (cond == COND_ALWAYS) return 5;
1179 else return 6;
1180 }
1181
1182 /**********************************************************************
1183 * objc_write_branch
1184 * Writes at entry an i386 branch instruction sequence that branches to target.
1185 * The sequence written will be objc_branch_size(entry, target) BYTES.
1186 * Returns the number of BYTES written.
1187 **********************************************************************/
1188 __private_extern__ size_t objc_write_branch(void *entry, void *target)
1189 {
1190 return objc_write_cond_branch(entry, target, COND_ALWAYS);
1191 }
1192
1193 __private_extern__ size_t
1194 objc_write_cond_branch(void *entry, void *target, unsigned cond)
1195 {
1196 uint8_t *address = (uint8_t *)entry; // instructions written to here
1197 intptr_t destination = (intptr_t)target; // branch dest as absolute address
1198 intptr_t displacement = (intptr_t)destination - ((intptr_t)address + objc_cond_branch_size(entry, target, cond)); // branch dest as relative offset
1199
1200 // For simplicity, always use 32-bit relative jumps
1201 if (cond != COND_ALWAYS) {
1202 *address++ = 0x0f; // Jcc prefix
1203 }
1204 *address++ = cond;
1205 *address++ = displacement & 0xff;
1206 *address++ = (displacement >> 8) & 0xff;
1207 *address++ = (displacement >> 16) & 0xff;
1208 *address++ = (displacement >> 24) & 0xff;
1209
1210 return address - (uint8_t *)entry;
1211 }
1212
1213 // defined __i386__
1214 #endif
1215
1216
1217 /**********************************************************************
1218 * secure_open
1219 * Securely open a file from a world-writable directory (like /tmp)
1220 * If the file does not exist, it will be atomically created with mode 0600
1221 * If the file exists, it must be, and remain after opening:
1222 * 1. a regular file (in particular, not a symlink)
1223 * 2. owned by euid
1224 * 3. permissions 0600
1225 * 4. link count == 1
1226 * Returns a file descriptor or -1. Errno may or may not be set on error.
1227 **********************************************************************/
1228 __private_extern__ int secure_open(const char *filename, int flags, uid_t euid)
1229 {
1230 struct stat fs, ls;
1231 int fd = -1;
1232 BOOL truncate = NO;
1233 BOOL create = NO;
1234
1235 if (flags & O_TRUNC) {
1236 // Don't truncate the file until after it is open and verified.
1237 truncate = YES;
1238 flags &= ~O_TRUNC;
1239 }
1240 if (flags & O_CREAT) {
1241 // Don't create except when we're ready for it
1242 create = YES;
1243 flags &= ~O_CREAT;
1244 flags &= ~O_EXCL;
1245 }
1246
1247 if (lstat(filename, &ls) < 0) {
1248 if (errno == ENOENT && create) {
1249 // No such file - create it
1250 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
1251 if (fd >= 0) {
1252 // File was created successfully.
1253 // New file does not need to be truncated.
1254 return fd;
1255 } else {
1256 // File creation failed.
1257 return -1;
1258 }
1259 } else {
1260 // lstat failed, or user doesn't want to create the file
1261 return -1;
1262 }
1263 } else {
1264 // lstat succeeded - verify attributes and open
1265 if (S_ISREG(ls.st_mode) && // regular file?
1266 ls.st_nlink == 1 && // link count == 1?
1267 ls.st_uid == euid && // owned by euid?
1268 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
1269 {
1270 // Attributes look ok - open it and check attributes again
1271 fd = open(filename, flags, 0000);
1272 if (fd >= 0) {
1273 // File is open - double-check attributes
1274 if (0 == fstat(fd, &fs) &&
1275 fs.st_nlink == ls.st_nlink && // link count == 1?
1276 fs.st_uid == ls.st_uid && // owned by euid?
1277 fs.st_mode == ls.st_mode && // regular file, 0600?
1278 fs.st_ino == ls.st_ino && // same inode as before?
1279 fs.st_dev == ls.st_dev) // same device as before?
1280 {
1281 // File is open and OK
1282 if (truncate) ftruncate(fd, 0);
1283 return fd;
1284 } else {
1285 // Opened file looks funny - close it
1286 close(fd);
1287 return -1;
1288 }
1289 } else {
1290 // File didn't open
1291 return -1;
1292 }
1293 } else {
1294 // Unopened file looks funny - don't open it
1295 return -1;
1296 }
1297 }
1298 }
1299
1300
1301 #if !__OBJC2__
1302 // GrP fixme
1303 extern Class _objc_getOrigClass(const char *name);
1304 #endif
1305 const char *class_getImageName(Class cls)
1306 {
1307 int ok;
1308 Dl_info info;
1309
1310 if (!cls) return NULL;
1311
1312 #if !__OBJC2__
1313 cls = _objc_getOrigClass(_class_getName(cls));
1314 #endif
1315
1316 ok = dladdr(cls, &info);
1317 if (ok) return info.dli_fname;
1318 else return NULL;
1319 }
1320
1321
1322 const char **objc_copyImageNames(unsigned int *outCount)
1323 {
1324 header_info *hi;
1325 int count = 0;
1326 int max = HeaderCount;
1327 const char **names = calloc(max+1, sizeof(char *));
1328
1329 for (hi = _objc_headerStart();
1330 hi != NULL && count < max;
1331 hi = hi->next)
1332 {
1333 if (hi->dl_info.dli_fname) {
1334 names[count++] = hi->dl_info.dli_fname;
1335 }
1336 }
1337 names[count] = NULL;
1338
1339 if (count == 0) {
1340 // Return NULL instead of empty list if there are no images
1341 free(names);
1342 names = NULL;
1343 }
1344
1345 if (outCount) *outCount = count;
1346 return names;
1347 }
1348
1349
1350 /**********************************************************************
1351 *
1352 **********************************************************************/
1353 const char **
1354 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
1355 {
1356 header_info *hi;
1357
1358 if (!image) {
1359 if (outCount) *outCount = 0;
1360 return NULL;
1361 }
1362
1363 // Find the image.
1364 for (hi = _objc_headerStart(); hi != NULL; hi = hi->next) {
1365 if (0 == strcmp(image, hi->dl_info.dli_fname)) break;
1366 }
1367
1368 if (!hi) {
1369 if (outCount) *outCount = 0;
1370 return NULL;
1371 }
1372
1373 return _objc_copyClassNamesForImage(hi, outCount);
1374 }
1375
1376
1377 /**********************************************************************
1378 * Fast Enumeration Support
1379 **********************************************************************/
1380
1381 static void (*enumerationMutationHandler)(id);
1382
1383 /**********************************************************************
1384 * objc_enumerationMutation
1385 * called by compiler when a mutation is detected during foreach iteration
1386 **********************************************************************/
1387 void objc_enumerationMutation(id object) {
1388 if (enumerationMutationHandler == nil) {
1389 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", object);
1390 }
1391 (*enumerationMutationHandler)(object);
1392 }
1393
1394
1395 /**********************************************************************
1396 * objc_setEnumerationMutationHandler
1397 * an entry point to customize mutation error handing
1398 **********************************************************************/
1399 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
1400 enumerationMutationHandler = handler;
1401 }