1*e4b17023SJohn Marino /* __cxa_atexit backwards-compatibility support for Darwin.
2*e4b17023SJohn Marino Copyright (C) 2006, 2009, 2011 Free Software Foundation, Inc.
3*e4b17023SJohn Marino
4*e4b17023SJohn Marino This file is part of GCC.
5*e4b17023SJohn Marino
6*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
7*e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
8*e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
9*e4b17023SJohn Marino version.
10*e4b17023SJohn Marino
11*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*e4b17023SJohn Marino for more details.
15*e4b17023SJohn Marino
16*e4b17023SJohn Marino Under Section 7 of GPL version 3, you are granted additional
17*e4b17023SJohn Marino permissions described in the GCC Runtime Library Exception, version
18*e4b17023SJohn Marino 3.1, as published by the Free Software Foundation.
19*e4b17023SJohn Marino
20*e4b17023SJohn Marino You should have received a copy of the GNU General Public License and
21*e4b17023SJohn Marino a copy of the GCC Runtime Library Exception along with this program;
22*e4b17023SJohn Marino see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
24*e4b17023SJohn Marino
25*e4b17023SJohn Marino /* Don't do anything if we are compiling for a kext multilib. */
26*e4b17023SJohn Marino #ifdef __PIC__
27*e4b17023SJohn Marino
28*e4b17023SJohn Marino #include "tconfig.h"
29*e4b17023SJohn Marino #include "tsystem.h"
30*e4b17023SJohn Marino
31*e4b17023SJohn Marino #include <dlfcn.h>
32*e4b17023SJohn Marino #include <stdbool.h>
33*e4b17023SJohn Marino #include <stdlib.h>
34*e4b17023SJohn Marino #include <string.h>
35*e4b17023SJohn Marino
36*e4b17023SJohn Marino /* This file works around two different problems.
37*e4b17023SJohn Marino
38*e4b17023SJohn Marino The first problem is that there is no __cxa_atexit on Mac OS versions
39*e4b17023SJohn Marino before 10.4. It fixes this by providing a complete atexit and
40*e4b17023SJohn Marino __cxa_atexit emulation called from the regular atexit.
41*e4b17023SJohn Marino
42*e4b17023SJohn Marino The second problem is that on all shipping versions of Mac OS,
43*e4b17023SJohn Marino __cxa_finalize and exit() don't work right: they don't run routines
44*e4b17023SJohn Marino that were registered while other atexit routines are running. This
45*e4b17023SJohn Marino is worked around by wrapping each atexit/__cxa_atexit routine with
46*e4b17023SJohn Marino our own routine which ensures that any __cxa_atexit calls while it
47*e4b17023SJohn Marino is running are honoured.
48*e4b17023SJohn Marino
49*e4b17023SJohn Marino There are still problems which this does not solve. Before 10.4,
50*e4b17023SJohn Marino shared objects linked with previous compilers won't have their
51*e4b17023SJohn Marino atexit calls properly interleaved with code compiled with newer
52*e4b17023SJohn Marino compilers. Also, atexit routines registered from shared objects
53*e4b17023SJohn Marino linked with previous compilers won't get the bug fix. */
54*e4b17023SJohn Marino
55*e4b17023SJohn Marino typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, const void* dso);
56*e4b17023SJohn Marino typedef void (*cxa_finalize_p)(const void *dso);
57*e4b17023SJohn Marino typedef int (*atexit_p)(void (*func)(void));
58*e4b17023SJohn Marino
59*e4b17023SJohn Marino /* These are from "keymgr.h". */
60*e4b17023SJohn Marino extern void *_keymgr_get_and_lock_processwide_ptr (unsigned key);
61*e4b17023SJohn Marino extern int _keymgr_get_and_lock_processwide_ptr_2 (unsigned, void **);
62*e4b17023SJohn Marino extern int _keymgr_set_and_unlock_processwide_ptr (unsigned key, void *ptr);
63*e4b17023SJohn Marino
64*e4b17023SJohn Marino extern void *__keymgr_global[];
65*e4b17023SJohn Marino typedef struct _Sinfo_Node {
66*e4b17023SJohn Marino unsigned int size ; /*size of this node*/
67*e4b17023SJohn Marino unsigned short major_version ; /*API major version.*/
68*e4b17023SJohn Marino unsigned short minor_version ; /*API minor version.*/
69*e4b17023SJohn Marino } _Tinfo_Node ;
70*e4b17023SJohn Marino
71*e4b17023SJohn Marino #ifdef __ppc__
72*e4b17023SJohn Marino #define CHECK_KEYMGR_ERROR(e) \
73*e4b17023SJohn Marino (((_Tinfo_Node *)__keymgr_global[2])->major_version >= 4 ? (e) : 0)
74*e4b17023SJohn Marino #else
75*e4b17023SJohn Marino #define CHECK_KEYMGR_ERROR(e) (e)
76*e4b17023SJohn Marino #endif
77*e4b17023SJohn Marino
78*e4b17023SJohn Marino /* Our globals are stored under this keymgr index. */
79*e4b17023SJohn Marino #define KEYMGR_ATEXIT_LIST 14
80*e4b17023SJohn Marino
81*e4b17023SJohn Marino /* The different kinds of callback routines. */
82*e4b17023SJohn Marino typedef void (*atexit_callback)(void);
83*e4b17023SJohn Marino typedef void (*cxa_atexit_callback)(void *);
84*e4b17023SJohn Marino
85*e4b17023SJohn Marino /* This structure holds a routine to call. There may be extra fields
86*e4b17023SJohn Marino at the end of the structure that this code doesn't know about. */
87*e4b17023SJohn Marino struct one_atexit_routine
88*e4b17023SJohn Marino {
89*e4b17023SJohn Marino union {
90*e4b17023SJohn Marino atexit_callback ac;
91*e4b17023SJohn Marino cxa_atexit_callback cac;
92*e4b17023SJohn Marino } callback;
93*e4b17023SJohn Marino /* has_arg is 0/2/4 if 'ac' is live, 1/3/5 if 'cac' is live.
94*e4b17023SJohn Marino Higher numbers indicate a later version of the structure that this
95*e4b17023SJohn Marino code doesn't understand and will ignore. */
96*e4b17023SJohn Marino int has_arg;
97*e4b17023SJohn Marino void * arg;
98*e4b17023SJohn Marino };
99*e4b17023SJohn Marino
100*e4b17023SJohn Marino struct atexit_routine_list
101*e4b17023SJohn Marino {
102*e4b17023SJohn Marino struct atexit_routine_list * next;
103*e4b17023SJohn Marino struct one_atexit_routine r;
104*e4b17023SJohn Marino };
105*e4b17023SJohn Marino
106*e4b17023SJohn Marino /* The various possibilities for status of atexit(). */
107*e4b17023SJohn Marino enum atexit_status {
108*e4b17023SJohn Marino atexit_status_unknown = 0,
109*e4b17023SJohn Marino atexit_status_missing = 1,
110*e4b17023SJohn Marino atexit_status_broken = 2,
111*e4b17023SJohn Marino atexit_status_working = 16
112*e4b17023SJohn Marino };
113*e4b17023SJohn Marino
114*e4b17023SJohn Marino struct keymgr_atexit_list
115*e4b17023SJohn Marino {
116*e4b17023SJohn Marino /* Version of this list. This code knows only about version 0.
117*e4b17023SJohn Marino If the version is higher than 0, this code may add new atexit routines
118*e4b17023SJohn Marino but should not attempt to run the list. */
119*e4b17023SJohn Marino short version;
120*e4b17023SJohn Marino /* 1 if an atexit routine is currently being run by this code, 0
121*e4b17023SJohn Marino otherwise. */
122*e4b17023SJohn Marino char running_routines;
123*e4b17023SJohn Marino /* Holds a value from 'enum atexit_status'. */
124*e4b17023SJohn Marino unsigned char atexit_status;
125*e4b17023SJohn Marino /* The list of atexit and cxa_atexit routines registered. If
126*e4b17023SJohn Marino atexit_status_missing it contains all routines registered while
127*e4b17023SJohn Marino linked with this code. If atexit_status_broken it contains all
128*e4b17023SJohn Marino routines registered during cxa_finalize while linked with this
129*e4b17023SJohn Marino code. */
130*e4b17023SJohn Marino struct atexit_routine_list *l;
131*e4b17023SJohn Marino /* &__cxa_atexit; set if atexit_status >= atexit_status_broken. */
132*e4b17023SJohn Marino cxa_atexit_p cxa_atexit_f;
133*e4b17023SJohn Marino /* &__cxa_finalize; set if atexit_status >= atexit_status_broken. */
134*e4b17023SJohn Marino cxa_finalize_p cxa_finalize_f;
135*e4b17023SJohn Marino /* &atexit; set if atexit_status >= atexit_status_working
136*e4b17023SJohn Marino or atexit_status == atexit_status_missing. */
137*e4b17023SJohn Marino atexit_p atexit_f;
138*e4b17023SJohn Marino };
139*e4b17023SJohn Marino
140*e4b17023SJohn Marino /* Return 0 if __cxa_atexit has the bug it has in Mac OS 10.4: it
141*e4b17023SJohn Marino fails to call routines registered while an atexit routine is
142*e4b17023SJohn Marino running. Return 1 if it works properly, and -1 if an error occurred. */
143*e4b17023SJohn Marino
144*e4b17023SJohn Marino struct atexit_data
145*e4b17023SJohn Marino {
146*e4b17023SJohn Marino int result;
147*e4b17023SJohn Marino cxa_atexit_p cxa_atexit;
148*e4b17023SJohn Marino };
149*e4b17023SJohn Marino
cxa_atexit_check_2(void * arg)150*e4b17023SJohn Marino static void cxa_atexit_check_2 (void *arg)
151*e4b17023SJohn Marino {
152*e4b17023SJohn Marino ((struct atexit_data *)arg)->result = 1;
153*e4b17023SJohn Marino }
154*e4b17023SJohn Marino
cxa_atexit_check_1(void * arg)155*e4b17023SJohn Marino static void cxa_atexit_check_1 (void *arg)
156*e4b17023SJohn Marino {
157*e4b17023SJohn Marino struct atexit_data * aed = arg;
158*e4b17023SJohn Marino if (aed->cxa_atexit (cxa_atexit_check_2, arg, arg) != 0)
159*e4b17023SJohn Marino aed->result = -1;
160*e4b17023SJohn Marino }
161*e4b17023SJohn Marino
162*e4b17023SJohn Marino static int
check_cxa_atexit(cxa_atexit_p cxa_atexit,cxa_finalize_p cxa_finalize)163*e4b17023SJohn Marino check_cxa_atexit (cxa_atexit_p cxa_atexit, cxa_finalize_p cxa_finalize)
164*e4b17023SJohn Marino {
165*e4b17023SJohn Marino struct atexit_data aed = { 0, cxa_atexit };
166*e4b17023SJohn Marino
167*e4b17023SJohn Marino /* We re-use &aed as the 'dso' parameter, since it's a unique address. */
168*e4b17023SJohn Marino if (cxa_atexit (cxa_atexit_check_1, &aed, &aed) != 0)
169*e4b17023SJohn Marino return -1;
170*e4b17023SJohn Marino cxa_finalize (&aed);
171*e4b17023SJohn Marino if (aed.result == 0)
172*e4b17023SJohn Marino {
173*e4b17023SJohn Marino /* Call __cxa_finalize again to make sure that cxa_atexit_check_2
174*e4b17023SJohn Marino is removed from the list before AED goes out of scope. */
175*e4b17023SJohn Marino cxa_finalize (&aed);
176*e4b17023SJohn Marino aed.result = 0;
177*e4b17023SJohn Marino }
178*e4b17023SJohn Marino return aed.result;
179*e4b17023SJohn Marino }
180*e4b17023SJohn Marino
181*e4b17023SJohn Marino #ifdef __ppc__
182*e4b17023SJohn Marino /* This comes from Csu. It works only before 10.4. The prototype has
183*e4b17023SJohn Marino been altered a bit to avoid casting. */
184*e4b17023SJohn Marino extern int _dyld_func_lookup(const char *dyld_func_name,
185*e4b17023SJohn Marino void *address) __attribute__((visibility("hidden")));
186*e4b17023SJohn Marino
187*e4b17023SJohn Marino static void our_atexit (void);
188*e4b17023SJohn Marino
189*e4b17023SJohn Marino /* We're running on 10.3.9. Find the address of the system atexit()
190*e4b17023SJohn Marino function. So easy to say, so hard to do. */
191*e4b17023SJohn Marino static atexit_p
find_atexit_10_3(void)192*e4b17023SJohn Marino find_atexit_10_3 (void)
193*e4b17023SJohn Marino {
194*e4b17023SJohn Marino unsigned int (*dyld_image_count_fn)(void);
195*e4b17023SJohn Marino const char *(*dyld_get_image_name_fn)(unsigned int image_index);
196*e4b17023SJohn Marino const void *(*dyld_get_image_header_fn)(unsigned int image_index);
197*e4b17023SJohn Marino const void *(*NSLookupSymbolInImage_fn)(const void *image,
198*e4b17023SJohn Marino const char *symbolName,
199*e4b17023SJohn Marino unsigned int options);
200*e4b17023SJohn Marino void *(*NSAddressOfSymbol_fn)(const void *symbol);
201*e4b17023SJohn Marino unsigned i, count;
202*e4b17023SJohn Marino
203*e4b17023SJohn Marino /* Find some dyld functions. */
204*e4b17023SJohn Marino _dyld_func_lookup("__dyld_image_count", &dyld_image_count_fn);
205*e4b17023SJohn Marino _dyld_func_lookup("__dyld_get_image_name", &dyld_get_image_name_fn);
206*e4b17023SJohn Marino _dyld_func_lookup("__dyld_get_image_header", &dyld_get_image_header_fn);
207*e4b17023SJohn Marino _dyld_func_lookup("__dyld_NSLookupSymbolInImage", &NSLookupSymbolInImage_fn);
208*e4b17023SJohn Marino _dyld_func_lookup("__dyld_NSAddressOfSymbol", &NSAddressOfSymbol_fn);
209*e4b17023SJohn Marino
210*e4b17023SJohn Marino /* If any of these don't exist, that's an error. */
211*e4b17023SJohn Marino if (! dyld_image_count_fn || ! dyld_get_image_name_fn
212*e4b17023SJohn Marino || ! dyld_get_image_header_fn || ! NSLookupSymbolInImage_fn
213*e4b17023SJohn Marino || ! NSAddressOfSymbol_fn)
214*e4b17023SJohn Marino return NULL;
215*e4b17023SJohn Marino
216*e4b17023SJohn Marino count = dyld_image_count_fn ();
217*e4b17023SJohn Marino for (i = 0; i < count; i++)
218*e4b17023SJohn Marino {
219*e4b17023SJohn Marino const char * path = dyld_get_image_name_fn (i);
220*e4b17023SJohn Marino const void * image;
221*e4b17023SJohn Marino const void * symbol;
222*e4b17023SJohn Marino
223*e4b17023SJohn Marino if (strcmp (path, "/usr/lib/libSystem.B.dylib") != 0)
224*e4b17023SJohn Marino continue;
225*e4b17023SJohn Marino image = dyld_get_image_header_fn (i);
226*e4b17023SJohn Marino if (! image)
227*e4b17023SJohn Marino return NULL;
228*e4b17023SJohn Marino /* '4' is NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR. */
229*e4b17023SJohn Marino symbol = NSLookupSymbolInImage_fn (image, "_atexit", 4);
230*e4b17023SJohn Marino if (! symbol)
231*e4b17023SJohn Marino return NULL;
232*e4b17023SJohn Marino return NSAddressOfSymbol_fn (symbol);
233*e4b17023SJohn Marino }
234*e4b17023SJohn Marino return NULL;
235*e4b17023SJohn Marino }
236*e4b17023SJohn Marino #endif
237*e4b17023SJohn Marino
238*e4b17023SJohn Marino /* Create (if necessary), find, lock, fill in, and return our globals.
239*e4b17023SJohn Marino Return NULL on error, in which case the globals will not be locked.
240*e4b17023SJohn Marino The caller should call keymgr_set_and_unlock. */
241*e4b17023SJohn Marino static struct keymgr_atexit_list *
get_globals(void)242*e4b17023SJohn Marino get_globals (void)
243*e4b17023SJohn Marino {
244*e4b17023SJohn Marino struct keymgr_atexit_list * r;
245*e4b17023SJohn Marino
246*e4b17023SJohn Marino #ifdef __ppc__
247*e4b17023SJohn Marino /* 10.3.9 doesn't have _keymgr_get_and_lock_processwide_ptr_2 so the
248*e4b17023SJohn Marino PPC side can't use it. On 10.4 this just means the error gets
249*e4b17023SJohn Marino reported a little later when
250*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr finds that the key was
251*e4b17023SJohn Marino never locked. */
252*e4b17023SJohn Marino r = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
253*e4b17023SJohn Marino #else
254*e4b17023SJohn Marino void * rr;
255*e4b17023SJohn Marino if (_keymgr_get_and_lock_processwide_ptr_2 (KEYMGR_ATEXIT_LIST, &rr))
256*e4b17023SJohn Marino return NULL;
257*e4b17023SJohn Marino r = rr;
258*e4b17023SJohn Marino #endif
259*e4b17023SJohn Marino
260*e4b17023SJohn Marino if (r == NULL)
261*e4b17023SJohn Marino {
262*e4b17023SJohn Marino r = calloc (sizeof (struct keymgr_atexit_list), 1);
263*e4b17023SJohn Marino if (! r)
264*e4b17023SJohn Marino return NULL;
265*e4b17023SJohn Marino }
266*e4b17023SJohn Marino
267*e4b17023SJohn Marino if (r->atexit_status == atexit_status_unknown)
268*e4b17023SJohn Marino {
269*e4b17023SJohn Marino void *handle;
270*e4b17023SJohn Marino
271*e4b17023SJohn Marino handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD);
272*e4b17023SJohn Marino if (!handle)
273*e4b17023SJohn Marino {
274*e4b17023SJohn Marino #ifdef __ppc__
275*e4b17023SJohn Marino r->atexit_status = atexit_status_missing;
276*e4b17023SJohn Marino r->atexit_f = find_atexit_10_3 ();
277*e4b17023SJohn Marino if (! r->atexit_f)
278*e4b17023SJohn Marino goto error;
279*e4b17023SJohn Marino if (r->atexit_f (our_atexit))
280*e4b17023SJohn Marino goto error;
281*e4b17023SJohn Marino #else
282*e4b17023SJohn Marino goto error;
283*e4b17023SJohn Marino #endif
284*e4b17023SJohn Marino }
285*e4b17023SJohn Marino else
286*e4b17023SJohn Marino {
287*e4b17023SJohn Marino int chk_result;
288*e4b17023SJohn Marino
289*e4b17023SJohn Marino r->cxa_atexit_f = (cxa_atexit_p)dlsym (handle, "__cxa_atexit");
290*e4b17023SJohn Marino r->cxa_finalize_f = (cxa_finalize_p)dlsym (handle, "__cxa_finalize");
291*e4b17023SJohn Marino if (! r->cxa_atexit_f || ! r->cxa_finalize_f)
292*e4b17023SJohn Marino goto error;
293*e4b17023SJohn Marino
294*e4b17023SJohn Marino chk_result = check_cxa_atexit (r->cxa_atexit_f, r->cxa_finalize_f);
295*e4b17023SJohn Marino if (chk_result == -1)
296*e4b17023SJohn Marino goto error;
297*e4b17023SJohn Marino else if (chk_result == 0)
298*e4b17023SJohn Marino r->atexit_status = atexit_status_broken;
299*e4b17023SJohn Marino else
300*e4b17023SJohn Marino {
301*e4b17023SJohn Marino r->atexit_f = (atexit_p)dlsym (handle, "atexit");
302*e4b17023SJohn Marino if (! r->atexit_f)
303*e4b17023SJohn Marino goto error;
304*e4b17023SJohn Marino r->atexit_status = atexit_status_working;
305*e4b17023SJohn Marino }
306*e4b17023SJohn Marino }
307*e4b17023SJohn Marino }
308*e4b17023SJohn Marino
309*e4b17023SJohn Marino return r;
310*e4b17023SJohn Marino
311*e4b17023SJohn Marino error:
312*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, r);
313*e4b17023SJohn Marino return NULL;
314*e4b17023SJohn Marino }
315*e4b17023SJohn Marino
316*e4b17023SJohn Marino /* Add TO_ADD to ATEXIT_LIST. ATEXIT_LIST may be NULL but is
317*e4b17023SJohn Marino always the result of calling _keymgr_get_and_lock_processwide_ptr and
318*e4b17023SJohn Marino so KEYMGR_ATEXIT_LIST is known to be locked; this routine is responsible
319*e4b17023SJohn Marino for unlocking it. */
320*e4b17023SJohn Marino
321*e4b17023SJohn Marino static int
add_routine(struct keymgr_atexit_list * g,const struct one_atexit_routine * to_add)322*e4b17023SJohn Marino add_routine (struct keymgr_atexit_list * g,
323*e4b17023SJohn Marino const struct one_atexit_routine * to_add)
324*e4b17023SJohn Marino {
325*e4b17023SJohn Marino struct atexit_routine_list * s
326*e4b17023SJohn Marino = malloc (sizeof (struct atexit_routine_list));
327*e4b17023SJohn Marino int result;
328*e4b17023SJohn Marino
329*e4b17023SJohn Marino if (!s)
330*e4b17023SJohn Marino {
331*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
332*e4b17023SJohn Marino return -1;
333*e4b17023SJohn Marino }
334*e4b17023SJohn Marino s->r = *to_add;
335*e4b17023SJohn Marino s->next = g->l;
336*e4b17023SJohn Marino g->l = s;
337*e4b17023SJohn Marino result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
338*e4b17023SJohn Marino return CHECK_KEYMGR_ERROR (result) == 0 ? 0 : -1;
339*e4b17023SJohn Marino }
340*e4b17023SJohn Marino
341*e4b17023SJohn Marino /* This runs the routines in G->L up to STOP. */
342*e4b17023SJohn Marino static struct keymgr_atexit_list *
run_routines(struct keymgr_atexit_list * g,struct atexit_routine_list * stop)343*e4b17023SJohn Marino run_routines (struct keymgr_atexit_list *g,
344*e4b17023SJohn Marino struct atexit_routine_list *stop)
345*e4b17023SJohn Marino {
346*e4b17023SJohn Marino for (;;)
347*e4b17023SJohn Marino {
348*e4b17023SJohn Marino struct atexit_routine_list * cur = g->l;
349*e4b17023SJohn Marino if (! cur || cur == stop)
350*e4b17023SJohn Marino break;
351*e4b17023SJohn Marino g->l = cur->next;
352*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
353*e4b17023SJohn Marino
354*e4b17023SJohn Marino switch (cur->r.has_arg) {
355*e4b17023SJohn Marino case 0: case 2: case 4:
356*e4b17023SJohn Marino cur->r.callback.ac ();
357*e4b17023SJohn Marino break;
358*e4b17023SJohn Marino case 1: case 3: case 5:
359*e4b17023SJohn Marino cur->r.callback.cac (cur->r.arg);
360*e4b17023SJohn Marino break;
361*e4b17023SJohn Marino default:
362*e4b17023SJohn Marino /* Don't understand, so don't call it. */
363*e4b17023SJohn Marino break;
364*e4b17023SJohn Marino }
365*e4b17023SJohn Marino free (cur);
366*e4b17023SJohn Marino
367*e4b17023SJohn Marino g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
368*e4b17023SJohn Marino if (! g)
369*e4b17023SJohn Marino break;
370*e4b17023SJohn Marino }
371*e4b17023SJohn Marino return g;
372*e4b17023SJohn Marino }
373*e4b17023SJohn Marino
374*e4b17023SJohn Marino /* Call the routine described by ROUTINE_PARAM and then call any
375*e4b17023SJohn Marino routines added to KEYMGR_ATEXIT_LIST while that routine was
376*e4b17023SJohn Marino running, all with in_cxa_finalize set. */
377*e4b17023SJohn Marino
378*e4b17023SJohn Marino static void
cxa_atexit_wrapper(void * routine_param)379*e4b17023SJohn Marino cxa_atexit_wrapper (void* routine_param)
380*e4b17023SJohn Marino {
381*e4b17023SJohn Marino struct one_atexit_routine * routine = routine_param;
382*e4b17023SJohn Marino struct keymgr_atexit_list *g;
383*e4b17023SJohn Marino struct atexit_routine_list * base = NULL;
384*e4b17023SJohn Marino char prev_running = 0;
385*e4b17023SJohn Marino
386*e4b17023SJohn Marino g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
387*e4b17023SJohn Marino if (g)
388*e4b17023SJohn Marino {
389*e4b17023SJohn Marino prev_running = g->running_routines;
390*e4b17023SJohn Marino g->running_routines = 1;
391*e4b17023SJohn Marino base = g->l;
392*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
393*e4b17023SJohn Marino }
394*e4b17023SJohn Marino
395*e4b17023SJohn Marino if (routine->has_arg)
396*e4b17023SJohn Marino routine->callback.cac (routine->arg);
397*e4b17023SJohn Marino else
398*e4b17023SJohn Marino routine->callback.ac ();
399*e4b17023SJohn Marino
400*e4b17023SJohn Marino if (g)
401*e4b17023SJohn Marino g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
402*e4b17023SJohn Marino if (g)
403*e4b17023SJohn Marino g = run_routines (g, base);
404*e4b17023SJohn Marino if (g)
405*e4b17023SJohn Marino {
406*e4b17023SJohn Marino g->running_routines = prev_running;
407*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
408*e4b17023SJohn Marino }
409*e4b17023SJohn Marino }
410*e4b17023SJohn Marino
411*e4b17023SJohn Marino #ifdef __ppc__
412*e4b17023SJohn Marino /* This code is used while running on 10.3.9, when __cxa_atexit doesn't
413*e4b17023SJohn Marino exist in the system library. 10.3.9 only supported regular PowerPC,
414*e4b17023SJohn Marino so this code isn't necessary on x86 or ppc64. */
415*e4b17023SJohn Marino
416*e4b17023SJohn Marino /* This routine is called from the system atexit(); it runs everything
417*e4b17023SJohn Marino registered on the KEYMGR_ATEXIT_LIST. */
418*e4b17023SJohn Marino
419*e4b17023SJohn Marino static void
our_atexit(void)420*e4b17023SJohn Marino our_atexit (void)
421*e4b17023SJohn Marino {
422*e4b17023SJohn Marino struct keymgr_atexit_list *g;
423*e4b17023SJohn Marino char prev_running;
424*e4b17023SJohn Marino
425*e4b17023SJohn Marino g = _keymgr_get_and_lock_processwide_ptr (KEYMGR_ATEXIT_LIST);
426*e4b17023SJohn Marino if (! g || g->version != 0 || g->atexit_status != atexit_status_missing)
427*e4b17023SJohn Marino return;
428*e4b17023SJohn Marino
429*e4b17023SJohn Marino prev_running = g->running_routines;
430*e4b17023SJohn Marino g->running_routines = 1;
431*e4b17023SJohn Marino g = run_routines (g, NULL);
432*e4b17023SJohn Marino if (! g)
433*e4b17023SJohn Marino return;
434*e4b17023SJohn Marino g->running_routines = prev_running;
435*e4b17023SJohn Marino _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
436*e4b17023SJohn Marino }
437*e4b17023SJohn Marino #endif
438*e4b17023SJohn Marino
439*e4b17023SJohn Marino /* This is our wrapper around atexit and __cxa_atexit. It will return
440*e4b17023SJohn Marino nonzero if an error occurs, and otherwise:
441*e4b17023SJohn Marino - if in_cxa_finalize is set, or running on 10.3.9, add R to
442*e4b17023SJohn Marino KEYMGR_ATEXIT_LIST; or
443*e4b17023SJohn Marino - call the system __cxa_atexit to add cxa_atexit_wrapper with an argument
444*e4b17023SJohn Marino that indicates how cxa_atexit_wrapper should call R. */
445*e4b17023SJohn Marino
446*e4b17023SJohn Marino static int
atexit_common(const struct one_atexit_routine * r,const void * dso)447*e4b17023SJohn Marino atexit_common (const struct one_atexit_routine *r, const void *dso)
448*e4b17023SJohn Marino {
449*e4b17023SJohn Marino struct keymgr_atexit_list *g = get_globals ();
450*e4b17023SJohn Marino
451*e4b17023SJohn Marino if (! g)
452*e4b17023SJohn Marino return -1;
453*e4b17023SJohn Marino
454*e4b17023SJohn Marino if (g->running_routines || g->atexit_status == atexit_status_missing)
455*e4b17023SJohn Marino return add_routine (g, r);
456*e4b17023SJohn Marino
457*e4b17023SJohn Marino if (g->atexit_status >= atexit_status_working)
458*e4b17023SJohn Marino {
459*e4b17023SJohn Marino int result;
460*e4b17023SJohn Marino if (r->has_arg)
461*e4b17023SJohn Marino {
462*e4b17023SJohn Marino cxa_atexit_p cxa_atexit = g->cxa_atexit_f;
463*e4b17023SJohn Marino result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST,
464*e4b17023SJohn Marino g);
465*e4b17023SJohn Marino if (CHECK_KEYMGR_ERROR (result))
466*e4b17023SJohn Marino return -1;
467*e4b17023SJohn Marino return cxa_atexit (r->callback.cac, r->arg, dso);
468*e4b17023SJohn Marino }
469*e4b17023SJohn Marino else
470*e4b17023SJohn Marino {
471*e4b17023SJohn Marino atexit_p atexit_f = g->atexit_f;
472*e4b17023SJohn Marino result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST,
473*e4b17023SJohn Marino g);
474*e4b17023SJohn Marino if (CHECK_KEYMGR_ERROR (result))
475*e4b17023SJohn Marino return -1;
476*e4b17023SJohn Marino return atexit_f (r->callback.ac);
477*e4b17023SJohn Marino }
478*e4b17023SJohn Marino }
479*e4b17023SJohn Marino else
480*e4b17023SJohn Marino {
481*e4b17023SJohn Marino cxa_atexit_p cxa_atexit = g->cxa_atexit_f;
482*e4b17023SJohn Marino struct one_atexit_routine *alloced;
483*e4b17023SJohn Marino int result;
484*e4b17023SJohn Marino
485*e4b17023SJohn Marino result = _keymgr_set_and_unlock_processwide_ptr (KEYMGR_ATEXIT_LIST, g);
486*e4b17023SJohn Marino if (CHECK_KEYMGR_ERROR (result))
487*e4b17023SJohn Marino return -1;
488*e4b17023SJohn Marino
489*e4b17023SJohn Marino alloced = malloc (sizeof (struct one_atexit_routine));
490*e4b17023SJohn Marino if (! alloced)
491*e4b17023SJohn Marino return -1;
492*e4b17023SJohn Marino *alloced = *r;
493*e4b17023SJohn Marino return cxa_atexit (cxa_atexit_wrapper, alloced, dso);
494*e4b17023SJohn Marino }
495*e4b17023SJohn Marino }
496*e4b17023SJohn Marino
497*e4b17023SJohn Marino /* These are the actual replacement routines; they just funnel into
498*e4b17023SJohn Marino atexit_common. */
499*e4b17023SJohn Marino
500*e4b17023SJohn Marino int __cxa_atexit (cxa_atexit_callback func, void* arg,
501*e4b17023SJohn Marino const void* dso) __attribute__((visibility("hidden")));
502*e4b17023SJohn Marino
503*e4b17023SJohn Marino int
__cxa_atexit(cxa_atexit_callback func,void * arg,const void * dso)504*e4b17023SJohn Marino __cxa_atexit (cxa_atexit_callback func, void* arg, const void* dso)
505*e4b17023SJohn Marino {
506*e4b17023SJohn Marino struct one_atexit_routine r;
507*e4b17023SJohn Marino r.callback.cac = func;
508*e4b17023SJohn Marino r.has_arg = 1;
509*e4b17023SJohn Marino r.arg = arg;
510*e4b17023SJohn Marino return atexit_common (&r, dso);
511*e4b17023SJohn Marino }
512*e4b17023SJohn Marino
513*e4b17023SJohn Marino int atexit (atexit_callback func) __attribute__((visibility("hidden")));
514*e4b17023SJohn Marino
515*e4b17023SJohn Marino /* Use __dso_handle to allow even bundles that call atexit() to be unloaded
516*e4b17023SJohn Marino on 10.4. */
517*e4b17023SJohn Marino extern void __dso_handle;
518*e4b17023SJohn Marino
519*e4b17023SJohn Marino int
atexit(atexit_callback func)520*e4b17023SJohn Marino atexit (atexit_callback func)
521*e4b17023SJohn Marino {
522*e4b17023SJohn Marino struct one_atexit_routine r;
523*e4b17023SJohn Marino r.callback.ac = func;
524*e4b17023SJohn Marino r.has_arg = 0;
525*e4b17023SJohn Marino return atexit_common (&r, &__dso_handle);
526*e4b17023SJohn Marino }
527*e4b17023SJohn Marino
528*e4b17023SJohn Marino #endif /* __PIC__ */
529