1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 2 * 3 * Copyright (c) 2004-2011 Apple Inc. All rights reserved. 4 * 5 * @APPLE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include <stdlib.h> 26#include <string.h> 27#include <mach-o/loader.h> 28#include <unistd.h> 29#include <stdio.h> 30#include <stdbool.h> 31#include <stdarg.h> 32#include <pthread.h> 33#include <Availability.h> 34 35#include "mach-o/dyld_priv.h" 36#include "dyldLibSystemInterface.h" 37 38 39extern void _ZN4dyld3logEPKcz(const char*, ...); 40extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE; 41 42 43#if __LP64__ 44 #define LC_SEGMENT_COMMAND LC_SEGMENT_64 45 #define macho_header mach_header_64 46 #define macho_segment_command segment_command_64 47 #define macho_section section_64 48 #define getsectdatafromheader getsectdatafromheader_64 49#else 50 #define LC_SEGMENT_COMMAND LC_SEGMENT 51 #define macho_header mach_header 52 #define macho_segment_command segment_command 53 #define macho_section section 54#endif 55 56 57// 58// The standard versions of __cxa_get_globals*() from libstdc++-static.a cannot be used. 59// On Mac OS X, they use keymgr which dyld does not implement. 60// On iPhoneOS, they use pthread_key_create which dyld cannot use. 61// 62// Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key 63// 64static pthread_key_t sCxaKey = 0; 65static char sPreMainCxaGlobals[2*sizeof(long)]; 66 67// called by libstdc++.a 68char* __cxa_get_globals() 69{ 70 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global 71 if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) ) 72 return sPreMainCxaGlobals; 73 74 if ( sCxaKey == 0 ) { 75 // create key 76 // we don't need a lock because only one thread can be in dyld at a time 77 _ZN4dyld17gLibSystemHelpersE->pthread_key_create(&sCxaKey, &free); 78 } 79 char* data = (char*)_ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); 80 if ( data == NULL ) { 81 data = calloc(2,sizeof(void*)); 82 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data); 83 } 84 return data; 85} 86 87// called by libstdc++.a 88char* __cxa_get_globals_fast() 89{ 90 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global 91 if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) ) 92 return sPreMainCxaGlobals; 93 94 return _ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); 95} 96 97 98 99#if !__USING_SJLJ_EXCEPTIONS__ 100// 101// When dyld uses zero-cost exceptions it just needs to implement 102// _dyld_find_unwind_sections to return sections inside dyld proper. 103// 104 105extern void* ehStart __asm("section$start$__TEXT$__eh_frame"); 106extern void* ehEnd __asm("section$end$__TEXT$__eh_frame"); 107extern void* uwStart __asm("section$start$__TEXT$__unwind_info"); 108extern void* uwEnd __asm("section$end$__TEXT$__unwind_info"); 109 110extern void* textStart __asm("section$start$__TEXT$__text"); 111extern void* textEnd __asm("section$end$__TEXT$__text"); 112 113extern void* __dso_handle; 114 115// called by libuwind code to find unwind information sections in dyld 116bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info) 117{ 118 if ( ((void*)&textStart < addr) && (addr < (void*)&textEnd) ) { 119 info->mh = (struct mach_header*)&__dso_handle; 120 info->dwarf_section = &ehStart; 121 info->dwarf_section_length = ((char*)&ehEnd - (char*)&ehStart); 122 info->compact_unwind_section = &uwStart; 123 info->compact_unwind_section_length = ((char*)&uwEnd - (char*)&uwStart); 124 return true; 125 } 126 else { 127 return false; 128 } 129} 130 131#else 132// 133// When dyld uses setjump-longjump exceptions it needs to implement 134// routines to push and pop a stack of _Unwind_FunctionContext. 135// 136 137struct _Unwind_FunctionContext 138{ 139 // next function in stack of handlers 140 struct _Unwind_FunctionContext* prev; 141 142}; 143 144 145static pthread_key_t sThreadChainKey = 0; 146static struct _Unwind_FunctionContext* sStaticThreadChain = NULL; 147 148// 149// When libSystem's initializers are run, they call back into dyld's 150// registerThreadHelpers which creates a pthread key and calls 151// __Unwind_SjLj_SetThreadKey(). 152// 153void __Unwind_SjLj_SetThreadKey(pthread_key_t key) 154{ 155 sThreadChainKey = key; 156 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain); 157 // switch static chain to be per thread 158 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, sStaticThreadChain); 159 sStaticThreadChain = NULL; 160 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey)); 161} 162 163 164//static void printChain() 165//{ 166// _ZN4dyld3logEPKcz("chain: "); 167// struct _Unwind_FunctionContext* start = sStaticThreadChain; 168// if ( sThreadChainKey != 0 ) { 169// start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); 170// } 171// for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) { 172// _ZN4dyld3logEPKcz("%p -> ", p); 173// } 174// _ZN4dyld3logEPKcz("\n"); 175//} 176 177 178struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack() 179{ 180 //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(), key=%d, ", sThreadChainKey); 181 //printChain(); 182 if ( sThreadChainKey != 0 ) { 183 return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); 184 } 185 else { 186 return sStaticThreadChain; 187 } 188} 189 190void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc) 191{ 192 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n", 193 // fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL); 194 if ( sThreadChainKey != 0 ) 195 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, fc); 196 else 197 sStaticThreadChain = fc; 198 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey); 199 //printChain(); 200} 201 202#endif 203 204 205 206