+++ /dev/null
-/*
- * Copyright (c) 2007 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/***********************************************************************
-* objc-os.m
-* OS portability layer.
-**********************************************************************/
-
-#include "objc-os.h"
-#include "objc-private.h"
-#include "objc-loadmethod.h"
-
-#if TARGET_OS_WIN32
-
-#include "objc-runtime-old.h"
-#include "objcrt.h"
-
-malloc_zone_t *_objc_internal_zone(void)
-{
- return NULL;
-}
-
-int monitor_init(monitor_t *c)
-{
- // fixme error checking
- HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
- while (!c->mutex) {
- // fixme memory barrier here?
- if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
- // we win - finish construction
- c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
- c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
- InitializeCriticalSection(&c->waitCountLock);
- c->waitCount = 0;
- c->didBroadcast = 0;
- ReleaseMutex(c->mutex);
- return 0;
- }
- }
-
- // someone else allocated the mutex and constructed the monitor
- ReleaseMutex(mutex);
- CloseHandle(mutex);
- return 0;
-}
-
-void mutex_init(mutex_t *m)
-{
- while (!m->lock) {
- CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
- InitializeCriticalSection(newlock);
- // fixme memory barrier here?
- if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
- return;
- }
- // someone else installed their lock first
- DeleteCriticalSection(newlock);
- free(newlock);
- }
-}
-
-
-void recursive_mutex_init(recursive_mutex_t *m)
-{
- // fixme error checking
- HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
- while (!m->mutex) {
- // fixme memory barrier here?
- if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
- // we win
- return;
- }
- }
-
- // someone else installed their lock first
- CloseHandle(newmutex);
-}
-
-
-WINBOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
-{
- switch (ul_reason_for_call) {
- case DLL_PROCESS_ATTACH:
- environ_init();
- tls_init();
- lock_init();
- sel_init(NO);
- exception_init();
- break;
-
- case DLL_THREAD_ATTACH:
- break;
-
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
-}
-
-OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
-{
- header_info *hi = _malloc_internal(sizeof(header_info));
- size_t count, i;
-
- hi->mhdr = (const headerType *)image;
- hi->info = sects->iiStart;
- hi->allClassesRealized = NO;
- hi->os.modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
- hi->os.moduleCount = (Module *)sects->modEnd - hi->os.modules;
- hi->os.protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
- hi->os.protocolCount = (struct old_protocol **)sects->protoEnd - hi->os.protocols;
- hi->os.imageinfo = NULL;
- hi->os.imageinfoBytes = 0;
- // hi->os.imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
-// hi->os.imageinfoBytes = (uint8_t *)sects->iiEnd - hi->os.imageinfo;
- hi->os.selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
- hi->os.selrefCount = (SEL *)sects->selrefsEnd - hi->os.selrefs;
- hi->os.clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
- hi->os.clsrefCount = (Class *)sects->clsrefsEnd - hi->os.clsrefs;
-
- count = 0;
- for (i = 0; i < hi->os.moduleCount; i++) {
- if (hi->os.modules[i]) count++;
- }
- hi->mod_count = 0;
- hi->mod_ptr = 0;
- if (count > 0) {
- hi->mod_ptr = malloc(count * sizeof(struct objc_module));
- for (i = 0; i < hi->os.moduleCount; i++) {
- if (hi->os.modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->os.modules[i], sizeof(struct objc_module));
- }
- }
-
- hi->os.moduleName = malloc(MAX_PATH * sizeof(TCHAR));
- GetModuleFileName((HMODULE)(hi->mhdr), hi->os.moduleName, MAX_PATH * sizeof(TCHAR));
-
- _objc_appendHeader(hi);
-
- if (PrintImages) {
- _objc_inform("IMAGES: loading image for %s%s%s\n",
- _nameForHeader(hi->mhdr),
- headerIsBundle(hi) ? " (bundle)" : "",
- _objcHeaderIsReplacement(hi) ? " (replacement)":"");
- }
-
- _read_images(&hi, 1);
-
- return hi;
-}
-
-OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
-{
- prepare_load_methods(hinfo);
- call_load_methods();
-}
-
-OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
-{
- _objc_fatal("image unload not supported");
-}
-
-
-PRIVATE_EXTERN bool crashlog_header_name(header_info *hi)
-{
- return true;
-}
-
-
-// TARGET_OS_WIN32
-#elif TARGET_OS_MAC
-
-#if !__OBJC2__
-#include "objc-file-old.h"
-#endif
-
-PRIVATE_EXTERN void mutex_init(mutex_t *m)
-{
- pthread_mutex_init(m, NULL);
-}
-
-
-PRIVATE_EXTERN void recursive_mutex_init(recursive_mutex_t *m)
-{
- // fixme error checking
- pthread_mutex_t *newmutex;
-
- // Build recursive mutex attributes, if needed
- static pthread_mutexattr_t *attr;
- if (!attr) {
- pthread_mutexattr_t *newattr =
- _malloc_internal(sizeof(pthread_mutexattr_t));
- pthread_mutexattr_init(newattr);
- pthread_mutexattr_settype(newattr, PTHREAD_MUTEX_RECURSIVE);
- while (!attr) {
- if (OSAtomicCompareAndSwapPtrBarrier(0, newattr, (void**)&attr)) {
- // we win
- goto attr_done;
- }
- }
- // someone else built the attr first
- _free_internal(newattr);
- }
- attr_done:
-
- // Build the mutex itself
- newmutex = _malloc_internal(sizeof(pthread_mutex_t));
- pthread_mutex_init(newmutex, attr);
- while (!m->mutex) {
- if (OSAtomicCompareAndSwapPtrBarrier(0, newmutex, (void**)&m->mutex)) {
- // we win
- return;
- }
- }
-
- // someone else installed their mutex first
- pthread_mutex_destroy(newmutex);
-}
-
-
-/***********************************************************************
-* bad_magic.
-* Return YES if the header has invalid Mach-o magic.
-**********************************************************************/
-PRIVATE_EXTERN BOOL bad_magic(const headerType *mhdr)
-{
- return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
- mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
-}
-
-
-static header_info * _objc_addHeader(const headerType *mhdr)
-{
- size_t info_size = 0;
- unsigned long seg_size;
- const uint8_t *objc_segment;
- const objc_image_info *image_info;
- header_info *result;
-
- if (bad_magic(mhdr)) return NULL;
-
- // Weed out duplicates
- for (result = FirstHeader; result; result = result->next) {
- if (mhdr == result->mhdr) return NULL;
- }
-
- // Locate the __OBJC segment
- image_info = _getObjcImageInfo(mhdr, &info_size);
- objc_segment = getsegmentdata(mhdr, SEG_OBJC, &seg_size);
- if (!objc_segment && !image_info) return NULL;
-
- // Allocate a header_info entry.
- result = _calloc_internal(sizeof(header_info), 1);
-
- // Set up the new header_info entry.
- result->mhdr = mhdr;
-#if !__OBJC2__
- // mhdr must already be set
- result->mod_count = 0;
- result->mod_ptr = _getObjcModules(result, &result->mod_count);
-#endif
- result->info = image_info;
- dladdr(result->mhdr, &result->os.dl_info);
- result->allClassesRealized = NO;
-
- // dylibs are not allowed to unload
- // ...except those with image_info and nothing else (5359412)
- if (result->mhdr->filetype == MH_DYLIB && _hasObjcContents(result)) {
- dlopen(result->os.dl_info.dli_fname, RTLD_NOLOAD);
- }
-
- // Make sure every copy of objc_image_info in this image is the same.
- // This means same version and same bitwise contents.
- if (result->info) {
- const objc_image_info *start = result->info;
- const objc_image_info *end =
- (objc_image_info *)(info_size + (uint8_t *)start);
- const objc_image_info *info = start;
- while (info < end) {
- // version is byte size, except for version 0
- size_t struct_size = info->version;
- if (struct_size == 0) struct_size = 2 * sizeof(uint32_t);
- if (info->version != start->version ||
- 0 != memcmp(info, start, struct_size))
- {
- _objc_inform("'%s' has inconsistently-compiled Objective-C "
- "code. Please recompile all code in it.",
- _nameForHeader(mhdr));
- }
- info = (objc_image_info *)(struct_size + (uint8_t *)info);
- }
- }
-
- _objc_appendHeader(result);
-
- return result;
-}
-
-
-#if !SUPPORT_GC
-
-PRIVATE_EXTERN const char *_gcForHInfo(const header_info *hinfo)
-{
- return "";
-}
-PRIVATE_EXTERN const char *_gcForHInfo2(const header_info *hinfo)
-{
- return "";
-}
-
-#else
-
-/***********************************************************************
-* _gcForHInfo.
-**********************************************************************/
-PRIVATE_EXTERN const char *_gcForHInfo(const header_info *hinfo)
-{
- if (_objcHeaderRequiresGC(hinfo)) {
- if (_objcHeaderSupportsCompaction(hinfo))
- return "requires GC, supports compaction";
- else
- return "requires GC";
- } else if (_objcHeaderSupportsGC(hinfo)) {
- if (_objcHeaderSupportsCompaction(hinfo))
- return "supports GC, supports compaction";
- else
- return "supports GC";
- } else {
- return "does not support GC";
- }
-}
-PRIVATE_EXTERN const char *_gcForHInfo2(const header_info *hinfo)
-{
- if (_objcHeaderRequiresGC(hinfo)) {
- if (_objcHeaderSupportsCompaction(hinfo))
- return "(requires GC) (supports compaction)";
- else
- return "(requires GC)";
- } else if (_objcHeaderSupportsGC(hinfo)) {
- if (_objcHeaderSupportsCompaction(hinfo))
- return "(supports GC) (supports compaction)";
- else
- return "(supports GC)";
- }
- return "";
-}
-
-
-/***********************************************************************
-* check_gc
-* Check whether the executable supports or requires GC, and make sure
-* all already-loaded libraries support the executable's GC mode.
-* Returns TRUE if the executable wants GC on.
-**********************************************************************/
-static void check_wants_gc(BOOL *appWantsGC, BOOL *appSupportsCompaction)
-{
- const header_info *hi;
-
- // Environment variables can override the following.
- if (DisableGC) {
- _objc_inform("GC: forcing GC OFF because OBJC_DISABLE_GC is set");
- *appWantsGC = NO;
- *appSupportsCompaction = NO;
- }
- else {
- // Find the executable and check its GC bits.
- // If the executable cannot be found, default to NO.
- // (The executable will not be found if the executable contains
- // no Objective-C code.)
- *appWantsGC = NO;
- *appSupportsCompaction = NO;
- for (hi = FirstHeader; hi != NULL; hi = hi->next) {
- if (hi->mhdr->filetype == MH_EXECUTE) {
- *appWantsGC = _objcHeaderSupportsGC(hi) ? YES : NO;
- *appSupportsCompaction = (*appWantsGC && _objcHeaderSupportsCompaction(hi)) ? YES : NO;
- if (PrintGC) {
- _objc_inform("GC: executable '%s' %s",
- _nameForHeader(hi->mhdr), _gcForHInfo(hi));
- }
- }
- }
- }
-}
-
-
-/***********************************************************************
-* verify_gc_readiness
-* if we want gc, verify that every header describes files compiled
-* and presumably ready for gc.
-************************************************************************/
-static void verify_gc_readiness(BOOL wantsGC, BOOL *wantsCompaction,
- header_info **hList, uint32_t hCount)
-{
- BOOL busted = NO;
- uint32_t i;
-
- // Find the libraries and check their GC bits against the app's request
- for (i = 0; i < hCount; i++) {
- header_info *hi = hList[i];
- if (hi->mhdr->filetype == MH_EXECUTE) {
- continue;
- }
- else if (hi->mhdr == &_mh_dylib_header) {
- // libobjc itself works with anything even though it is not
- // compiled with -fobjc-gc (fixme should it be?)
- }
- else if (wantsGC && ! _objcHeaderSupportsGC(hi)) {
- // App wants GC but library does not support it - bad
- _objc_inform_now_and_on_crash
- ("'%s' was not compiled with -fobjc-gc or -fobjc-gc-only, "
- "but the application requires GC",
- _nameForHeader(hi->mhdr));
- busted = YES;
- }
- else if (!wantsGC && _objcHeaderRequiresGC(hi)) {
- // App doesn't want GC but library requires it - bad
- _objc_inform_now_and_on_crash
- ("'%s' was compiled with -fobjc-gc-only, "
- "but the application does not support GC",
- _nameForHeader(hi->mhdr));
- busted = YES;
- }
-
- if (*wantsCompaction && !_objcHeaderSupportsCompaction(hi)) {
- // App supports compaction, but library doesn't.
- _objc_inform_now_and_on_crash
- ("'%s' was not linked with -Xlinker -objc_gc_compaction, "
- "but the application wants compaction.",
- _nameForHeader(hi->mhdr));
- // Simply warn for now until radars are filed. Eventually,
- // objc_disableCompaction() will block until any current compaction completes.
- objc_disableCompaction();
- *wantsCompaction = NO;
- }
-
- if (PrintGC) {
- _objc_inform("GC: library '%s' %s",
- _nameForHeader(hi->mhdr), _gcForHInfo(hi));
- }
- }
-
- if (busted) {
- // GC state is not consistent.
- // Kill the process unless one of the forcing flags is set.
- if (!DisableGC) {
- _objc_fatal("*** GC capability of application and some libraries did not match");
- }
- }
-}
-
-
-/***********************************************************************
-* gc_enforcer
-* Make sure that images about to be loaded by dyld are GC-acceptable.
-* Images linked to the executable are always permitted; they are
-* enforced inside map_images() itself.
-**********************************************************************/
-static BOOL InitialDyldRegistration = NO;
-static const char *gc_enforcer(enum dyld_image_states state,
- uint32_t infoCount,
- const struct dyld_image_info info[])
-{
- uint32_t i;
-
- // Linked images get a free pass
- if (InitialDyldRegistration) return NULL;
-
- if (PrintImages) {
- _objc_inform("IMAGES: checking %d images for compatibility...",
- infoCount);
- }
-
- for (i = 0; i < infoCount; i++) {
- crashlog_header_name_string(info[i].imageFilePath);
-
- const headerType *mhdr = (const headerType *)info[i].imageLoadAddress;
- if (bad_magic(mhdr)) continue;
-
- objc_image_info *image_info;
- size_t size;
-
- if (mhdr == &_mh_dylib_header) {
- // libobjc itself - OK
- continue;
- }
-
-#if !__OBJC2__
- unsigned long seg_size;
- // 32-bit: __OBJC seg but no image_info means no GC support
- if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
- // not objc - assume OK
- continue;
- }
- image_info = _getObjcImageInfo(mhdr, &size);
- if (!image_info) {
- // No image_info - assume GC unsupported
- if (!UseGC) {
- // GC is OFF - ok
- continue;
- } else {
- // GC is ON - bad
- if (PrintImages || PrintGC) {
- _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC (no image_info)", infoCount, info[i].imageFilePath);
- }
- goto reject;
- }
- }
-#else
- // 64-bit: no image_info means no objc at all
- image_info = _getObjcImageInfo(mhdr, &size);
- if (!image_info) {
- // not objc - assume OK
- continue;
- }
-#endif
-
- if (UseGC && !_objcInfoSupportsGC(image_info)) {
- // GC is ON, but image does not support GC
- if (PrintImages || PrintGC) {
- _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC", infoCount, info[i].imageFilePath);
- }
- goto reject;
- }
- if (!UseGC && _objcInfoRequiresGC(image_info)) {
- // GC is OFF, but image requires GC
- if (PrintImages || PrintGC) {
- _objc_inform("IMAGES: rejecting %d images because %s requires GC", infoCount, info[i].imageFilePath);
- }
- goto reject;
- }
- }
-
- crashlog_header_name_string(NULL);
- return NULL;
-
- reject:
- crashlog_header_name_string(NULL);
- return "GC capability mismatch";
-}
-
-// SUPPORT_GC
-#endif
-
-
-/***********************************************************************
-* map_images_nolock
-* Process the given images which are being mapped in by dyld.
-* All class registration and fixups are performed (or deferred pending
-* discovery of missing superclasses etc), and +load methods are called.
-*
-* info[] is in bottom-up order i.e. libobjc will be earlier in the
-* array than any library that links to libobjc.
-*
-* Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
-**********************************************************************/
-PRIVATE_EXTERN const char *
-map_images_nolock(enum dyld_image_states state, uint32_t infoCount,
- const struct dyld_image_info infoList[])
-{
- static BOOL firstTime = YES;
- static BOOL wantsGC = NO;
- static BOOL wantsCompaction = NO;
- uint32_t i;
- header_info *hi;
- header_info *hList[infoCount];
- uint32_t hCount;
-
- // Perform first-time initialization if necessary.
- // This function is called before ordinary library initializers.
- // fixme defer initialization until an objc-using image is found?
- if (firstTime) {
-#if SUPPORT_GC
- InitialDyldRegistration = YES;
- dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* batch */, &gc_enforcer);
- InitialDyldRegistration = NO;
-#endif
- }
-
- if (PrintImages) {
- _objc_inform("IMAGES: processing %u newly-mapped images...\n", infoCount);
- }
-
-
- // Find all images with Objective-C metadata.
- hCount = 0;
- i = infoCount;
- while (i--) {
- const headerType *mhdr = (headerType *)infoList[i].imageLoadAddress;
-
- hi = _objc_addHeader(mhdr);
- if (!hi) {
- // no objc data in this entry
- continue;
- }
-
- hList[hCount++] = hi;
-
-
- if (PrintImages) {
- _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
- _nameForHeader(mhdr),
- mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
- _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
- _objcHeaderOptimizedByDyld(hi)?" (preoptimized)" : "",
- _gcForHInfo2(hi));
- }
- }
-
- // Perform one-time runtime initialization that must be deferred until
- // the executable itself is found. This needs to be done before
- // further initialization.
- // (The executable may not be present in this infoList if the
- // executable does not contain Objective-C code but Objective-C
- // is dynamically loaded later. In that case, check_wants_gc()
- // will do the right thing.)
-#if SUPPORT_GC
- if (firstTime) {
- check_wants_gc(&wantsGC, &wantsCompaction);
-
- verify_gc_readiness(wantsGC, &wantsCompaction, hList, hCount);
-
- gc_init(wantsGC, wantsCompaction); // needs executable for GC decision
- rtp_init(); // needs GC decision first
- } else {
- verify_gc_readiness(wantsGC, &wantsCompaction, hList, hCount);
- }
-
- if (wantsGC) {
- // tell the collector about the data segment ranges.
- for (i = 0; i < hCount; ++i) {
- uint8_t *seg;
- unsigned long seg_size;
- hi = hList[i];
-
- seg = getsegmentdata(hi->mhdr, "__DATA", &seg_size);
- if (seg) gc_register_datasegment((uintptr_t)seg, seg_size);
-
- seg = getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
- if (seg) gc_register_datasegment((uintptr_t)seg, seg_size);
- // __OBJC contains no GC data, but pointers to it are
- // used as associated reference values (rdar://6953570)
- }
- }
-
- // Need to fixup barriers in all libraries that call into libobjc, whether GC is on or not.
- for (i = 0; i < infoCount; ++i) {
- gc_fixup_barrier_stubs(&infoList[i]);
- }
-#endif
-
- if (firstTime) {
- extern SEL FwdSel; // in objc-msg-*.s
- sel_init(wantsGC);
- FwdSel = sel_registerName("forward::");
-
- arr_init();
- }
-
- _read_images(hList, hCount);
-
- firstTime = NO;
-
- return NULL;
-}
-
-
-/***********************************************************************
-* load_images_nolock
-* Prepares +load in the given images which are being mapped in by dyld.
-* Returns YES if there are now +load methods to be called by call_load_methods.
-*
-* Locking: loadMethodLock(both) and runtimeLock(new) acquired by load_images
-**********************************************************************/
-PRIVATE_EXTERN BOOL
-load_images_nolock(enum dyld_image_states state,uint32_t infoCount,
- const struct dyld_image_info infoList[])
-{
- BOOL found = NO;
- uint32_t i;
-
- i = infoCount;
- while (i--) {
- header_info *hi;
- for (hi = FirstHeader; hi != NULL; hi = hi->next) {
- const headerType *mhdr = (headerType*)infoList[i].imageLoadAddress;
- if (hi->mhdr == mhdr) {
- prepare_load_methods(hi);
- found = YES;
- }
- }
- }
-
- return found;
-}
-
-
-/***********************************************************************
-* unmap_image_nolock
-* Process the given image which is about to be unmapped by dyld.
-* mh is mach_header instead of headerType because that's what
-* dyld_priv.h says even for 64-bit.
-*
-* Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
-**********************************************************************/
-PRIVATE_EXTERN void
-unmap_image_nolock(const struct mach_header *mh)
-{
- if (PrintImages) {
- _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
- }
-
- header_info *hi;
-
- // Find the runtime's header_info struct for the image
- for (hi = FirstHeader; hi != NULL; hi = hi->next) {
- if (hi->mhdr == (const headerType *)mh) {
- break;
- }
- }
-
- if (!hi) return;
-
- if (PrintImages) {
- _objc_inform("IMAGES: unloading image for %s%s%s%s\n",
- _nameForHeader(hi->mhdr),
- hi->mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
- _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
- _gcForHInfo2(hi));
- }
-
-#if SUPPORT_GC
- if (UseGC) {
- uint8_t *seg;
- unsigned long seg_size;
-
- seg = getsegmentdata(hi->mhdr, "__DATA", &seg_size);
- if (seg) gc_unregister_datasegment((uintptr_t)seg, seg_size);
-
- seg = getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
- if (seg) gc_unregister_datasegment((uintptr_t)seg, seg_size);
- }
-#endif
-
- _unload_image(hi);
-
- // Remove header_info from header list
- _objc_removeHeader(hi);
- _free_internal(hi);
-}
-
-
-/***********************************************************************
-* _objc_init
-* Static initializer. Registers our image notifier with dyld.
-**********************************************************************/
-static __attribute__((constructor))
-void _objc_init(void)
-{
- // fixme defer initialization until an objc-using image is found?
- environ_init();
- tls_init();
- lock_init();
- exception_init();
-
- // Register for unmap first, in case some +load unmaps something
- _dyld_register_func_for_remove_image(&unmap_image);
- dyld_register_image_state_change_handler(dyld_image_state_bound,
- 1/*batch*/, &map_images);
- dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized, 0/*not batch*/, &load_images);
-}
-
-
-/***********************************************************************
-* _headerForAddress.
-* addr can be a class or a category
-**********************************************************************/
-static const header_info *_headerForAddress(void *addr)
-{
-#if __OBJC2__
- const char *segname = "__DATA";
-#else
- const char *segname = "__OBJC";
-#endif
- header_info *hi;
-
- // Check all headers in the vector
- for (hi = FirstHeader; hi != NULL; hi = hi->next)
- {
- uint8_t *seg;
- unsigned long seg_size;
-
- seg = getsegmentdata(hi->mhdr, segname, &seg_size);
- if (!seg) continue;
-
- // Is the class in this header?
- if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size)
- return hi;
- }
-
- // Not found
- return 0;
-}
-
-
-/***********************************************************************
-* _headerForClass
-* Return the image header containing this class, or NULL.
-* Returns NULL on runtime-constructed classes, and the NSCF classes.
-**********************************************************************/
-PRIVATE_EXTERN const header_info *_headerForClass(Class cls)
-{
- return _headerForAddress(cls);
-}
-
-
-/**********************************************************************
-* secure_open
-* Securely open a file from a world-writable directory (like /tmp)
-* If the file does not exist, it will be atomically created with mode 0600
-* If the file exists, it must be, and remain after opening:
-* 1. a regular file (in particular, not a symlink)
-* 2. owned by euid
-* 3. permissions 0600
-* 4. link count == 1
-* Returns a file descriptor or -1. Errno may or may not be set on error.
-**********************************************************************/
-PRIVATE_EXTERN int secure_open(const char *filename, int flags, uid_t euid)
-{
- struct stat fs, ls;
- int fd = -1;
- BOOL truncate = NO;
- BOOL create = NO;
-
- if (flags & O_TRUNC) {
- // Don't truncate the file until after it is open and verified.
- truncate = YES;
- flags &= ~O_TRUNC;
- }
- if (flags & O_CREAT) {
- // Don't create except when we're ready for it
- create = YES;
- flags &= ~O_CREAT;
- flags &= ~O_EXCL;
- }
-
- if (lstat(filename, &ls) < 0) {
- if (errno == ENOENT && create) {
- // No such file - create it
- fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
- if (fd >= 0) {
- // File was created successfully.
- // New file does not need to be truncated.
- return fd;
- } else {
- // File creation failed.
- return -1;
- }
- } else {
- // lstat failed, or user doesn't want to create the file
- return -1;
- }
- } else {
- // lstat succeeded - verify attributes and open
- if (S_ISREG(ls.st_mode) && // regular file?
- ls.st_nlink == 1 && // link count == 1?
- ls.st_uid == euid && // owned by euid?
- (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
- {
- // Attributes look ok - open it and check attributes again
- fd = open(filename, flags, 0000);
- if (fd >= 0) {
- // File is open - double-check attributes
- if (0 == fstat(fd, &fs) &&
- fs.st_nlink == ls.st_nlink && // link count == 1?
- fs.st_uid == ls.st_uid && // owned by euid?
- fs.st_mode == ls.st_mode && // regular file, 0600?
- fs.st_ino == ls.st_ino && // same inode as before?
- fs.st_dev == ls.st_dev) // same device as before?
- {
- // File is open and OK
- if (truncate) ftruncate(fd, 0);
- return fd;
- } else {
- // Opened file looks funny - close it
- close(fd);
- return -1;
- }
- } else {
- // File didn't open
- return -1;
- }
- } else {
- // Unopened file looks funny - don't open it
- return -1;
- }
- }
-}
-
-
-/***********************************************************************
-* _objc_internal_zone.
-* Malloc zone for internal runtime data.
-* By default this is the default malloc zone, but a dedicated zone is
-* used if environment variable OBJC_USE_INTERNAL_ZONE is set.
-**********************************************************************/
-PRIVATE_EXTERN malloc_zone_t *_objc_internal_zone(void)
-{
- static malloc_zone_t *z = (malloc_zone_t *)-1;
- if (z == (malloc_zone_t *)-1) {
- if (UseInternalZone) {
- z = malloc_create_zone(vm_page_size, 0);
- malloc_set_zone_name(z, "ObjC");
- } else {
- z = malloc_default_zone();
- }
- }
- return z;
-}
-
-
-PRIVATE_EXTERN const char *
-_getObjcHeaderName(const headerType *header)
-{
- Dl_info info;
-
- if (dladdr(header, &info)) {
- return info.dli_fname;
- }
- else {
- return (*_NSGetArgv())[0];
- }
-}
-
-
-PRIVATE_EXTERN bool crashlog_header_name(header_info *hi)
-{
- return crashlog_header_name_string(hi ? hi->os.dl_info.dli_fname : NULL);
-}
-
-PRIVATE_EXTERN bool crashlog_header_name_string(const char *name)
-{
- CRSetCrashLogMessage2(name);
- return true;
-}
-
-
-#if TARGET_OS_IPHONE
-
-PRIVATE_EXTERN const char *__crashreporter_info__ = NULL;
-
-PRIVATE_EXTERN const char *CRSetCrashLogMessage(const char *msg)
-{
- __crashreporter_info__ = msg;
- return msg;
-}
-PRIVATE_EXTERN const char *CRGetCrashLogMessage(void)
-{
- return __crashreporter_info__;
-}
-
-PRIVATE_EXTERN const char *CRSetCrashLogMessage2(const char *msg)
-{
- // sorry
- return msg;
-}
-
-#endif
-
-// TARGET_OS_MAC
-#else
-
-
-#error unknown OS
-
-
-#endif