]> git.saurik.com Git - apple/dyld.git/blob - src/dyldExceptions.c
0cf1a18ec44fcc5e76a59a342b340dfc31069889
[apple/dyld.git] / src / dyldExceptions.c
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
34 #include "mach-o/dyld_priv.h"
35 #include "dyldLibSystemInterface.h"
36
37 extern void _ZN4dyld3logEPKcz(const char*, ...);
38 extern struct LibSystemHelpers* _ZN4dyld17gLibSystemHelpersE;
39
40
41 #if __LP64__
42 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
43 #define macho_header mach_header_64
44 #define macho_segment_command segment_command_64
45 #define macho_section section_64
46 #define getsectdatafromheader getsectdatafromheader_64
47 #else
48 #define LC_SEGMENT_COMMAND LC_SEGMENT
49 #define macho_header mach_header
50 #define macho_segment_command segment_command
51 #define macho_section section
52 #endif
53
54
55 #if __i386__ || __x86_64 || __ppc__
56
57 static struct dyld_unwind_sections sDyldInfo;
58 static void* sDyldTextEnd;
59 static pthread_key_t sCxaKey = 0;
60 static char sPreMainCxaGlobals[2*sizeof(long)];
61
62 // called by dyldStartup.s very early
63 void dyld_exceptions_init(struct mach_header* mh, intptr_t slide)
64 {
65 // record location of unwind sections in dyld itself
66 sDyldInfo.mh = mh;
67 const struct load_command* cmd;
68 unsigned long i;
69 cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
70 for(i = 0; i < mh->ncmds; i++) {
71 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
72 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
73 if ( strcmp(seg->segname, "__TEXT") == 0 ) {
74 const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
75 unsigned long j;
76 for (j = 0; j < seg->nsects; j++) {
77 if ( strcmp(sect[j].sectname, "__eh_frame") == 0 ) {
78 sDyldInfo.dwarf_section = (void*)(sect[j].addr + slide);
79 sDyldInfo.dwarf_section_length = sect[j].size;
80 }
81 else if ( strcmp(sect[j].sectname, "__unwind_info") == 0 ) {
82 sDyldInfo.compact_unwind_section = (void*)(sect[j].addr + slide);
83 sDyldInfo.compact_unwind_section_length = sect[j].size;
84 }
85 }
86 sDyldTextEnd = (void*)(seg->vmaddr + seg->vmsize + slide);
87 }
88 }
89 cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
90 }
91 }
92
93 // called by libuwind code to find unwind information in dyld
94 bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
95 {
96 if ( ((void*)sDyldInfo.mh < addr) && (addr < sDyldTextEnd) ) {
97 *info = sDyldInfo;
98 return true;
99 }
100 else {
101 return false;
102 }
103 }
104
105
106
107 // called by libstdc++.a
108 char* __cxa_get_globals()
109 {
110 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
111 if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
112 return sPreMainCxaGlobals;
113
114 if ( sCxaKey == 0 ) {
115 // create key
116 // we don't need a lock because only one thread can be in dyld at a time
117 _ZN4dyld17gLibSystemHelpersE->pthread_key_create(&sCxaKey, &free);
118 }
119 char* data = (char*)pthread_getspecific(sCxaKey);
120 if ( data == NULL ) {
121 data = calloc(2,sizeof(void*));
122 _ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sCxaKey, data);
123 }
124 return data;
125 }
126
127 // called by libstdc++.a
128 char* __cxa_get_globals_fast()
129 {
130 // if libSystem.dylib not yet initialized, or is old libSystem, use shared global
131 if ( (_ZN4dyld17gLibSystemHelpersE == NULL) || (_ZN4dyld17gLibSystemHelpersE->version < 5) )
132 return sPreMainCxaGlobals;
133
134 return pthread_getspecific(sCxaKey);
135 }
136
137 #if __ppc__
138 // the ppc version of _Znwm in libstdc++.a uses keymgr
139 // need to override that
140 void* _Znwm(size_t size) { return malloc(size); }
141 #endif
142
143
144
145
146
147 #else /* __i386__ || __x86_64 || __ppc__ */
148
149
150
151
152
153
154 //
155 // BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
156 //
157 #define KEYMGR_API_MAJOR_GCC3 3
158 /* ... with these keys. */
159 #define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */
160 #define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */
161 #define KEYMGR_EH_GLOBALS_KEY 13
162
163 /* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */
164 struct live_images {
165 unsigned long this_size; /* sizeof (live_images) */
166 struct mach_header *mh; /* the image info */
167 unsigned long vm_slide;
168 void (*destructor)(struct live_images *); /* destructor for this */
169 struct live_images *next;
170 unsigned int examined_p;
171 void *fde;
172 void *object_info;
173 unsigned long info[2]; /* Future use. */
174 };
175 //
176 // END copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
177 //
178
179
180 //
181 // dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc.
182 //
183 // In order for C++ exceptions to work within dyld, the C++ exception handling code
184 // must be able to find the exception handling frame data inside dyld. The standard
185 // exception handling code uses crt and keymgr to keep track of all images and calls
186 // getsectdatafromheader("__eh_frame") to find the EH data for each image. We implement
187 // our own copy of those functions below to enable exceptions within dyld.
188 //
189 // Note: This exception handling is completely separate from any user code exception .
190 // handling which has its own keymgr (in libSystem).
191 //
192
193
194 static struct live_images sDyldImage; // zero filled
195 static void* sObjectList = NULL;
196 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
197 static void* sEHGlobals = NULL;
198 #endif
199
200
201 // called by dyldStartup.s very early
202 void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
203 {
204 sDyldImage.this_size = sizeof(struct live_images);
205 sDyldImage.mh = mh;
206 sDyldImage.vm_slide = slide;
207 }
208
209
210
211 // Hack for gcc 3.5's use of keymgr includes accessing __keymgr_global
212 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
213 typedef struct Sinfo_Node {
214 uint32_t size; /* Size of this node. */
215 uint16_t major_version; /* API major version. */
216 uint16_t minor_version; /* API minor version. */
217 } Tinfo_Node;
218 static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 };
219 const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info };
220 #endif
221
222 static __attribute__((noreturn))
223 void dyld_abort()
224 {
225 //dyld::log("internal dyld error\n");
226 _exit(1);
227 }
228
229 void* _keymgr_get_and_lock_processwide_ptr(unsigned int key)
230 {
231 // The C++ exception handling code uses two keys. No other keys should be seen
232 if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
233 return &sDyldImage;
234 }
235 else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
236 return sObjectList;
237 }
238 dyld_abort();
239 }
240
241 void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value)
242 {
243 // The C++ exception handling code uses just this key. No other keys should be seen
244 if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
245 sObjectList = value;
246 return;
247 }
248 dyld_abort();
249 }
250
251 void _keymgr_unlock_processwide_ptr(unsigned int key)
252 {
253 // The C++ exception handling code uses just this key. No other keys should be seen
254 if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
255 return;
256 }
257 dyld_abort();
258 }
259
260 void* _keymgr_get_per_thread_data(unsigned int key)
261 {
262 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
263 // gcc 3.5 and later use this key
264 if ( key == KEYMGR_EH_GLOBALS_KEY )
265 return sEHGlobals;
266 #endif
267
268 // used by std::termination which dyld does not use
269 dyld_abort();
270 }
271
272 void _keymgr_set_per_thread_data(unsigned int key, void *keydata)
273 {
274 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
275 // gcc 3.5 and later use this key
276 if ( key == KEYMGR_EH_GLOBALS_KEY ) {
277 sEHGlobals = keydata;
278 return;
279 }
280 #endif
281 // used by std::termination which dyld does not use
282 dyld_abort();
283 }
284
285
286 // needed by C++ exception handling code to find __eh_frame section
287 const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
288 {
289 const struct load_command* cmd;
290 unsigned long i;
291
292 cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
293 for(i = 0; i < mh->ncmds; i++) {
294 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
295 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
296 if ( strcmp(seg->segname, segname) == 0 ) {
297 const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
298 unsigned long j;
299 for (j = 0; j < seg->nsects; j++) {
300 if ( strcmp(sect[j].sectname, sectname) == 0 ) {
301 *size = sect[j].size;
302 return (void*)(sect[j].addr);
303 }
304 }
305 }
306 }
307 cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
308 }
309 return NULL;
310 }
311
312
313 // Hack for transition of rdar://problem/3933738
314 // Can be removed later.
315 // Allow C++ runtime to call getsectdatafromheader or getsectdatafromheader_64
316 #if __LP64__
317 #undef getsectdatafromheader
318 const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
319 {
320 return getsectdatafromheader_64(mh, segname, sectname, size);
321 }
322 #endif
323
324 #endif
325
326
327