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