]> git.saurik.com Git - apple/dyld.git/blobdiff - src/dyldExceptions.c
dyld-851.27.tar.gz
[apple/dyld.git] / src / dyldExceptions.c
index 0cf1a18ec44fcc5e76a59a342b340dfc31069889..a757d9a9cfc7fb17939cb8f71f6550ff8af4c28e 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <stdbool.h>
 #include <stdarg.h>
 #include <pthread.h>
+#include <Availability.h>
+#include <mach-o/dyld_priv.h>
 
-#include "mach-o/dyld_priv.h"
 #include "dyldLibSystemInterface.h"
 
+
 extern void _ZN4dyld3logEPKcz(const char*, ...);
 extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
 
@@ -52,63 +54,21 @@ extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
 #endif
 
 
-#if __i386__ || __x86_64 || __ppc__
-
-static struct dyld_unwind_sections     sDyldInfo;
-static void*                                           sDyldTextEnd;
+//
+//  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.
+//
+//   Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key
+//
 static pthread_key_t                           sCxaKey = 0;
 static char                                                    sPreMainCxaGlobals[2*sizeof(long)];
 
-// called by dyldStartup.s very early
-void dyld_exceptions_init(struct mach_header* mh, intptr_t slide)
-{
-       // record location of unwind sections in dyld itself
-    sDyldInfo.mh = mh;    
-       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, "__TEXT") == 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, "__eh_frame") == 0 ) {
-                                               sDyldInfo.dwarf_section = (void*)(sect[j].addr + slide);
-                                               sDyldInfo.dwarf_section_length = sect[j].size;
-                                       }
-                                       else if ( strcmp(sect[j].sectname, "__unwind_info") == 0 ) {
-                                               sDyldInfo.compact_unwind_section = (void*)(sect[j].addr + slide);
-                                               sDyldInfo.compact_unwind_section_length = sect[j].size;
-                                       }
-                               }
-                               sDyldTextEnd = (void*)(seg->vmaddr + seg->vmsize + slide);
-                   }
-               }
-           cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
-       }
-}
-
-// called by libuwind code to find unwind information in dyld
-bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
-{
-       if ( ((void*)sDyldInfo.mh < addr) && (addr < sDyldTextEnd) ) { 
-               *info = sDyldInfo;
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-
-
 // 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 < 5) )
+       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) )
                return sPreMainCxaGlobals;
 
        if ( sCxaKey == 0 ) {
@@ -116,9 +76,10 @@ char* __cxa_get_globals()
                // 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*)pthread_getspecific(sCxaKey);
+       char* data = (char*)_ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey);
        if ( data == NULL ) {
-               data = calloc(2,sizeof(void*));
+        long* t = (long*)calloc(2,sizeof(long));
+               data = (char*)t;
                _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data);
        }
        return data; 
@@ -128,199 +89,117 @@ char* __cxa_get_globals()
 char* __cxa_get_globals_fast() 
 { 
        // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
-       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
+       if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) )
                return sPreMainCxaGlobals;
 
-       return pthread_getspecific(sCxaKey); 
+       return _ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); 
 }
 
-#if __ppc__
-       // the ppc version of _Znwm in libstdc++.a uses keymgr
-       // need to override that
-       void* _Znwm(size_t size) { return malloc(size); }
-#endif
-
-
-
-
-
-#else /*  __i386__ || __x86_64 || __ppc__ */
-
-
-
-
 
 
+#if !__USING_SJLJ_EXCEPTIONS__
 //
-// 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
+//  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");
 
-//
-// dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc.
-//
-// 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.
-//
-// Note: This exception handling is completely separate from any user code exception .
-//              handling which has its own keymgr (in libSystem).
-// 
-
-
-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
+extern void*  textStart __asm("section$start$__TEXT$__text");
+extern void*  textEnd   __asm("section$end$__TEXT$__text");
 
+extern void* __dso_handle;
 
-// called by dyldStartup.s very early
-void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
+// called by libuwind code to find unwind information sections in dyld
+bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
 {
-       sDyldImage.this_size = sizeof(struct live_images);
-       sDyldImage.mh = mh;
-       sDyldImage.vm_slide = slide;
+       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 {
+               return false;
+       }
 }
 
+#else
+//
+//  When dyld uses setjump-longjump exceptions it needs to implement 
+//  routines to push and pop a stack of _Unwind_FunctionContext.
+//
 
+struct _Unwind_FunctionContext
+{
+       // next function in stack of handlers
+       struct _Unwind_FunctionContext*         prev;
 
-//  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
+};
 
-static __attribute__((noreturn)) 
-void dyld_abort() 
-{
-       //dyld::log("internal dyld error\n");
-       _exit(1);
-}
 
-void* _keymgr_get_and_lock_processwide_ptr(unsigned int key)
-{
-       // The C++ exception handling code uses two keys. No other keys should be seen
-       if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
-               return &sDyldImage;
-       }
-       else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
-               return sObjectList;
-       }
-       dyld_abort();
-}
+static pthread_key_t                                           sThreadChainKey = 0; 
+static struct _Unwind_FunctionContext*         sStaticThreadChain = NULL; 
 
-void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value)
+//
+// 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)
 {
-       // 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();
+       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));
 }
 
-void _keymgr_unlock_processwide_ptr(unsigned int key)
-{
-       // 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
 
-       // used by std::termination which dyld does not use
-       dyld_abort();
-}
+//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");
+//}
 
-void _keymgr_set_per_thread_data(unsigned int key, void *keydata)
+
+struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
 {
-#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;
+       //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(),           key=%d, ", sThreadChainKey);
+       //printChain();
+       if ( sThreadChainKey != 0 ) {
+               return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
+       }
+       else {
+               return sStaticThreadChain;
        }
-#endif
-       // used by std::termination which dyld does not use
-       dyld_abort();
 }
 
-
-// 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)
+void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
 {
-       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 );
-       }
-       return NULL;
+       //_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
-
 #endif