]> git.saurik.com Git - apple/dyld.git/blame - src/dyldExceptions.c
dyld-43.1.tar.gz
[apple/dyld.git] / src / dyldExceptions.c
CommitLineData
0959b6d4
A
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. */
40struct 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
70static struct live_images sDyldImage; // zero filled
71static void* sObjectList = NULL;
72#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ >= 4))
73static void* sEHGlobals = NULL;
74#endif
75
76
77// called by dyldStartup.s very early
78void 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))
89typedef 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;
94static const Tinfo_Node keymgr_info = { sizeof (Tinfo_Node), KEYMGR_API_MAJOR_GCC3, 0 };
95const Tinfo_Node* __keymgr_global[3] = { NULL, NULL, &keymgr_info };
96#endif
97
98static __attribute__((noreturn))
99void dyld_abort()
100{
101 fprintf(stderr, "internal dyld error\n");
102 abort();
103}
104
105void* _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
117void _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
127void _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
136void* _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
148void _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
175const 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 __ppc64__
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