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 38extern void _ZN4dyld3logEPKcz(const char*, ...); 39extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE; 40 41 42#if __LP64__ 43 #define LC_SEGMENT_COMMAND LC_SEGMENT_64 44 #define macho_header mach_header_64 45 #define macho_segment_command segment_command_64 46 #define macho_section section_64 47 #define getsectdatafromheader getsectdatafromheader_64 48#else 49 #define LC_SEGMENT_COMMAND LC_SEGMENT 50 #define macho_header mach_header 51 #define macho_segment_command segment_command 52 #define macho_section section 53#endif 54 55 56// 57// The standard versions of __cxa_get_globals*() from libstdc++-static.a cannot be used. 58// On Mac OS X, they use keymgr which dyld does not implement. 59// On iPhoneOS, they use pthread_key_create which dyld cannot use. 60// 61// Implement these ourselves to make upcalls into libSystem to malloc and create a pthread key 62// 63static pthread_key_t sCxaKey = 0; 64static char sPreMainCxaGlobals[2*sizeof(long)]; 65 66// called by libstdc++.a 67char* __cxa_get_globals() 68{ 69 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global 70 if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) ) 71 return sPreMainCxaGlobals; 72 73 if ( sCxaKey == 0 ) { 74 // create key 75 // we don't need a lock because only one thread can be in dyld at a time 76 _ZN4dyld17gLibSystemHelpersE->pthread_key_create(&sCxaKey, &free); 77 } 78 char* data = (char*)_ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); 79 if ( data == NULL ) { 80 data = calloc(2,sizeof(void*)); 81 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data); 82 } 83 return data; 84} 85 86// called by libstdc++.a 87char* __cxa_get_globals_fast() 88{ 89 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global 90 if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 7) ) 91 return sPreMainCxaGlobals; 92 93 return _ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey); 94} 95 96 97 98 99#if !__arm__ 100// 101// The intel versions of dyld uses zero-cost exceptions which are handled by 102// linking with a special copy of libunwind.a 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#endif // !__arm__ 132 133 134#if __arm__ 135 136struct _Unwind_FunctionContext 137{ 138 // next function in stack of handlers 139 struct _Unwind_FunctionContext* prev; 140 141}; 142 143 144static pthread_key_t sThreadChainKey = 0; 145static struct _Unwind_FunctionContext* sStaticThreadChain = NULL; 146 147// 148// When libSystem's initializers are run, they call back into dyld's 149// registerThreadHelpers which creates a pthread key and calls 150// __Unwind_SjLj_SetThreadKey(). 151// 152void __Unwind_SjLj_SetThreadKey(pthread_key_t key) 153{ 154 sThreadChainKey = key; 155 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain); 156 // switch static chain to be per thread 157 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, sStaticThreadChain); 158 sStaticThreadChain = NULL; 159 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey)); 160} 161 162 163//static void printChain() 164//{ 165// _ZN4dyld3logEPKcz("chain: "); 166// struct _Unwind_FunctionContext* start = sStaticThreadChain; 167// if ( sThreadChainKey != 0 ) { 168// start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); 169// } 170// for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) { 171// _ZN4dyld3logEPKcz("%p -> ", p); 172// } 173// _ZN4dyld3logEPKcz("\n"); 174//} 175 176 177struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack() 178{ 179 //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(), key=%d, ", sThreadChainKey); 180 //printChain(); 181 if ( sThreadChainKey != 0 ) { 182 return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); 183 } 184 else { 185 return sStaticThreadChain; 186 } 187} 188 189void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc) 190{ 191 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n", 192 // fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL); 193 if ( sThreadChainKey != 0 ) 194 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, fc); 195 else 196 sStaticThreadChain = fc; 197 //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey); 198 //printChain(); 199} 200 201#endif 202 203 204 205