1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "lint.h"
28 #include "thr_uberdata.h"
29 #include "stack_unwind.h"
30 #include "reg_num.h"
31 #include <dlfcn.h>
32
33 /*
34 * Due to the subtle mysteries of the amd64 unwind interfaces, the
35 * "Canonical Frame Address" is 16 bytes higher in memory than the
36 * value of the frame pointer (%fp).
37 */
38 #define CFA_ADJUST 16
39
40 static _Unwind_Reason_Code
posix_stop_func(int version __unused,_Unwind_Action _Unwind_actions __unused,uint64_t exceptionClass __unused,struct _Unwind_Exception * exceptionObject,struct _Unwind_Context * context,void * func_arg)41 posix_stop_func(int version __unused,
42 _Unwind_Action _Unwind_actions __unused,
43 uint64_t exceptionClass __unused,
44 struct _Unwind_Exception *exceptionObject,
45 struct _Unwind_Context *context,
46 void *func_arg)
47 {
48 __cleanup_t **headp = (__cleanup_t **)func_arg;
49 __cleanup_t *head;
50 uint64_t cfa;
51
52 /*
53 * If we have reached the origin of the stack, exit now.
54 */
55 cfa = _Unwind_GetCFA(context);
56 if (cfa == 0 || _Unwind_GetGR(context, RET_ADD) == 0) {
57 _Unwind_DeleteException(exceptionObject);
58 _thrp_exit();
59 thr_panic("posix_stop_func(): _thrp_exit() returned");
60 }
61
62 /*
63 * Call all Posix cleanup handlers for this frame.
64 */
65 while ((head = *headp) != NULL &&
66 (caddr_t)cfa == head->fp + CFA_ADJUST) {
67 *headp = head->next;
68 (*head->func)(head->arg);
69 }
70
71 return (_URC_NO_REASON);
72 }
73
74 /*
75 * _ex_unwind() is provided by libCrun to perform stack unwinding
76 * and calling C++ destructors as needed, interleaved with calling
77 * Posix cleanup handlers along the way. If libCrun is not present
78 * we just need to call the Posix cleanup handlers.
79 */
80
81 void
_thrp_unwind(void * dummy __unused)82 _thrp_unwind(void *dummy __unused)
83 {
84 ulwp_t *self = curthread;
85 __cleanup_t **headp = &self->ul_clnup_hdr;
86 __cleanup_t *head;
87 void (*fptr)(_Unwind_Stop_Fn, void *);
88
89 /* Do this once per thread exit, not once per unwind frame */
90 if (self->ul_ex_unwind == NULL &&
91 (self->ul_ex_unwind = dlsym(RTLD_PROBE, "_ex_unwind")) == NULL)
92 self->ul_ex_unwind = (void *)-1;
93
94 if (self->ul_ex_unwind == (void *)-1)
95 fptr = NULL;
96 else
97 fptr = (void (*)())self->ul_ex_unwind;
98
99 /*
100 * Call _ex_unwind() if it is present (C++ loaded),
101 * else just call the Posix cleanup handlers.
102 */
103 if (fptr != NULL)
104 (*fptr)(posix_stop_func, headp);
105
106 /*
107 * Call all remaining Posix cleanup handlers.
108 */
109 while ((head = *headp) != NULL) {
110 *headp = head->next;
111 (*head->func)(head->arg);
112 }
113
114 _thrp_exit();
115 thr_panic("_thrp_unwind(): _thrp_exit() returned");
116 }
117