xref: /illumos-gate/usr/src/head/stack_unwind.h (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Public interfaces for AMD64 Unwind routines
29  */
30 
31 #ifndef _STACK_UNWIND_H
32 #define	_STACK_UNWIND_H
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 #include <sys/types.h>
37 
38 #ifdef	__cplusplus
39 extern "C" {
40 #endif
41 
42 #if defined(__amd64)	/* none of this is valid except for AMD64 */
43 
44 typedef enum {
45 	_URC_NO_REASON = 0,
46 	_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
47 	_URC_FATAL_PHASE2_ERROR = 2,
48 	_URC_FATAL_PHASE1_ERROR = 3,
49 	_URC_NORMAL_STOP = 4,
50 	_URC_END_OF_STACK = 5,
51 	_URC_HANDLER_FOUND = 6,
52 	_URC_INSTALL_CONTEXT = 7,
53 	_URC_CONTINUE_UNWIND = 8
54 } _Unwind_Reason_Code;
55 
56 typedef int _Unwind_Action;
57 extern const _Unwind_Action _UA_SEARCH_PHASE;
58 extern const _Unwind_Action _UA_CLEANUP_PHASE;
59 extern const _Unwind_Action _UA_HANDLER_FRAME;
60 extern const _Unwind_Action _UA_FORCE_UNWIND;
61 
62 struct _Unwind_Exception;
63 struct _Unwind_Context;
64 
65 
66 /*
67  * Signature of language specific call back for deleting exception object
68  */
69 typedef void (*_Unwind_Exception_Cleanup_Fn)(
70 	_Unwind_Reason_Code reason,
71 	struct _Unwind_Exception *exc);
72 
73 /*
74  * Header preceding language specific exception object
75  * For Sun C++ these fields are the beginning of the
76  * language specific structure.
77  */
78 struct _Unwind_Exception {
79 	uint64_t exception_class;
80 	_Unwind_Exception_Cleanup_Fn exception_cleanup;
81 	uint64_t private_1;
82 	uint64_t private_2;
83 };
84 
85 /*
86  * Signature for language specific routine - address is in eh_frame CIE.
87  * During phase one it predicts whether exception would be caught at this
88  * frame and during phase two selects a handler as predicted.  An action
89  * of _UA_FORCE_UNWIND will prevent any catch block from being selected.
90  *
91  * The personality function is the only call back used when
92  * _Unwind_RaiseException() is called.
93  */
94 typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)(
95 	int version,
96 	_Unwind_Action actions,
97 	uint64_t exceptionClass,
98 	struct _Unwind_Exception *exceptionObject,
99 	struct _Unwind_Context *context);
100 
101 /*
102  * Signature of callback function that is used when _Unwind_ForcedUnwind()
103  * is called.  It is called at every step of walkback and that can control
104  * the execution of the personality routine at each frame.
105  */
106 typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)(
107 	int version,
108 	_Unwind_Action actions,
109 	uint64_t exceptionClass,
110 	struct _Unwind_Exception *exceptionObject,
111 	struct _Unwind_Context *context,
112 	void *stop_parameter);
113 
114 /*
115  * Here begins the external functional interface
116  */
117 
118 /*
119  * Used to implement C++ throw - starts walkback with caller's caller.
120  * The routine in the middle must use %rbp as a frame pointer
121  */
122 _Unwind_Reason_Code _Unwind_RaiseException(
123 	struct _Unwind_Exception *exception_object);
124 
125 /*
126  * Used (with different stop functions) for POSIX thread cancellation
127  * and stack walking - starts walkback with caller's caller.
128  *
129  * Note: must be called by a routine which has a real FP and doesn't use
130  * callee saves registers.
131  */
132 _Unwind_Reason_Code _Unwind_ForcedUnwind(
133 	struct _Unwind_Exception *exception_object,
134 	_Unwind_Stop_Fn stop,
135 	void *stop_parameter);
136 
137 /*
138  * Used to resume unwinding at end of cleanup (not catch) code
139  * Assumes that caller is language specific cleanup code and
140  * pops the stack one level before resuming walk.
141  */
142 void _Unwind_Resume(struct _Unwind_Exception *exception_object);
143 
144 /*
145  * Calls destructor function for exception object
146  */
147 void _Unwind_DeleteException(struct _Unwind_Exception *exception_object);
148 /*
149  * {
150  * 	(*(exception_object->exception_cleanup))(_URC_NO_REASON,
151  * 		exception_object);
152  * }
153  */
154 
155 
156 #if 0
157 
158 extern "C" _Unwind_Reason_Code
159 __example_stop_fn(int version, int actions, uint64_t exclass,
160 	struct _Unwind_Exception *exception_object,
161 	struct _Unwind_Context *ctx, void *_Sa)
162 {
163 	_Unwind_Reason_Code res;
164 
165 	uint64_t fp = _Unwind_GetCFA(ctx);
166 
167 	if (fp == 0 || _Unwind_GetGR(ctx, RET_ADD) == 0) {
168 		if (no_return)
169 			die;
170 		res = _URC_END_OF_STACK;
171 	} else {
172 		/*
173 		 * Your logic here:
174 		 * res = ........
175 		 */
176 	}
177 	switch (res) {
178 	case _URC_NO_REASON:
179 		/*
180 		 * framework will call personality routine for current context
181 		 * then then move one frame back the stack and call here with
182 		 * updated context. POSIX thread cancellation uses this pattern.
183 		 *
184 		 * If this path is taken the exception object passed must have
185 		 * been constructed by the same language system supplying the
186 		 * personality routines. i.e. foreign exceptions are not
187 		 * implemented.
188 		 *
189 		 * The Sun Microsystems C++ runtime contains the routine
190 		 *
191 		 *	_ex_unwind(_Unwind_Stop_fn sfunc, void *sfunc_arg)
192 		 *
193 		 * which is a wrapper around _Unwind_ForcedUnwind that
194 		 * sets up a C++ exception object.
195 		 *
196 		 * Once this path is taken, the stack frame from which
197 		 * _Unwind_ForcedUnwind was called is not guaranteed to
198 		 * still exist. Thus the return codes listed below which
199 		 * result in that call returning are rendered bogus.
200 		 *
201 		 * A thread reaching the end of the stack during cancellation
202 		 * must die instead of returning _URC_END_OF_STACK.
203 		 */
204 		break;
205 	case _URC_CONTINUE_UNWIND:
206 		/*
207 		 * framework will move one frame back the stack and
208 		 * call here with updated context
209 		 *
210 		 * The exception record supplied to _Unwind_ForcedUnwind
211 		 * need only contain the header and may be stack allocated
212 		 * if this function will never allow the personality
213 		 * function to run (as in a trace generator).
214 		 */
215 		break;
216 	case _URC_INSTALL_CONTEXT:
217 		/*
218 		 * framework will resume execution of user code at location
219 		 * specified by (altered) context
220 		 */
221 		_Unwind_Delete_Exception(res, exception_object);
222 		break;
223 	case _URC_NORMAL_STOP:
224 		/*
225 		 * call to _Unwind_ForcedUnwind will return _URC_NORMAL_STOP
226 		 */
227 		_Unwind_Delete_Exception(res, exception_object);
228 		break;
229 	case _URC_END_OF_STACK:
230 		/*
231 		 * call to _Unwind_ForcedUnwind will return _URC_END_OF_STACK
232 		 */
233 		_Unwind_Delete_Exception(res, exception_object);
234 		break;
235 	case _URC_FOREIGN_EXCEPTION_CAUGHT:
236 	case _URC_FATAL_PHASE2_ERROR:
237 	case _URC_FATAL_PHASE1_ERROR:
238 	case _URC_HANDLER_FOUND:
239 		/*
240 		 * call to _Unwind_ForcedUnwind will return
241 		 * _URC_FATAL_PHASE2_ERROR
242 		 */
243 		_Unwind_Delete_Exception(res, exception_object);
244 		break;
245 	}
246 	return (res);
247 }
248 
249 #endif
250 
251 /*
252  * Stack frame context accessors defined in ABI
253  * (despite all the dire text in the ABI these are reliable Get/Set routines)
254  * Note: RA is handled as a GR value
255  */
256 
257 /*
258  * Valid Index values for _Unwind_GetGR
259  */
260 #define	GPR_RBX	3	/* callee saves */
261 #define	FP_RBP	6	/* callee saves (optional frame pointer) */
262 #define	SP_RSP	7	/* callee saves */
263 #define	EIR_R12	12	/* callee saves */
264 #define	EIR_R13	13	/* callee saves */
265 #define	EIR_R14	14	/* callee saves */
266 #define	EIR_R15	15	/* callee saves */
267 #define	RET_ADD	16	/* virtual register - really caller's PC */
268 
269 /*
270  * Valid Index values for _Unwind_SetGR
271  */
272 #define	GPR_RDX	1	/* landing pad parameter */
273 #define	GPR_RCX	2	/* landing pad parameter */
274 #define	GPR_RSI	4	/* landing pad parameter */
275 #define	GPR_RDI	5	/* landing pad parameter */
276 
277 uint64_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
278 
279 void _Unwind_SetGR(struct _Unwind_Context *context, int index,
280 	uint64_t new_value);
281 
282 uint64_t _Unwind_GetCFA(struct _Unwind_Context *context);
283 
284 uint64_t _Unwind_GetIP(struct _Unwind_Context *context);
285 
286 void _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value);
287 
288 void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context);
289 
290 uint64_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
291 
292 #endif	/* __amd64 */
293 
294 #ifdef	__cplusplus
295 }
296 #endif
297 
298 #endif	/* _STACK_UNWIND_H */
299