]> git.saurik.com Git - apple/dyld.git/blame_incremental - src/dyldExceptions.c
dyld-195.6.tar.gz
[apple/dyld.git] / src / dyldExceptions.c
... / ...
CommitLineData
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
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 < 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
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 < 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
105static struct dyld_unwind_sections sDyldInfo;
106static void* sDyldTextEnd;
107
108// called by dyldStartup.s very early
109void 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
140bool _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
162struct _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//
173void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
174{
175}
176
177static pthread_key_t sThreadChainKey = 0;
178static 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//
185void __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
210struct _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
222void __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