dyld-46.16.tar.gz
[apple/dyld.git] / src / dyldExceptions.c
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2005 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 <stdio.h>
28 #include <mach-o/loader.h>
29
30 //
31 // BEGIN copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
32 //
33 #define KEYMGR_API_MAJOR_GCC3 3
34 /* ... with these keys. */
35 #define KEYMGR_GCC3_LIVE_IMAGE_LIST 301 /* loaded images */
36 #define KEYMGR_GCC3_DW2_OBJ_LIST 302 /* Dwarf2 object list */
37 #define KEYMGR_EH_GLOBALS_KEY 13
38
39 /* Node of KEYMGR_GCC3_LIVE_IMAGE_LIST. Info about each resident image. */
40 struct live_images {
41 unsigned long this_size; /* sizeof (live_images) */
42 struct mach_header *mh; /* the image info */
43 unsigned long vm_slide;
44 void (*destructor)(struct live_images *); /* destructor for this */
45 struct live_images *next;
46 unsigned int examined_p;
47 void *fde;
48 void *object_info;
49 unsigned long info[2]; /* Future use. */
50 };
51 //
52 // END copy of code from libgcc.a source file unwind-dw2-fde-darwin.c
53 //
54
55
56 //
57 // dyld is built as stand alone executable with a static copy of libc, libstdc++, and libgcc.
58 //
59 // In order for C++ exceptions to work within dyld, the C++ exception handling code
60 // must be able to find the exception handling frame data inside dyld. The standard
61 // exception handling code uses crt and keymgr to keep track of all images and calls
62 // getsectdatafromheader("__eh_frame") to find the EH data for each image. We implement
63 // our own copy of those functions below to enable exceptions within dyld.
64 //
65 // Note: This exception handling is completely separate from any user code exception .
66 // handling which has its own keymgr (in libSystem).
67 //
68
69
70 static struct live_images sDyldImage; // zero filled
71 static void* sObjectList = NULL;
72 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
73 static void* sEHGlobals = NULL;
74 #endif
75
76
77 // called by dyldStartup.s very early
78 void dyld_exceptions_init(struct mach_header *mh, uintptr_t slide)
79 {
80 sDyldImage.this_size = sizeof(struct live_images);
81 sDyldImage.mh = mh;
82 sDyldImage.vm_slide = slide;
83 }
84
85
86
87 // Hack for gcc 3.5's use of keymgr includes accessing __keymgr_global
88 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
89 typedef struct Sinfo_Node {
90 uint32_t size; /* Size of this node. */
91 uint16_t major_version; /* API major version. */
92 uint16_t minor_version; /* API minor version. */
93 } Tinfo_Node;
94 static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 };
95 const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info };
96 #endif
97
98 static __attribute__((noreturn))
99 void dyld_abort()
100 {
101 fprintf(stderr, "internal dyld error\n");
102 abort();
103 }
104
105 void* _keymgr_get_and_lock_processwide_ptr(unsigned int key)
106 {
107 // The C++ exception handling code uses two keys. No other keys should be seen
108 if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
109 return &sDyldImage;
110 }
111 else if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
112 return sObjectList;
113 }
114 dyld_abort();
115 }
116
117 void _keymgr_set_and_unlock_processwide_ptr(unsigned int key, void* value)
118 {
119 // The C++ exception handling code uses just this key. No other keys should be seen
120 if ( key == KEYMGR_GCC3_DW2_OBJ_LIST ) {
121 sObjectList = value;
122 return;
123 }
124 dyld_abort();
125 }
126
127 void _keymgr_unlock_processwide_ptr(unsigned int key)
128 {
129 // The C++ exception handling code uses just this key. No other keys should be seen
130 if ( key == KEYMGR_GCC3_LIVE_IMAGE_LIST ) {
131 return;
132 }
133 dyld_abort();
134 }
135
136 void* _keymgr_get_per_thread_data(unsigned int key)
137 {
138 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
139 // gcc 3.5 and later use this key
140 if ( key == KEYMGR_EH_GLOBALS_KEY )
141 return sEHGlobals;
142 #endif
143
144 // used by std::termination which dyld does not use
145 dyld_abort();
146 }
147
148 void _keymgr_set_per_thread_data(unsigned int key, void *keydata)
149 {
150 #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
151 // gcc 3.5 and later use this key
152 if ( key == KEYMGR_EH_GLOBALS_KEY ) {
153 sEHGlobals = keydata;
154 return;
155 }
156 #endif
157 // used by std::termination which dyld does not use
158 dyld_abort();
159 }
160
161 #if __LP64__
162 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
163 #define macho_header mach_header_64
164 #define macho_segment_command segment_command_64
165 #define macho_section section_64
166 #define getsectdatafromheader getsectdatafromheader_64
167 #else
168 #define LC_SEGMENT_COMMAND LC_SEGMENT
169 #define macho_header mach_header
170 #define macho_segment_command segment_command
171 #define macho_section section
172 #endif
173
174 // needed by C++ exception handling code to find __eh_frame section
175 const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
176 {
177 const struct load_command* cmd;
178 unsigned long i;
179
180 cmd = (struct load_command*) ((char *)mh + sizeof(struct macho_header));
181 for(i = 0; i < mh->ncmds; i++) {
182 if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
183 const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
184 if ( strcmp(seg->segname, segname) == 0 ) {
185 const struct macho_section* sect = (struct macho_section*)( (char*)seg + sizeof(struct macho_segment_command) );
186 unsigned long j;
187 for (j = 0; j < seg->nsects; j++) {
188 if ( strcmp(sect[j].sectname, sectname) == 0 ) {
189 *size = sect[j].size;
190 return (void*)(sect[j].addr);
191 }
192 }
193 }
194 }
195 cmd = (struct load_command*)( (char*)cmd + cmd->cmdsize );
196 }
197 return NULL;
198 }
199
200
201 // Hack for transition of rdar://problem/3933738
202 // Can be removed later.
203 // Allow C++ runtime to call getsectdatafromheader or getsectdatafromheader_64
204 #if __LP64__
205 #undef getsectdatafromheader
206 const void* getsectdatafromheader(struct mach_header* mh, const char* segname, const char* sectname, unsigned long* size)
207 {
208 return getsectdatafromheader_64(mh, segname, sectname, size);
209 }
210 #endif
211
212