]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-os.mm
objc4-646.tar.gz
[apple/objc4.git] / runtime / objc-os.mm
CommitLineData
7af964d1
A
1/*
2 * Copyright (c) 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/***********************************************************************
25* objc-os.m
26* OS portability layer.
27**********************************************************************/
28
7af964d1
A
29#include "objc-private.h"
30#include "objc-loadmethod.h"
31
32#if TARGET_OS_WIN32
33
8972963c 34#include "objc-runtime-old.h"
7af964d1
A
35#include "objcrt.h"
36
37malloc_zone_t *_objc_internal_zone(void)
38{
39 return NULL;
40}
41
42int monitor_init(monitor_t *c)
43{
44 // fixme error checking
45 HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
46 while (!c->mutex) {
47 // fixme memory barrier here?
48 if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
49 // we win - finish construction
50 c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
51 c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
52 InitializeCriticalSection(&c->waitCountLock);
53 c->waitCount = 0;
54 c->didBroadcast = 0;
55 ReleaseMutex(c->mutex);
56 return 0;
57 }
58 }
59
60 // someone else allocated the mutex and constructed the monitor
61 ReleaseMutex(mutex);
62 CloseHandle(mutex);
63 return 0;
64}
65
66void mutex_init(mutex_t *m)
67{
68 while (!m->lock) {
69 CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
70 InitializeCriticalSection(newlock);
71 // fixme memory barrier here?
72 if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
73 return;
74 }
75 // someone else installed their lock first
76 DeleteCriticalSection(newlock);
77 free(newlock);
78 }
79}
80
81
82void recursive_mutex_init(recursive_mutex_t *m)
83{
84 // fixme error checking
85 HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
86 while (!m->mutex) {
87 // fixme memory barrier here?
88 if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
89 // we win
90 return;
91 }
92 }
93
94 // someone else installed their lock first
95 CloseHandle(newmutex);
96}
97
98
99WINBOOL APIENTRY DllMain( HMODULE hModule,
100 DWORD ul_reason_for_call,
101 LPVOID lpReserved
102 )
103{
104 switch (ul_reason_for_call) {
105 case DLL_PROCESS_ATTACH:
106 environ_init();
107 tls_init();
108 lock_init();
cd5f04f5
A
109 sel_init(NO, 3500); // old selector heuristic
110 exception_init();
7af964d1
A
111 break;
112
113 case DLL_THREAD_ATTACH:
114 break;
115
116 case DLL_THREAD_DETACH:
117 case DLL_PROCESS_DETACH:
118 break;
119 }
120 return TRUE;
121}
122
123OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
124{
125 header_info *hi = _malloc_internal(sizeof(header_info));
126 size_t count, i;
127
128 hi->mhdr = (const headerType *)image;
129 hi->info = sects->iiStart;
130 hi->allClassesRealized = NO;
cd5f04f5
A
131 hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
132 hi->moduleCount = (Module *)sects->modEnd - hi->modules;
133 hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
134 hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;
135 hi->imageinfo = NULL;
136 hi->imageinfoBytes = 0;
137 // hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
138// hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;
139 hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
140 hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;
141 hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
142 hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;
7af964d1
A
143
144 count = 0;
cd5f04f5
A
145 for (i = 0; i < hi->moduleCount; i++) {
146 if (hi->modules[i]) count++;
7af964d1
A
147 }
148 hi->mod_count = 0;
149 hi->mod_ptr = 0;
150 if (count > 0) {
151 hi->mod_ptr = malloc(count * sizeof(struct objc_module));
cd5f04f5
A
152 for (i = 0; i < hi->moduleCount; i++) {
153 if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));
7af964d1
A
154 }
155 }
8972963c 156
cd5f04f5
A
157 hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
158 GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
7af964d1 159
cd5f04f5 160 appendHeader(hi);
7af964d1
A
161
162 if (PrintImages) {
163 _objc_inform("IMAGES: loading image for %s%s%s\n",
cd5f04f5 164 hi->fname,
7af964d1
A
165 headerIsBundle(hi) ? " (bundle)" : "",
166 _objcHeaderIsReplacement(hi) ? " (replacement)":"");
167 }
168
169 _read_images(&hi, 1);
170
171 return hi;
172}
173
174OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
175{
176 prepare_load_methods(hinfo);
177 call_load_methods();
178}
179
180OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
181{
182 _objc_fatal("image unload not supported");
183}
184
185
cd5f04f5 186bool crashlog_header_name(header_info *hi)
8972963c
A
187{
188 return true;
189}
190
191
7af964d1
A
192// TARGET_OS_WIN32
193#elif TARGET_OS_MAC
194
8972963c 195#include "objc-file-old.h"
7257e56c 196#include "objc-file.h"
8972963c 197
cd5f04f5 198void mutex_init(mutex_t *m)
7af964d1
A
199{
200 pthread_mutex_init(m, NULL);
201}
202
203
cd5f04f5 204void recursive_mutex_init(recursive_mutex_t *m)
7af964d1
A
205{
206 // fixme error checking
207 pthread_mutex_t *newmutex;
208
209 // Build recursive mutex attributes, if needed
210 static pthread_mutexattr_t *attr;
211 if (!attr) {
cd5f04f5 212 pthread_mutexattr_t *newattr = (pthread_mutexattr_t *)
7af964d1
A
213 _malloc_internal(sizeof(pthread_mutexattr_t));
214 pthread_mutexattr_init(newattr);
215 pthread_mutexattr_settype(newattr, PTHREAD_MUTEX_RECURSIVE);
216 while (!attr) {
217 if (OSAtomicCompareAndSwapPtrBarrier(0, newattr, (void**)&attr)) {
218 // we win
219 goto attr_done;
220 }
221 }
222 // someone else built the attr first
223 _free_internal(newattr);
224 }
225 attr_done:
226
227 // Build the mutex itself
cd5f04f5 228 newmutex = (pthread_mutex_t *)_malloc_internal(sizeof(pthread_mutex_t));
7af964d1
A
229 pthread_mutex_init(newmutex, attr);
230 while (!m->mutex) {
231 if (OSAtomicCompareAndSwapPtrBarrier(0, newmutex, (void**)&m->mutex)) {
232 // we win
233 return;
234 }
235 }
236
237 // someone else installed their mutex first
238 pthread_mutex_destroy(newmutex);
239}
240
241
242/***********************************************************************
243* bad_magic.
244* Return YES if the header has invalid Mach-o magic.
245**********************************************************************/
cd5f04f5 246BOOL bad_magic(const headerType *mhdr)
7af964d1
A
247{
248 return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
249 mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
250}
251
252
cd5f04f5 253static header_info * addHeader(const headerType *mhdr)
7af964d1 254{
cd5f04f5 255 header_info *hi;
7af964d1
A
256
257 if (bad_magic(mhdr)) return NULL;
258
cd5f04f5
A
259#if __OBJC2__
260 // Look for hinfo from the dyld shared cache.
261 hi = preoptimizedHinfoForHeader(mhdr);
262 if (hi) {
263 // Found an hinfo in the dyld shared cache.
264
265 // Weed out duplicates.
266 if (hi->loaded) {
267 return NULL;
268 }
269
270 // Initialize fields not set by the shared cache
271 // hi->next is set by appendHeader
272 hi->fname = dyld_image_path_containing_address(hi->mhdr);
273 hi->loaded = true;
274 hi->inSharedCache = true;
275
276 if (PrintPreopt) {
277 _objc_inform("PREOPTIMIZATION: honoring preoptimized header info at %p for %s", hi, hi->fname);
278 }
279
280# if !NDEBUG
281 // Verify image_info
282 size_t info_size = 0;
283 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
284 assert(image_info == hi->info);
285# endif
7af964d1 286 }
cd5f04f5
A
287 else
288#endif
289 {
290 // Didn't find an hinfo in the dyld shared cache.
7af964d1 291
cd5f04f5
A
292 // Weed out duplicates
293 for (hi = FirstHeader; hi; hi = hi->next) {
294 if (mhdr == hi->mhdr) return NULL;
295 }
7af964d1 296
cd5f04f5
A
297 // Locate the __OBJC segment
298 size_t info_size = 0;
299 unsigned long seg_size;
300 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
301 const uint8_t *objc_segment = getsegmentdata(mhdr,SEG_OBJC,&seg_size);
302 if (!objc_segment && !image_info) return NULL;
7af964d1 303
cd5f04f5
A
304 // Allocate a header_info entry.
305 hi = (header_info *)_calloc_internal(sizeof(header_info), 1);
306
307 // Set up the new header_info entry.
308 hi->mhdr = mhdr;
7af964d1 309#if !__OBJC2__
cd5f04f5
A
310 // mhdr must already be set
311 hi->mod_count = 0;
312 hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);
7af964d1 313#endif
cd5f04f5
A
314 hi->info = image_info;
315 hi->fname = dyld_image_path_containing_address(hi->mhdr);
316 hi->loaded = true;
317 hi->inSharedCache = false;
318 hi->allClassesRealized = NO;
319 }
7af964d1
A
320
321 // dylibs are not allowed to unload
322 // ...except those with image_info and nothing else (5359412)
cd5f04f5
A
323 if (hi->mhdr->filetype == MH_DYLIB && _hasObjcContents(hi)) {
324 dlopen(hi->fname, RTLD_NOLOAD);
7af964d1
A
325 }
326
cd5f04f5 327 appendHeader(hi);
7af964d1 328
cd5f04f5 329 return hi;
7af964d1
A
330}
331
332
8972963c
A
333#if !SUPPORT_GC
334
cd5f04f5 335const char *_gcForHInfo(const header_info *hinfo)
8972963c
A
336{
337 return "";
338}
cd5f04f5 339const char *_gcForHInfo2(const header_info *hinfo)
8972963c
A
340{
341 return "";
342}
343
344#else
7af964d1
A
345
346/***********************************************************************
347* _gcForHInfo.
348**********************************************************************/
cd5f04f5 349const char *_gcForHInfo(const header_info *hinfo)
7af964d1 350{
8972963c 351 if (_objcHeaderRequiresGC(hinfo)) {
7257e56c 352 return "requires GC";
8972963c 353 } else if (_objcHeaderSupportsGC(hinfo)) {
7257e56c 354 return "supports GC";
8972963c
A
355 } else {
356 return "does not support GC";
357 }
7af964d1 358}
cd5f04f5 359const char *_gcForHInfo2(const header_info *hinfo)
7af964d1 360{
8972963c 361 if (_objcHeaderRequiresGC(hinfo)) {
7257e56c 362 return "(requires GC)";
8972963c 363 } else if (_objcHeaderSupportsGC(hinfo)) {
7257e56c 364 return "(supports GC)";
8972963c
A
365 }
366 return "";
7af964d1
A
367}
368
369
7257e56c
A
370/***********************************************************************
371* linksToLibrary
372* Returns true if the image links directly to a dylib whose install name
373* is exactly the given name.
374**********************************************************************/
375bool
376linksToLibrary(const header_info *hi, const char *name)
377{
378 const struct dylib_command *cmd;
379 unsigned long i;
380
381 cmd = (const struct dylib_command *) (hi->mhdr + 1);
382 for (i = 0; i < hi->mhdr->ncmds; i++) {
383 if (cmd->cmd == LC_LOAD_DYLIB || cmd->cmd == LC_LOAD_UPWARD_DYLIB ||
384 cmd->cmd == LC_LOAD_WEAK_DYLIB || cmd->cmd == LC_REEXPORT_DYLIB)
385 {
386 const char *dylib = cmd->dylib.name.offset + (const char *)cmd;
387 if (0 == strcmp(dylib, name)) return true;
388 }
389 cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);
390 }
391
392 return false;
393}
394
395
7af964d1
A
396/***********************************************************************
397* check_gc
398* Check whether the executable supports or requires GC, and make sure
399* all already-loaded libraries support the executable's GC mode.
400* Returns TRUE if the executable wants GC on.
401**********************************************************************/
7257e56c 402static void check_wants_gc(BOOL *appWantsGC)
7af964d1
A
403{
404 const header_info *hi;
7af964d1
A
405
406 // Environment variables can override the following.
407 if (DisableGC) {
cd5f04f5 408 _objc_inform_on_crash("GC: forcing GC OFF because OBJC_DISABLE_GC is set");
8972963c 409 *appWantsGC = NO;
7af964d1
A
410 }
411 else {
412 // Find the executable and check its GC bits.
413 // If the executable cannot be found, default to NO.
414 // (The executable will not be found if the executable contains
415 // no Objective-C code.)
8972963c 416 *appWantsGC = NO;
7af964d1
A
417 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
418 if (hi->mhdr->filetype == MH_EXECUTE) {
8972963c 419 *appWantsGC = _objcHeaderSupportsGC(hi) ? YES : NO;
7257e56c 420
7af964d1
A
421 if (PrintGC) {
422 _objc_inform("GC: executable '%s' %s",
cd5f04f5 423 hi->fname, _gcForHInfo(hi));
7af964d1 424 }
7257e56c
A
425
426 if (*appWantsGC) {
427 // Exception: AppleScriptObjC apps run without GC in 10.9+
428 // 1. executable defines no classes
429 // 2. executable references NSBundle only
430 // 3. executable links to AppleScriptObjC.framework
431 size_t classcount = 0;
432 size_t refcount = 0;
433#if __OBJC2__
434 _getObjc2ClassList(hi, &classcount);
435 _getObjc2ClassRefs(hi, &refcount);
436#else
437 if (hi->mod_count == 0 || (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;
438 else classcount = 1;
439 _getObjcClassRefs(hi, &refcount);
440#endif
441 if (classcount == 0 && refcount == 1 &&
442 linksToLibrary(hi, "/System/Library/Frameworks"
443 "/AppleScriptObjC.framework/Versions/A"
444 "/AppleScriptObjC"))
445 {
446 *appWantsGC = NO;
447 if (PrintGC) {
448 _objc_inform("GC: forcing GC OFF because this is "
449 "a trivial AppleScriptObjC app");
450 }
451 }
452 }
7af964d1
A
453 }
454 }
455 }
7af964d1
A
456}
457
458
459/***********************************************************************
460* verify_gc_readiness
461* if we want gc, verify that every header describes files compiled
462* and presumably ready for gc.
463************************************************************************/
7257e56c 464static void verify_gc_readiness(BOOL wantsGC,
8972963c 465 header_info **hList, uint32_t hCount)
7af964d1
A
466{
467 BOOL busted = NO;
468 uint32_t i;
469
470 // Find the libraries and check their GC bits against the app's request
471 for (i = 0; i < hCount; i++) {
472 header_info *hi = hList[i];
473 if (hi->mhdr->filetype == MH_EXECUTE) {
474 continue;
475 }
476 else if (hi->mhdr == &_mh_dylib_header) {
477 // libobjc itself works with anything even though it is not
478 // compiled with -fobjc-gc (fixme should it be?)
479 }
480 else if (wantsGC && ! _objcHeaderSupportsGC(hi)) {
481 // App wants GC but library does not support it - bad
482 _objc_inform_now_and_on_crash
483 ("'%s' was not compiled with -fobjc-gc or -fobjc-gc-only, "
484 "but the application requires GC",
cd5f04f5 485 hi->fname);
7af964d1
A
486 busted = YES;
487 }
488 else if (!wantsGC && _objcHeaderRequiresGC(hi)) {
489 // App doesn't want GC but library requires it - bad
490 _objc_inform_now_and_on_crash
491 ("'%s' was compiled with -fobjc-gc-only, "
492 "but the application does not support GC",
cd5f04f5 493 hi->fname);
7af964d1
A
494 busted = YES;
495 }
8972963c 496
7af964d1
A
497 if (PrintGC) {
498 _objc_inform("GC: library '%s' %s",
cd5f04f5 499 hi->fname, _gcForHInfo(hi));
7af964d1
A
500 }
501 }
502
503 if (busted) {
504 // GC state is not consistent.
505 // Kill the process unless one of the forcing flags is set.
506 if (!DisableGC) {
507 _objc_fatal("*** GC capability of application and some libraries did not match");
508 }
509 }
510}
511
512
513/***********************************************************************
514* gc_enforcer
515* Make sure that images about to be loaded by dyld are GC-acceptable.
516* Images linked to the executable are always permitted; they are
517* enforced inside map_images() itself.
518**********************************************************************/
519static BOOL InitialDyldRegistration = NO;
520static const char *gc_enforcer(enum dyld_image_states state,
521 uint32_t infoCount,
522 const struct dyld_image_info info[])
523{
524 uint32_t i;
525
526 // Linked images get a free pass
527 if (InitialDyldRegistration) return NULL;
528
529 if (PrintImages) {
530 _objc_inform("IMAGES: checking %d images for compatibility...",
531 infoCount);
532 }
533
534 for (i = 0; i < infoCount; i++) {
8972963c
A
535 crashlog_header_name_string(info[i].imageFilePath);
536
7af964d1
A
537 const headerType *mhdr = (const headerType *)info[i].imageLoadAddress;
538 if (bad_magic(mhdr)) continue;
539
540 objc_image_info *image_info;
541 size_t size;
542
543 if (mhdr == &_mh_dylib_header) {
544 // libobjc itself - OK
545 continue;
546 }
547
548#if !__OBJC2__
8972963c 549 unsigned long seg_size;
7af964d1 550 // 32-bit: __OBJC seg but no image_info means no GC support
8972963c 551 if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
7af964d1
A
552 // not objc - assume OK
553 continue;
554 }
8972963c 555 image_info = _getObjcImageInfo(mhdr, &size);
7af964d1
A
556 if (!image_info) {
557 // No image_info - assume GC unsupported
558 if (!UseGC) {
559 // GC is OFF - ok
560 continue;
561 } else {
562 // GC is ON - bad
563 if (PrintImages || PrintGC) {
564 _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC (no image_info)", infoCount, info[i].imageFilePath);
565 }
8972963c 566 goto reject;
7af964d1
A
567 }
568 }
569#else
570 // 64-bit: no image_info means no objc at all
8972963c 571 image_info = _getObjcImageInfo(mhdr, &size);
7af964d1
A
572 if (!image_info) {
573 // not objc - assume OK
574 continue;
575 }
576#endif
577
578 if (UseGC && !_objcInfoSupportsGC(image_info)) {
579 // GC is ON, but image does not support GC
580 if (PrintImages || PrintGC) {
581 _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC", infoCount, info[i].imageFilePath);
582 }
8972963c 583 goto reject;
7af964d1
A
584 }
585 if (!UseGC && _objcInfoRequiresGC(image_info)) {
586 // GC is OFF, but image requires GC
587 if (PrintImages || PrintGC) {
588 _objc_inform("IMAGES: rejecting %d images because %s requires GC", infoCount, info[i].imageFilePath);
589 }
8972963c 590 goto reject;
7af964d1
A
591 }
592 }
593
8972963c 594 crashlog_header_name_string(NULL);
7af964d1 595 return NULL;
8972963c
A
596
597 reject:
598 crashlog_header_name_string(NULL);
599 return "GC capability mismatch";
7af964d1
A
600}
601
8972963c 602// SUPPORT_GC
7af964d1
A
603#endif
604
605
8070259c
A
606
607/***********************************************************************
608* getSDKVersion
609* Look up the build-time SDK version for an image.
610* Version X.Y.Z is encoded as 0xXXXXYYZZ.
611* Images without the load command are assumed to be old (version 0.0.0).
612**********************************************************************/
613#if TARGET_OS_IPHONE
614 // Simulator binaries encode an iOS version
615# define LC_VERSION_MIN LC_VERSION_MIN_IPHONEOS
616#elif TARGET_OS_MAC
617# define LC_VERSION_MIN LC_VERSION_MIN_MACOSX
618#else
619# error unknown OS
620#endif
621
622static uint32_t
623getSDKVersion(const header_info *hi)
624{
625 const struct version_min_command *cmd;
626 unsigned long i;
627
628 cmd = (const struct version_min_command *) (hi->mhdr + 1);
629 for (i = 0; i < hi->mhdr->ncmds; i++){
630 if (cmd->cmd == LC_VERSION_MIN && cmd->cmdsize >= 16) {
631 return cmd->sdk;
632 }
633 cmd = (const struct version_min_command *)((char *)cmd + cmd->cmdsize);
634 }
635
636 // Lack of version load command is assumed to be old.
637 return 0;
638}
639
640
7af964d1
A
641/***********************************************************************
642* map_images_nolock
643* Process the given images which are being mapped in by dyld.
644* All class registration and fixups are performed (or deferred pending
645* discovery of missing superclasses etc), and +load methods are called.
646*
647* info[] is in bottom-up order i.e. libobjc will be earlier in the
648* array than any library that links to libobjc.
649*
650* Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
651**********************************************************************/
cd5f04f5
A
652#if __OBJC2__
653#include "objc-file.h"
654#else
655#include "objc-file-old.h"
656#endif
657
658const char *
7af964d1
A
659map_images_nolock(enum dyld_image_states state, uint32_t infoCount,
660 const struct dyld_image_info infoList[])
661{
662 static BOOL firstTime = YES;
8972963c 663 static BOOL wantsGC = NO;
7af964d1
A
664 uint32_t i;
665 header_info *hi;
666 header_info *hList[infoCount];
667 uint32_t hCount;
cd5f04f5 668 size_t selrefCount = 0;
7af964d1
A
669
670 // Perform first-time initialization if necessary.
671 // This function is called before ordinary library initializers.
672 // fixme defer initialization until an objc-using image is found?
673 if (firstTime) {
cd5f04f5 674 preopt_init();
8972963c 675#if SUPPORT_GC
7af964d1
A
676 InitialDyldRegistration = YES;
677 dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* batch */, &gc_enforcer);
678 InitialDyldRegistration = NO;
679#endif
680 }
681
682 if (PrintImages) {
683 _objc_inform("IMAGES: processing %u newly-mapped images...\n", infoCount);
684 }
685
686
687 // Find all images with Objective-C metadata.
688 hCount = 0;
689 i = infoCount;
690 while (i--) {
691 const headerType *mhdr = (headerType *)infoList[i].imageLoadAddress;
692
cd5f04f5 693 hi = addHeader(mhdr);
7af964d1
A
694 if (!hi) {
695 // no objc data in this entry
696 continue;
697 }
cd5f04f5 698 if (mhdr->filetype == MH_EXECUTE) {
8070259c
A
699 // Record main executable's build SDK version
700 AppSDKVersion = getSDKVersion(hi);
701
702 // Size some data structures based on main executable's size
cd5f04f5
A
703#if __OBJC2__
704 size_t count;
705 _getObjc2SelectorRefs(hi, &count);
706 selrefCount += count;
707 _getObjc2MessageRefs(hi, &count);
708 selrefCount += count;
709#else
710 _getObjcSelectorRefs(hi, &selrefCount);
711#endif
712 }
7af964d1
A
713
714 hList[hCount++] = hi;
715
716
717 if (PrintImages) {
718 _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
cd5f04f5 719 hi->fname,
7af964d1
A
720 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
721 _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
722 _objcHeaderOptimizedByDyld(hi)?" (preoptimized)" : "",
723 _gcForHInfo2(hi));
724 }
725 }
726
727 // Perform one-time runtime initialization that must be deferred until
728 // the executable itself is found. This needs to be done before
729 // further initialization.
730 // (The executable may not be present in this infoList if the
731 // executable does not contain Objective-C code but Objective-C
732 // is dynamically loaded later. In that case, check_wants_gc()
733 // will do the right thing.)
8972963c 734#if SUPPORT_GC
7af964d1 735 if (firstTime) {
7257e56c 736 check_wants_gc(&wantsGC);
7af964d1 737
7257e56c 738 verify_gc_readiness(wantsGC, hList, hCount);
7af964d1 739
7257e56c 740 gc_init(wantsGC); // needs executable for GC decision
7af964d1 741 } else {
7257e56c 742 verify_gc_readiness(wantsGC, hList, hCount);
7af964d1
A
743 }
744
745 if (wantsGC) {
746 // tell the collector about the data segment ranges.
747 for (i = 0; i < hCount; ++i) {
8972963c
A
748 uint8_t *seg;
749 unsigned long seg_size;
7af964d1 750 hi = hList[i];
8972963c
A
751
752 seg = getsegmentdata(hi->mhdr, "__DATA", &seg_size);
753 if (seg) gc_register_datasegment((uintptr_t)seg, seg_size);
754
755 seg = getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
756 if (seg) gc_register_datasegment((uintptr_t)seg, seg_size);
757 // __OBJC contains no GC data, but pointers to it are
758 // used as associated reference values (rdar://6953570)
7af964d1
A
759 }
760 }
761#endif
762
763 if (firstTime) {
cd5f04f5 764 sel_init(wantsGC, selrefCount);
8972963c 765 arr_init();
7af964d1
A
766 }
767
768 _read_images(hList, hCount);
769
770 firstTime = NO;
771
772 return NULL;
773}
774
775
776/***********************************************************************
777* load_images_nolock
778* Prepares +load in the given images which are being mapped in by dyld.
779* Returns YES if there are now +load methods to be called by call_load_methods.
780*
781* Locking: loadMethodLock(both) and runtimeLock(new) acquired by load_images
782**********************************************************************/
cd5f04f5 783BOOL
7af964d1
A
784load_images_nolock(enum dyld_image_states state,uint32_t infoCount,
785 const struct dyld_image_info infoList[])
786{
787 BOOL found = NO;
788 uint32_t i;
789
790 i = infoCount;
791 while (i--) {
792 header_info *hi;
793 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
794 const headerType *mhdr = (headerType*)infoList[i].imageLoadAddress;
795 if (hi->mhdr == mhdr) {
796 prepare_load_methods(hi);
797 found = YES;
798 }
799 }
800 }
801
802 return found;
803}
804
805
806/***********************************************************************
807* unmap_image_nolock
808* Process the given image which is about to be unmapped by dyld.
809* mh is mach_header instead of headerType because that's what
810* dyld_priv.h says even for 64-bit.
811*
812* Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
813**********************************************************************/
cd5f04f5 814void
8972963c 815unmap_image_nolock(const struct mach_header *mh)
7af964d1
A
816{
817 if (PrintImages) {
818 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
819 }
820
821 header_info *hi;
822
823 // Find the runtime's header_info struct for the image
824 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
825 if (hi->mhdr == (const headerType *)mh) {
826 break;
827 }
828 }
829
830 if (!hi) return;
831
832 if (PrintImages) {
833 _objc_inform("IMAGES: unloading image for %s%s%s%s\n",
cd5f04f5 834 hi->fname,
7af964d1
A
835 hi->mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
836 _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
837 _gcForHInfo2(hi));
838 }
839
8972963c 840#if SUPPORT_GC
7af964d1 841 if (UseGC) {
8972963c
A
842 uint8_t *seg;
843 unsigned long seg_size;
844
845 seg = getsegmentdata(hi->mhdr, "__DATA", &seg_size);
846 if (seg) gc_unregister_datasegment((uintptr_t)seg, seg_size);
847
848 seg = getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
849 if (seg) gc_unregister_datasegment((uintptr_t)seg, seg_size);
7af964d1
A
850 }
851#endif
852
853 _unload_image(hi);
854
855 // Remove header_info from header list
cd5f04f5 856 removeHeader(hi);
7af964d1
A
857 _free_internal(hi);
858}
859
860
861/***********************************************************************
862* _objc_init
cd5f04f5
A
863* Bootstrap initialization. Registers our image notifier with dyld.
864* Old ABI: called by dyld as a library initializer
865* New ABI: called by libSystem BEFORE library initialization time
7af964d1 866**********************************************************************/
cd5f04f5 867#if !__OBJC2__
7af964d1 868static __attribute__((constructor))
cd5f04f5 869#endif
7af964d1
A
870void _objc_init(void)
871{
cd5f04f5
A
872 static bool initialized = false;
873 if (initialized) return;
874 initialized = true;
875
7af964d1
A
876 // fixme defer initialization until an objc-using image is found?
877 environ_init();
878 tls_init();
879 lock_init();
880 exception_init();
8972963c 881
7af964d1
A
882 // Register for unmap first, in case some +load unmaps something
883 _dyld_register_func_for_remove_image(&unmap_image);
884 dyld_register_image_state_change_handler(dyld_image_state_bound,
885 1/*batch*/, &map_images);
886 dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized, 0/*not batch*/, &load_images);
887}
888
889
890/***********************************************************************
891* _headerForAddress.
892* addr can be a class or a category
893**********************************************************************/
894static const header_info *_headerForAddress(void *addr)
895{
8972963c
A
896#if __OBJC2__
897 const char *segname = "__DATA";
898#else
899 const char *segname = "__OBJC";
900#endif
901 header_info *hi;
7af964d1
A
902
903 // Check all headers in the vector
904 for (hi = FirstHeader; hi != NULL; hi = hi->next)
905 {
8972963c
A
906 uint8_t *seg;
907 unsigned long seg_size;
908
909 seg = getsegmentdata(hi->mhdr, segname, &seg_size);
910 if (!seg) continue;
7af964d1
A
911
912 // Is the class in this header?
8972963c 913 if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size)
7af964d1
A
914 return hi;
915 }
916
917 // Not found
918 return 0;
919}
920
921
922/***********************************************************************
923* _headerForClass
924* Return the image header containing this class, or NULL.
925* Returns NULL on runtime-constructed classes, and the NSCF classes.
926**********************************************************************/
cd5f04f5 927const header_info *_headerForClass(Class cls)
7af964d1
A
928{
929 return _headerForAddress(cls);
930}
931
932
933/**********************************************************************
934* secure_open
935* Securely open a file from a world-writable directory (like /tmp)
936* If the file does not exist, it will be atomically created with mode 0600
937* If the file exists, it must be, and remain after opening:
938* 1. a regular file (in particular, not a symlink)
939* 2. owned by euid
940* 3. permissions 0600
941* 4. link count == 1
942* Returns a file descriptor or -1. Errno may or may not be set on error.
943**********************************************************************/
cd5f04f5 944int secure_open(const char *filename, int flags, uid_t euid)
7af964d1
A
945{
946 struct stat fs, ls;
947 int fd = -1;
948 BOOL truncate = NO;
949 BOOL create = NO;
950
951 if (flags & O_TRUNC) {
952 // Don't truncate the file until after it is open and verified.
953 truncate = YES;
954 flags &= ~O_TRUNC;
955 }
956 if (flags & O_CREAT) {
957 // Don't create except when we're ready for it
958 create = YES;
959 flags &= ~O_CREAT;
960 flags &= ~O_EXCL;
961 }
962
963 if (lstat(filename, &ls) < 0) {
964 if (errno == ENOENT && create) {
965 // No such file - create it
966 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
967 if (fd >= 0) {
968 // File was created successfully.
969 // New file does not need to be truncated.
970 return fd;
971 } else {
972 // File creation failed.
973 return -1;
974 }
975 } else {
976 // lstat failed, or user doesn't want to create the file
977 return -1;
978 }
979 } else {
980 // lstat succeeded - verify attributes and open
981 if (S_ISREG(ls.st_mode) && // regular file?
982 ls.st_nlink == 1 && // link count == 1?
983 ls.st_uid == euid && // owned by euid?
984 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
985 {
986 // Attributes look ok - open it and check attributes again
987 fd = open(filename, flags, 0000);
988 if (fd >= 0) {
989 // File is open - double-check attributes
990 if (0 == fstat(fd, &fs) &&
991 fs.st_nlink == ls.st_nlink && // link count == 1?
992 fs.st_uid == ls.st_uid && // owned by euid?
993 fs.st_mode == ls.st_mode && // regular file, 0600?
994 fs.st_ino == ls.st_ino && // same inode as before?
995 fs.st_dev == ls.st_dev) // same device as before?
996 {
997 // File is open and OK
998 if (truncate) ftruncate(fd, 0);
999 return fd;
1000 } else {
1001 // Opened file looks funny - close it
1002 close(fd);
1003 return -1;
1004 }
1005 } else {
1006 // File didn't open
1007 return -1;
1008 }
1009 } else {
1010 // Unopened file looks funny - don't open it
1011 return -1;
1012 }
1013 }
1014}
1015
1016
1017/***********************************************************************
1018* _objc_internal_zone.
1019* Malloc zone for internal runtime data.
1020* By default this is the default malloc zone, but a dedicated zone is
1021* used if environment variable OBJC_USE_INTERNAL_ZONE is set.
1022**********************************************************************/
cd5f04f5 1023malloc_zone_t *_objc_internal_zone(void)
7af964d1
A
1024{
1025 static malloc_zone_t *z = (malloc_zone_t *)-1;
1026 if (z == (malloc_zone_t *)-1) {
1027 if (UseInternalZone) {
1028 z = malloc_create_zone(vm_page_size, 0);
8070259c 1029 malloc_set_zone_name(z, "ObjC_Internal");
7af964d1
A
1030 } else {
1031 z = malloc_default_zone();
1032 }
1033 }
1034 return z;
1035}
1036
1037
cd5f04f5 1038bool crashlog_header_name(header_info *hi)
8972963c 1039{
cd5f04f5 1040 return crashlog_header_name_string(hi ? hi->fname : NULL);
8972963c
A
1041}
1042
cd5f04f5 1043bool crashlog_header_name_string(const char *name)
8972963c
A
1044{
1045 CRSetCrashLogMessage2(name);
1046 return true;
1047}
1048
1049
1050#if TARGET_OS_IPHONE
1051
cd5f04f5 1052const char *__crashreporter_info__ = NULL;
8972963c 1053
cd5f04f5 1054const char *CRSetCrashLogMessage(const char *msg)
8972963c
A
1055{
1056 __crashreporter_info__ = msg;
1057 return msg;
1058}
cd5f04f5 1059const char *CRGetCrashLogMessage(void)
8972963c
A
1060{
1061 return __crashreporter_info__;
1062}
1063
cd5f04f5 1064const char *CRSetCrashLogMessage2(const char *msg)
8972963c
A
1065{
1066 // sorry
1067 return msg;
1068}
1069
1070#endif
1071
7af964d1
A
1072// TARGET_OS_MAC
1073#else
1074
1075
1076#error unknown OS
1077
1078
1079#endif