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