1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2011 Apple 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 < 7) )
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*)_ZN4dyld17gLibSystemHelpersE->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 < 7) )
91		return sPreMainCxaGlobals;
92
93	return _ZN4dyld17gLibSystemHelpersE->pthread_getspecific(sCxaKey);
94}
95
96
97
98
99#if !__arm__
100//
101//  The intel versions of dyld uses zero-cost exceptions which are handled by
102//  linking with a special copy of libunwind.a
103//
104
105extern void*  ehStart  __asm("section$start$__TEXT$__eh_frame");
106extern void*  ehEnd    __asm("section$end$__TEXT$__eh_frame");
107extern void*  uwStart  __asm("section$start$__TEXT$__unwind_info");
108extern void*  uwEnd    __asm("section$end$__TEXT$__unwind_info");
109
110extern void*  textStart __asm("section$start$__TEXT$__text");
111extern void*  textEnd   __asm("section$end$__TEXT$__text");
112
113extern void* __dso_handle;
114
115// called by libuwind code to find unwind information sections in dyld
116bool _dyld_find_unwind_sections(void* addr, struct dyld_unwind_sections* info)
117{
118 	if ( ((void*)&textStart < addr) && (addr < (void*)&textEnd) ) {
119        info->mh = (struct mach_header*)&__dso_handle;
120        info->dwarf_section = &ehStart;
121        info->dwarf_section_length = ((char*)&ehEnd - (char*)&ehStart);
122        info->compact_unwind_section = &uwStart;
123        info->compact_unwind_section_length = ((char*)&uwEnd - (char*)&uwStart);
124		return true;
125	}
126	else {
127		return false;
128	}
129}
130
131#endif // !__arm__
132
133
134#if __arm__
135
136struct _Unwind_FunctionContext
137{
138	// next function in stack of handlers
139	struct _Unwind_FunctionContext*		prev;
140
141};
142
143
144static pthread_key_t						sThreadChainKey = 0;
145static struct _Unwind_FunctionContext*		sStaticThreadChain = NULL;
146
147//
148// When libSystem's initializers are run, they call back into dyld's
149// registerThreadHelpers which creates a pthread key and calls
150//  __Unwind_SjLj_SetThreadKey().
151//
152void __Unwind_SjLj_SetThreadKey(pthread_key_t key)
153{
154	sThreadChainKey = key;
155	//_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), sStaticThreadChain=%p\n", key, sStaticThreadChain);
156	// switch static chain to be per thread
157	_ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, sStaticThreadChain);
158	sStaticThreadChain = NULL;
159	//_ZN4dyld3logEPKcz("__Unwind_SjLj_SetThreadKey(key=%d), result=%d, new top=%p\n", key, result, pthread_getspecific(sThreadChainKey));
160}
161
162
163//static void printChain()
164//{
165//	_ZN4dyld3logEPKcz("chain: ");
166//	struct _Unwind_FunctionContext* start = sStaticThreadChain;
167//	if ( sThreadChainKey != 0 ) {
168//		start = (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
169//	}
170//	for (struct _Unwind_FunctionContext* p = start; p != NULL; p = p->prev) {
171//		_ZN4dyld3logEPKcz("%p -> ", p);
172//	}
173//	_ZN4dyld3logEPKcz("\n");
174//}
175
176
177struct _Unwind_FunctionContext* __Unwind_SjLj_GetTopOfFunctionStack()
178{
179	//_ZN4dyld3logEPKcz("__Unwind_SjLj_GetTopOfFunctionStack(),           key=%d, ", sThreadChainKey);
180	//printChain();
181	if ( sThreadChainKey != 0 ) {
182		return (struct _Unwind_FunctionContext*)pthread_getspecific(sThreadChainKey);
183	}
184	else {
185		return sStaticThreadChain;
186	}
187}
188
189void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext* fc)
190{
191	//_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, prev=%p\n",
192	//	fc, sThreadChainKey, (fc != NULL) ? fc->prev : NULL);
193	if ( sThreadChainKey != 0 )
194		_ZN4dyld17gLibSystemHelpersE->pthread_setspecific(sThreadChainKey, fc);
195	else
196		sStaticThreadChain = fc;
197	//_ZN4dyld3logEPKcz("__Unwind_SjLj_SetTopOfFunctionStack(%p), key=%d, ", fc, sThreadChainKey);
198	//printChain();
199}
200
201#endif
202
203
204
205