]>
Commit | Line | Data |
---|---|---|
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- | |
2 | * | |
3 | * Copyright (c) 2004-2008 Apple Computer, 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 | extern void _ZN4dyld3logEPKcz(const char*, ...); | |
39 | extern 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 | // | |
63 | static pthread_key_t sCxaKey = 0; | |
64 | static char sPreMainCxaGlobals[2*sizeof(long)]; | |
65 | ||
66 | // called by libstdc++.a | |
67 | char* __cxa_get_globals() | |
68 | { | |
69 | // if libSystem.dylib not yet initialized, or is old libSystem, use shared global | |
70 | if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) ) | |
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*)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 | |
87 | char* __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 < 5) ) | |
91 | return sPreMainCxaGlobals; | |
92 | ||
93 | return pthread_getspecific(sCxaKey); | |
94 | } | |
95 | ||
96 | ||
97 | ||
98 | ||
99 | #if __x86_64__ || __i386__ || __ppc__ | |
100 | // | |
101 | // The intel/ppc versions of dyld uses zero-cost exceptions which are handled by | |
102 | // linking with a special copy of libunwind.a | |
103 | // | |
104 | ||
105 | static struct dyld_unwind_sections sDyldInfo; | |
106 | static void* sDyldTextEnd; | |
107 | ||
108 | // called by dyldStartup.s very early | |
109 | void dyld_exceptions_init(struct mach_header* mh, intptr_t slide) | |
110 | { | |
111 | // record location of unwind sections in dyld itself | |
112 | sDyldInfo.mh = mh; | |
113 | const struct load_command* cmd; | |
114 | unsigned long i; | |
115 | cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header)); | |
116 | for(i = 0; i < mh->ncmds; i++) { | |
117 | if ( cmd->cmd == LC_SEGMENT_COMMAND ) { | |
118 | const struct macho_segment_command* seg = (struct macho_segment_command*)cmd; | |
119 | if ( strcmp(seg->segname, "__TEXT") == 0 ) { | |
120 | const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) ); | |
121 | unsigned long j; | |
122 | for (j = 0; j < seg->nsects; j++) { | |
123 | if ( strcmp(sect[j].sectname, "__eh_frame") == 0 ) { | |
124 | sDyldInfo.dwarf_section = (void*)(sect[j].addr + slide); | |
125 | sDyldInfo.dwarf_section_length = sect[j].size; | |
126 | } | |
127 | else if ( strcmp(sect[j].sectname, "__unwind_info") == 0 ) { | |
128 | sDyldInfo.compact_unwind_section = (void*)(sect[j].addr + slide); | |
129 | sDyldInfo.compact_unwind_section_length = sect[j].size; | |
130 | } | |
131 | } | |
132 | sDyldTextEnd = (void*)(seg->vmaddr + seg->vmsize + slide); | |
133 | } | |
134 | } | |
135 | cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize ); | |
136 | } | |
137 | } | |
138 | ||
139 | // called by libuwind code to find unwind information in dyld | |
140 | bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info) | |
141 | { | |
142 | if ( ((void*)sDyldInfo.mh < addr) && (addr < sDyldTextEnd) ) { | |
143 | *info = sDyldInfo; | |
144 | return true; | |
145 | } | |
146 | else { | |
147 | return false; | |
148 | } | |
149 | } | |
150 | ||
151 | #if __ppc__ | |
152 | // the ppc version of _Znwm in libstdc++.a uses keymgr | |
153 | // need to override that | |
154 | void* _Znwm(size_t size) { return malloc(size); } | |
155 | #endif | |
156 | ||
157 | #endif // __MAC_OS_X_VERSION_MIN_REQUIRED | |
158 | ||
159 | ||
160 | #if __arm__ | |
161 | ||
162 | struct _Unwind_FunctionContext | |
163 | { | |
164 | // next function in stack of handlers | |
165 | struct _Unwind_FunctionContext* prev; | |
166 | ||
167 | }; | |
168 | ||
169 | // | |
170 | // The ARM of dyld use SL-LJ based exception handling | |
171 | // which does not require any initialization until libSystem is initialized. | |
172 | // | |
173 | void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide) | |
174 | { | |
175 | } | |
176 | ||
177 | static pthread_key_t sThreadChainKey = 0; | |
178 | static struct _Unwind_FunctionContext* sStaticThreadChain = NULL; | |
179 | ||
180 | // | |
181 | // When libSystem's initializers are run, they call back into dyld's | |
182 | // registerThreadHelpers which creates a pthread key and calls | |
183 | // __Unwind_SjLj_SetThreadKey(). | |
184 | // | |
185 | void __Unwind_SjLj_SetThreadKey(pthread_key_t key) | |
186 | { | |
187 | sThreadChainKey = key; | |
188 | //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain); | |
189 | // switch static chain to be per thread | |
190 | _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, sStaticThreadChain); | |
191 | sStaticThreadChain = NULL; | |
192 | //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey)); | |
193 | } | |
194 | ||
195 | ||
196 | //static void printChain() | |
197 | //{ | |
198 | // _ZN4dyld3logEPKcz("chain: "); | |
199 | // struct _Unwind_FunctionContext* start = sStaticThreadChain; | |
200 | // if ( sThreadChainKey != 0 ) { | |
201 | // start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); | |
202 | // } | |
203 | // for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) { | |
204 | // _ZN4dyld3logEPKcz("%p -> ", p); | |
205 | // } | |
206 | // _ZN4dyld3logEPKcz("\n"); | |
207 | //} | |
208 | ||
209 | ||
210 | struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack() | |
211 | { | |
212 | //_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(), key=%d, ", sThreadChainKey); | |
213 | //printChain(); | |
214 | if ( sThreadChainKey != 0 ) { | |
215 | return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey); | |
216 | } | |
217 | else { | |
218 | return sStaticThreadChain; | |
219 | } | |
220 | } | |
221 | ||
222 | void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc) | |
223 | { | |
224 | //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n", | |
225 | // fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL); | |
226 | if ( sThreadChainKey != 0 ) | |
227 | _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, fc); | |
228 | else | |
229 | sStaticThreadChain = fc; | |
230 | //_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey); | |
231 | //printChain(); | |
232 | } | |
233 | ||
234 | #endif | |
235 | ||
236 | ||
237 |