X-Git-Url: https://git.saurik.com/apple/dyld.git/blobdiff_plain/bac542e65c0030c0d819c7ff1dcfc25892a61844..refs/heads/master:/src/dyldExceptions.c diff --git a/src/dyldExceptions.c b/src/dyldExceptions.c index 133e978..a757d9a 100644 --- a/src/dyldExceptions.c +++ b/src/dyldExceptions.c @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,187 +26,181 @@ #include #include #include +#include +#include +#include +#include +#include +#include -// -// BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c -// -#define KEYMGR_API_MAJOR_GCC3 3 -/* ... with these keys. */ -#define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */ -#define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */ -#define KEYMGR_EH_GLOBALS_KEY 13 - -/* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */ -struct live_images { - unsigned long this_size; /* sizeof (live_images) */ - struct mach_header *mh; /* the image info */ - unsigned long vm_slide; - void (*destructor)(struct live_images *); /* destructor for this */ - struct live_images *next; - unsigned int examined_p; - void *fde; - void *object_info; - unsigned long info[2]; /* Future use. */ -}; -// -// END copy of code from libgcc.a source file unwind-dw2-fde-darwin.c -// +#include "dyldLibSystemInterface.h" + + +extern void _ZN4dyld3logEPKcz(const char*, ...); +extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE; + + +#if __LP64__ + #define LC_SEGMENT_COMMAND LC_SEGMENT_64 + #define macho_header mach_header_64 + #define macho_segment_command segment_command_64 + #define macho_section section_64 + #define getsectdatafromheader getsectdatafromheader_64 +#else + #define LC_SEGMENT_COMMAND LC_SEGMENT + #define macho_header mach_header + #define macho_segment_command segment_command + #define macho_section section +#endif // -// dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc. +// The standard versions of __cxa_get_globals*() from libstdc++-static.a cannot be used. +// On Mac OS X, they use keymgr which dyld does not implement. +// On iPhoneOS, they use pthread_key_create which dyld cannot use. // -// In order for C++ exceptions to work within dyld, the C++ exception handling code -// must be able to find the exception handling frame data inside dyld. The standard -// exception handling code uses crt and keymgr to keep track of all images and calls -// getsectdatafromheader("__eh_frame") to find the EH data for each image. We implement -// our own copy of those functions below to enable exceptions within dyld. +// Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key // -// Note: This exception handling is completely separate from any user code exception . -// handling which has its own keymgr (in libSystem). -// +static pthread_key_t sCxaKey = 0; +static char sPreMainCxaGlobals[2*sizeof(long)]; + +// called by libstdc++.a +char* __cxa_get_globals() +{ + // if libSystem.dylib not yet initialized, or is old libSystem, use shared global + if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) ) + return sPreMainCxaGlobals; + + if ( sCxaKey == 0 ) { + // create key + // we don't need a lock because only one thread can be in dyld at a time + _ZN4dyld17gLibSystemHelpersE->pthread_key_create(&sCxaKey, &free); + } + char* data = (char*)_ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); + if ( data == NULL ) { + long* t = (long*)calloc(2,sizeof(long)); + data = (char*)t; + _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data); + } + return data; +} +// called by libstdc++.a +char* __cxa_get_globals_fast() +{ + // if libSystem.dylib not yet initialized, or is old libSystem, use shared global + if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) ) + return sPreMainCxaGlobals; -static struct live_images sDyldImage; // zero filled -static void* sObjectList = NULL; -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) -static void* sEHGlobals = NULL; -#endif + return _ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); +} -// called by dyldStartup.s very early -void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide) -{ - sDyldImage.this_size = sizeof(struct live_images); - sDyldImage.mh = mh; - sDyldImage.vm_slide = slide; -} +#if !__USING_SJLJ_EXCEPTIONS__ +// +// When dyld uses zero-cost exceptions it just needs to implement +// _dyld_find_unwind_sections to return sections inside dyld proper. +// +extern void* ehStart __asm("section$start$__TEXT$__eh_frame"); +extern void* ehEnd __asm("section$end$__TEXT$__eh_frame"); +extern void* uwStart __asm("section$start$__TEXT$__unwind_info"); +extern void* uwEnd __asm("section$end$__TEXT$__unwind_info"); -// Hack for gcc 3.5's use of keymgr includes accessing __keymgr_global -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) -typedef struct Sinfo_Node { - uint32_t size; /* Size of this node. */ - uint16_t major_version; /* API major version. */ - uint16_t minor_version; /* API minor version. */ -} Tinfo_Node; -static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 }; -const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info }; -#endif +extern void* textStart __asm("section$start$__TEXT$__text"); +extern void* textEnd __asm("section$end$__TEXT$__text"); -static __attribute__((noreturn)) -void dyld_abort() -{ - //dyld::log("internal dyld error\n"); - _exit(1); -} +extern void* __dso_handle; -void* _keymgr_get_and_lock_processwide_ptr(unsigned int key) +// called by libuwind code to find unwind information sections in dyld +bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info) { - // The C++ exception handling code uses two keys. No other keys should be seen - if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) { - return &sDyldImage; + if ( ((void*)&textStart < addr) && (addr < (void*)&textEnd) ) { + info->mh = (struct mach_header*)&__dso_handle; + info->dwarf_section = &ehStart; + info->dwarf_section_length = ((char*)&ehEnd - (char*)&ehStart); + info->compact_unwind_section = &uwStart; + info->compact_unwind_section_length = ((char*)&uwEnd - (char*)&uwStart); + return true; } - else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) { - return sObjectList; + else { + return false; } - dyld_abort(); } -void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value) -{ - // The C++ exception handling code uses just this key. No other keys should be seen - if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) { - sObjectList = value; - return; - } - dyld_abort(); -} +#else +// +// When dyld uses setjump-longjump exceptions it needs to implement +// routines to push and pop a stack of _Unwind_FunctionContext. +// -void _keymgr_unlock_processwide_ptr(unsigned int key) +struct _Unwind_FunctionContext { - // The C++ exception handling code uses just this key. No other keys should be seen - if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) { - return; - } - dyld_abort(); -} - -void* _keymgr_get_per_thread_data(unsigned int key) -{ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) - // gcc 3.5 and later use this key - if ( key == KEYMGR_EH_GLOBALS_KEY ) - return sEHGlobals; -#endif + // next function in stack of handlers + struct _Unwind_FunctionContext* prev; - // used by std::termination which dyld does not use - dyld_abort(); -} +}; -void _keymgr_set_per_thread_data(unsigned int key, void *keydata) + +static pthread_key_t sThreadChainKey = 0; +static struct _Unwind_FunctionContext* sStaticThreadChain = NULL; + +// +// When libSystem's initializers are run, they call back into dyld's +// registerThreadHelpers which creates a pthread key and calls +// __Unwind_SjLj_SetThreadKey(). +// +void __Unwind_SjLj_SetThreadKey(pthread_key_t key) { -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4)) - // gcc 3.5 and later use this key - if ( key == KEYMGR_EH_GLOBALS_KEY ) { - sEHGlobals = keydata; - return; - } -#endif - // used by std::termination which dyld does not use - dyld_abort(); + sThreadChainKey = key; + //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain); + // switch static chain to be per thread + _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, sStaticThreadChain); + sStaticThreadChain = NULL; + //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey)); } -#if __LP64__ - #define LC_SEGMENT_COMMAND LC_SEGMENT_64 - #define macho_header mach_header_64 - #define macho_segment_command segment_command_64 - #define macho_section section_64 - #define getsectdatafromheader getsectdatafromheader_64 -#else - #define LC_SEGMENT_COMMAND LC_SEGMENT - #define macho_header mach_header - #define macho_segment_command segment_command - #define macho_section section -#endif -// needed by C++ exception handling code to find __eh_frame section -const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size) +//static void printChain() +//{ +// _ZN4dyld3logEPKcz("chain: "); +// struct _Unwind_FunctionContext* start = sStaticThreadChain; +// if ( sThreadChainKey != 0 ) { +// start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); +// } +// for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) { +// _ZN4dyld3logEPKcz("%p -> ", p); +// } +// _ZN4dyld3logEPKcz("\n"); +//} + + +struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack() { - const struct load_command* cmd; - unsigned long i; - - cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header)); - for(i = 0; i < mh->ncmds; i++) { - if ( cmd->cmd == LC_SEGMENT_COMMAND ) { - const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; - if ( strcmp(seg->segname, segname) == 0 ) { - const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) ); - unsigned long j; - for (j = 0; j < seg->nsects; j++) { - if ( strcmp(sect[j].sectname, sectname) == 0 ) { - *size = sect[j].size; - return (void*)(sect[j].addr); - } - } - } - } - cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize ); + //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(), key=%d, ", sThreadChainKey); + //printChain(); + if ( sThreadChainKey != 0 ) { + return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); + } + else { + return sStaticThreadChain; } - return NULL; } +void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc) +{ + //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n", + // fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL); + if ( sThreadChainKey != 0 ) + _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, fc); + else + sStaticThreadChain = fc; + //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey); + //printChain(); +} -// Hack for transition of rdar://problem/3933738 -// Can be removed later. -// Allow C++ runtime to call getsectdatafromheader or getsectdatafromheader_64 -#if __LP64__ - #undef getsectdatafromheader - const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size) - { - return getsectdatafromheader_64(mh, segname, sectname, size); - } #endif +