1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * UNWIND - Unwind library
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  * ===================== stack walk ====================
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * Stack walk-back starts with the user code at the top of the stack
37*0Sstevel@tonic-gate  * calling a language specific support routine which calls the generic
38*0Sstevel@tonic-gate  * unwind code. The unwind code captures
39*0Sstevel@tonic-gate  * information which can be used to partially build an _Unwind_Context
40*0Sstevel@tonic-gate  * for the user code containing:
41*0Sstevel@tonic-gate  *
42*0Sstevel@tonic-gate  *    callee saves registers <current values>
43*0Sstevel@tonic-gate  *    PC
44*0Sstevel@tonic-gate  *    %rbp
45*0Sstevel@tonic-gate  *    %rsp
46*0Sstevel@tonic-gate  *
47*0Sstevel@tonic-gate  * Using that pc location the unwind info for the function is found.
48*0Sstevel@tonic-gate  * Then the CFA operations encoded in the unwind info are interepreted to get
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  *    callee saves registers <values on entry>
51*0Sstevel@tonic-gate  *    the return address
52*0Sstevel@tonic-gate  *    cannonical frame address
53*0Sstevel@tonic-gate  *
54*0Sstevel@tonic-gate  * completing the context for the user function (See
55*0Sstevel@tonic-gate  * _Unw_Rollback_Registers()) .
56*0Sstevel@tonic-gate  *
57*0Sstevel@tonic-gate  * The values computed above are equivalent to the info which would have been
58*0Sstevel@tonic-gate  * captured from the caller and are used to initialize the callers context
59*0Sstevel@tonic-gate  * (see _Unw_Propagate_Registers()) which can be completed.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * Using the same two-step procedure
62*0Sstevel@tonic-gate  * context records for each frame down the stack may be constructed
63*0Sstevel@tonic-gate  * in turn.  The ABI defined interface to _Unwind_Context provides
64*0Sstevel@tonic-gate  * access to
65*0Sstevel@tonic-gate  *
66*0Sstevel@tonic-gate  *    callee saves registers <current values>
67*0Sstevel@tonic-gate  *    current PC
68*0Sstevel@tonic-gate  *    frame pointer
69*0Sstevel@tonic-gate  *
70*0Sstevel@tonic-gate  * and allows changing
71*0Sstevel@tonic-gate  *
72*0Sstevel@tonic-gate  *    PC
73*0Sstevel@tonic-gate  *    values of integer argument registers
74*0Sstevel@tonic-gate  *
75*0Sstevel@tonic-gate  * (changed values take effect if context is "installed" - think
76*0Sstevel@tonic-gate  * setcontext(2))
77*0Sstevel@tonic-gate  *
78*0Sstevel@tonic-gate  */
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate /*
81*0Sstevel@tonic-gate  *
82*0Sstevel@tonic-gate  * |                              |
83*0Sstevel@tonic-gate  * | local storage for start()    | <FP == 0>
84*0Sstevel@tonic-gate  * |                              |
85*0Sstevel@tonic-gate  * --------------------------------.
86*0Sstevel@tonic-gate  * |                              |
87*0Sstevel@tonic-gate  * |     ..........               |
88*0Sstevel@tonic-gate  * |                              | <-  CFA for bar()
89*0Sstevel@tonic-gate  * --------------------------------.
90*0Sstevel@tonic-gate  * |                              |
91*0Sstevel@tonic-gate  * | local storage for bar()      |
92*0Sstevel@tonic-gate  * |                              | <-  SP for bar(), CFA for foo()
93*0Sstevel@tonic-gate  * ................................
94*0Sstevel@tonic-gate  * |  pc for bar()                |
95*0Sstevel@tonic-gate  * --------------------------------
96*0Sstevel@tonic-gate  * |                              |
97*0Sstevel@tonic-gate  * | local storage for foo()      |
98*0Sstevel@tonic-gate  * |                              | <-  SP for foo(), CFA for ex_throw()
99*0Sstevel@tonic-gate  * ................................
100*0Sstevel@tonic-gate  * | pc for foo() - PC3           |
101*0Sstevel@tonic-gate  * ................................
102*0Sstevel@tonic-gate  * | saved RBP from foo() - BP3   | <-  FP for ex_throw() == FP2
103*0Sstevel@tonic-gate  * --------------------------------
104*0Sstevel@tonic-gate  * |                              |
105*0Sstevel@tonic-gate  * | local storage for ex_throw() |
106*0Sstevel@tonic-gate  * |                              | <- SP for ex_throw(), CFA for Unw()
107*0Sstevel@tonic-gate  * ................................
108*0Sstevel@tonic-gate  * | pc for ex_throw() - PC2      |
109*0Sstevel@tonic-gate  * ................................
110*0Sstevel@tonic-gate  * | saved RBP from ex_throw()    | <- FP for Unw() == FP1
111*0Sstevel@tonic-gate  * --------------------------------
112*0Sstevel@tonic-gate  * |                              |
113*0Sstevel@tonic-gate  * | local storage for Unw()      |
114*0Sstevel@tonic-gate  * |                              | <- SP for Unw() == SP1
115*0Sstevel@tonic-gate  *
116*0Sstevel@tonic-gate  * We know that Unw() and ex_throw save and have an FP
117*0Sstevel@tonic-gate  *
118*0Sstevel@tonic-gate  */
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate #ifdef _LIBCRUN_
121*0Sstevel@tonic-gate #define	_Unwind_DeleteException  _SUNW_Unwind_DeleteException
122*0Sstevel@tonic-gate #define	_Unwind_ForcedUnwind  _SUNW_Unwind_ForcedUnwind
123*0Sstevel@tonic-gate #define	_Unwind_GetCFA  _SUNW_Unwind_GetCFA
124*0Sstevel@tonic-gate #define	_Unwind_GetGR  _SUNW_Unwind_GetGR
125*0Sstevel@tonic-gate #define	_Unwind_GetIP  _SUNW_Unwind_GetIP
126*0Sstevel@tonic-gate #define	_Unwind_GetLanguageSpecificData _SUNW_Unwind_GetLanguageSpecificData
127*0Sstevel@tonic-gate #define	_Unwind_GetRegionStart  _SUNW_Unwind_GetRegionStart
128*0Sstevel@tonic-gate #define	_Unwind_RaiseException  _SUNW_Unwind_RaiseException
129*0Sstevel@tonic-gate #define	_Unwind_Resume  _SUNW_Unwind_Resume
130*0Sstevel@tonic-gate #define	_Unwind_SetGR  _SUNW_Unwind_SetGR
131*0Sstevel@tonic-gate #define	_Unwind_SetIP  _SUNW_Unwind_SetIP
132*0Sstevel@tonic-gate #else
133*0Sstevel@tonic-gate #pragma weak _Unwind_DeleteException = _SUNW_Unwind_DeleteException
134*0Sstevel@tonic-gate #pragma weak _Unwind_ForcedUnwind = _SUNW_Unwind_ForcedUnwind
135*0Sstevel@tonic-gate #pragma weak _Unwind_GetCFA = _SUNW_Unwind_GetCFA
136*0Sstevel@tonic-gate #pragma weak _Unwind_GetGR = _SUNW_Unwind_GetGR
137*0Sstevel@tonic-gate #pragma weak _Unwind_GetIP = _SUNW_Unwind_GetIP
138*0Sstevel@tonic-gate #pragma weak _Unwind_GetLanguageSpecificData = \
139*0Sstevel@tonic-gate 			_SUNW_Unwind_GetLanguageSpecificData
140*0Sstevel@tonic-gate #pragma weak _Unwind_GetRegionStart = _SUNW_Unwind_GetRegionStart
141*0Sstevel@tonic-gate #pragma weak _Unwind_RaiseException = _SUNW_Unwind_RaiseException
142*0Sstevel@tonic-gate #pragma weak _Unwind_Resume = _SUNW_Unwind_Resume
143*0Sstevel@tonic-gate #pragma weak _Unwind_SetGR = _SUNW_Unwind_SetGR
144*0Sstevel@tonic-gate #pragma weak _Unwind_SetIP = _SUNW_Unwind_SetIP
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate #include "synonyms.h"
147*0Sstevel@tonic-gate #endif
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate #include "stack_unwind.h"
150*0Sstevel@tonic-gate #include "reg_num.h"
151*0Sstevel@tonic-gate #include "unwind_context.h"
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate const _Unwind_Action _UA_SEARCH_PHASE = 1;
154*0Sstevel@tonic-gate const _Unwind_Action _UA_CLEANUP_PHASE = 2;
155*0Sstevel@tonic-gate const _Unwind_Action _UA_HANDLER_FRAME = 4;
156*0Sstevel@tonic-gate const _Unwind_Action _UA_FORCE_UNWIND = 8;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate void _Unw_capture_regs(uint64_t *regs);
159*0Sstevel@tonic-gate void _Unw_jmp(uint64_t pc, uint64_t *regs);
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate static void
162*0Sstevel@tonic-gate copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2)
163*0Sstevel@tonic-gate {
164*0Sstevel@tonic-gate 	if (ctx1 != ctx2) {
165*0Sstevel@tonic-gate 		*ctx2 = *ctx1;
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate static _Unwind_Personality_Fn
170*0Sstevel@tonic-gate ctx_who(struct _Unwind_Context *ctx)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	return (ctx->pfn);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate /* ARGSUSED */
176*0Sstevel@tonic-gate _Unwind_Reason_Code
177*0Sstevel@tonic-gate _Unw_very_boring_personality(int version, int actions, uint64_t exclass,
178*0Sstevel@tonic-gate 	struct _Unwind_Exception *exception_object,
179*0Sstevel@tonic-gate 	struct _Unwind_Context *ctx)
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	_Unwind_Reason_Code res = _URC_CONTINUE_UNWIND;
182*0Sstevel@tonic-gate 	uint64_t fp;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	fp =  _Unwind_GetCFA(ctx);
185*0Sstevel@tonic-gate 	if (fp == 0 || _Unwind_GetIP(ctx) == 0) {
186*0Sstevel@tonic-gate 		return (_URC_END_OF_STACK);
187*0Sstevel@tonic-gate 	}
188*0Sstevel@tonic-gate 	return (res);
189*0Sstevel@tonic-gate }
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate /*
192*0Sstevel@tonic-gate  * The only static variables in this code - changed by debugging hook below
193*0Sstevel@tonic-gate  */
194*0Sstevel@tonic-gate static int using_ehf = 1;
195*0Sstevel@tonic-gate static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate void
198*0Sstevel@tonic-gate _SUNW_Unw_set_defaults(int use, uintptr_t def_per)
199*0Sstevel@tonic-gate {
200*0Sstevel@tonic-gate 	using_ehf = use;
201*0Sstevel@tonic-gate 	def_per_fcn = def_per;
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate static void
205*0Sstevel@tonic-gate complete_context(struct _Unwind_Context *ctx)
206*0Sstevel@tonic-gate {
207*0Sstevel@tonic-gate 	struct eh_frame_fields sf;
208*0Sstevel@tonic-gate 	struct eh_frame_fields *sfp = 0;
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn;
211*0Sstevel@tonic-gate 	ctx->lsda = 0;
212*0Sstevel@tonic-gate 	ctx->func = 0;
213*0Sstevel@tonic-gate 	ctx->range = 0;
214*0Sstevel@tonic-gate 	ctx->fde = 0;
215*0Sstevel@tonic-gate 	if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) {
216*0Sstevel@tonic-gate 		sfp = _Unw_Decode_FDE(&sf, ctx);
217*0Sstevel@tonic-gate 	}
218*0Sstevel@tonic-gate 	(void) _Unw_Rollback_Registers(sfp, ctx);
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate /*
222*0Sstevel@tonic-gate  * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad))
223*0Sstevel@tonic-gate  *
224*0Sstevel@tonic-gate  * FP2 = FP1[0];
225*0Sstevel@tonic-gate  * BP3 = FP2[0];
226*0Sstevel@tonic-gate  * PC3 = FP2[1];
227*0Sstevel@tonic-gate  * SP3 = FP2 + 16;
228*0Sstevel@tonic-gate  *
229*0Sstevel@tonic-gate  * output: PC3, SP3, and BP3
230*0Sstevel@tonic-gate  *
231*0Sstevel@tonic-gate  * remaining callee saves registers are also captured in context
232*0Sstevel@tonic-gate  */
233*0Sstevel@tonic-gate static void
234*0Sstevel@tonic-gate finish_capture(struct _Unwind_Context *ctx, int from_landing_pad)
235*0Sstevel@tonic-gate {
236*0Sstevel@tonic-gate 	uint64_t fp1 = ctx->current_regs[FP_RBP];
237*0Sstevel@tonic-gate 	uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0];
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	ctx->pc = ((uint64_t *)fp2)[1];
240*0Sstevel@tonic-gate 	ctx->current_regs[SP_RSP] = fp2 + 16;
241*0Sstevel@tonic-gate 	ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0];
242*0Sstevel@tonic-gate 	complete_context(ctx);
243*0Sstevel@tonic-gate }
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate static int
246*0Sstevel@tonic-gate down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx)
247*0Sstevel@tonic-gate {
248*0Sstevel@tonic-gate 	uint64_t old_cfa = old_ctx->cfa;
249*0Sstevel@tonic-gate 	uint64_t old_pc = old_ctx->pc;
250*0Sstevel@tonic-gate 	uint64_t new_cfa;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	if (old_cfa == 0 || old_pc == 0) {
253*0Sstevel@tonic-gate 		new_ctx->pc = 0;
254*0Sstevel@tonic-gate 		new_ctx->cfa = 0;
255*0Sstevel@tonic-gate 		new_ctx->ra = 0;
256*0Sstevel@tonic-gate 		return (1);
257*0Sstevel@tonic-gate 	}
258*0Sstevel@tonic-gate 	if (old_ctx->ra == 0) {
259*0Sstevel@tonic-gate 		new_ctx->pc = 0;
260*0Sstevel@tonic-gate 		new_ctx->cfa = 0;
261*0Sstevel@tonic-gate 		new_ctx->ra = 0;
262*0Sstevel@tonic-gate 		return (0);
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 	/* now shift ----------------------------- */
265*0Sstevel@tonic-gate 	_Unw_Propagate_Registers(old_ctx, new_ctx);
266*0Sstevel@tonic-gate 	complete_context(new_ctx);
267*0Sstevel@tonic-gate 	new_cfa = new_ctx->cfa;
268*0Sstevel@tonic-gate 	if ((new_cfa < old_cfa) || (new_cfa & 7)) {
269*0Sstevel@tonic-gate 		new_ctx->pc = 0;
270*0Sstevel@tonic-gate 		new_ctx->cfa = 0;
271*0Sstevel@tonic-gate 		new_ctx->ra = 0;
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 	return (0);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate static void
277*0Sstevel@tonic-gate jmp_ctx(struct _Unwind_Context *ctx)
278*0Sstevel@tonic-gate {
279*0Sstevel@tonic-gate 	_Unw_jmp(ctx->pc, ctx->current_regs);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate /*
283*0Sstevel@tonic-gate  * Here starts the real work - the entry points from either a language
284*0Sstevel@tonic-gate  * runtime or directly from user code.
285*0Sstevel@tonic-gate  *
286*0Sstevel@tonic-gate  * The two ..._Body functions are intended as private interfaces for
287*0Sstevel@tonic-gate  * Sun code as well so should remain accessible.
288*0Sstevel@tonic-gate  */
289*0Sstevel@tonic-gate _Unwind_Reason_Code
290*0Sstevel@tonic-gate _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object,
291*0Sstevel@tonic-gate 	struct _Unwind_Context *entry_ctx, int phase)
292*0Sstevel@tonic-gate {
293*0Sstevel@tonic-gate 	struct _Unwind_Context context;
294*0Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
295*0Sstevel@tonic-gate 	_Unwind_Reason_Code res;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	if (phase & _UA_SEARCH_PHASE) {
298*0Sstevel@tonic-gate 		finish_capture(entry_ctx, 0);
299*0Sstevel@tonic-gate 		copy_ctx(entry_ctx, ctx);
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 		for (;;) {
302*0Sstevel@tonic-gate 			res = (*ctx_who(ctx))(1, phase,
303*0Sstevel@tonic-gate 			    exception_object->exception_class,
304*0Sstevel@tonic-gate 			    exception_object, ctx);
305*0Sstevel@tonic-gate 			if (res != _URC_CONTINUE_UNWIND)
306*0Sstevel@tonic-gate 				break;
307*0Sstevel@tonic-gate 			if (down_one(ctx, ctx))
308*0Sstevel@tonic-gate 				return (_URC_FATAL_PHASE1_ERROR);
309*0Sstevel@tonic-gate 		}
310*0Sstevel@tonic-gate 		switch (res) {
311*0Sstevel@tonic-gate 		case _URC_HANDLER_FOUND:
312*0Sstevel@tonic-gate 			exception_object->private_2 = _Unwind_GetCFA(ctx);
313*0Sstevel@tonic-gate 			break;
314*0Sstevel@tonic-gate 		default:
315*0Sstevel@tonic-gate 			return (res);
316*0Sstevel@tonic-gate 			break;
317*0Sstevel@tonic-gate 		}
318*0Sstevel@tonic-gate 	} else {
319*0Sstevel@tonic-gate 		finish_capture(entry_ctx, 1);
320*0Sstevel@tonic-gate 		if (down_one(entry_ctx, entry_ctx))
321*0Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
322*0Sstevel@tonic-gate 	}
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	phase = _UA_CLEANUP_PHASE;
325*0Sstevel@tonic-gate 	copy_ctx(entry_ctx, ctx);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	for (;;) {
328*0Sstevel@tonic-gate 		if (exception_object->private_2 == _Unwind_GetCFA(ctx)) {
329*0Sstevel@tonic-gate 			phase |= _UA_HANDLER_FRAME;
330*0Sstevel@tonic-gate 		}
331*0Sstevel@tonic-gate 		res = (*ctx_who(ctx))(1, phase,
332*0Sstevel@tonic-gate 		    exception_object->exception_class,
333*0Sstevel@tonic-gate 		    exception_object, ctx);
334*0Sstevel@tonic-gate 		if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT)
335*0Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
336*0Sstevel@tonic-gate 		if (res != _URC_CONTINUE_UNWIND)
337*0Sstevel@tonic-gate 			break;
338*0Sstevel@tonic-gate 		if (down_one(ctx, ctx))
339*0Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
340*0Sstevel@tonic-gate 	}
341*0Sstevel@tonic-gate 	switch (res) {
342*0Sstevel@tonic-gate 	case _URC_INSTALL_CONTEXT:
343*0Sstevel@tonic-gate 		exception_object->private_1 = 0;
344*0Sstevel@tonic-gate 		jmp_ctx(ctx); /* does not return */
345*0Sstevel@tonic-gate 		break;
346*0Sstevel@tonic-gate 	default:
347*0Sstevel@tonic-gate 		break;
348*0Sstevel@tonic-gate 	}
349*0Sstevel@tonic-gate 	return (res);
350*0Sstevel@tonic-gate }
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate _Unwind_Reason_Code
353*0Sstevel@tonic-gate _Unwind_RaiseException(struct _Unwind_Exception *exception_object)
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 	struct _Unwind_Context entry_context;
356*0Sstevel@tonic-gate 	struct _Unwind_Context *entry_ctx = &entry_context;
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	_Unw_capture_regs(entry_ctx->current_regs);
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	return (_Unwind_RaiseException_Body(exception_object, entry_ctx,
361*0Sstevel@tonic-gate 	    _UA_SEARCH_PHASE));
362*0Sstevel@tonic-gate }
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate _Unwind_Reason_Code
365*0Sstevel@tonic-gate _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object,
366*0Sstevel@tonic-gate 	_Unwind_Stop_Fn stop, void *stop_parameter,
367*0Sstevel@tonic-gate 	struct _Unwind_Context *ctx, int resume)
368*0Sstevel@tonic-gate {
369*0Sstevel@tonic-gate 	_Unwind_Reason_Code res;
370*0Sstevel@tonic-gate 	int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND;
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	int again;
373*0Sstevel@tonic-gate 	int doper;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	finish_capture(ctx, resume);
376*0Sstevel@tonic-gate 	if (resume && down_one(ctx, ctx))
377*0Sstevel@tonic-gate 	    return (_URC_FATAL_PHASE2_ERROR);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	do {
380*0Sstevel@tonic-gate 		again = 0;
381*0Sstevel@tonic-gate 		doper = 0;
382*0Sstevel@tonic-gate 		res = (*stop)(1, phase,
383*0Sstevel@tonic-gate 		    exception_object->exception_class,
384*0Sstevel@tonic-gate 		    exception_object, ctx, stop_parameter);
385*0Sstevel@tonic-gate 		switch (res) {
386*0Sstevel@tonic-gate 		case _URC_CONTINUE_UNWIND:
387*0Sstevel@tonic-gate 			/* keep going - don't call personality */
388*0Sstevel@tonic-gate 			again = 1;
389*0Sstevel@tonic-gate 			break;
390*0Sstevel@tonic-gate 		case _URC_NO_REASON:
391*0Sstevel@tonic-gate 			/* keep going - do call personality */
392*0Sstevel@tonic-gate 			again = 1;
393*0Sstevel@tonic-gate 			doper = 1;
394*0Sstevel@tonic-gate 			break;
395*0Sstevel@tonic-gate 		case _URC_NORMAL_STOP:  /* done */
396*0Sstevel@tonic-gate 			break;
397*0Sstevel@tonic-gate 		case _URC_INSTALL_CONTEXT:  /* resume execution */
398*0Sstevel@tonic-gate 			break;
399*0Sstevel@tonic-gate 		default:		/* failure */
400*0Sstevel@tonic-gate 			break;
401*0Sstevel@tonic-gate 		}
402*0Sstevel@tonic-gate 		if (doper) {
403*0Sstevel@tonic-gate 			res = (*ctx_who(ctx))(1, phase,
404*0Sstevel@tonic-gate 			    exception_object->exception_class,
405*0Sstevel@tonic-gate 			    exception_object, ctx);
406*0Sstevel@tonic-gate 		}
407*0Sstevel@tonic-gate 		switch (res) {
408*0Sstevel@tonic-gate 		case _URC_INSTALL_CONTEXT:
409*0Sstevel@tonic-gate 			exception_object->private_1 = (uint64_t)stop;
410*0Sstevel@tonic-gate 			exception_object->private_2 = (uint64_t)stop_parameter;
411*0Sstevel@tonic-gate 			jmp_ctx(ctx); /* does not return */
412*0Sstevel@tonic-gate 			break;
413*0Sstevel@tonic-gate 		case _URC_CONTINUE_UNWIND:
414*0Sstevel@tonic-gate 		case _URC_NO_REASON:
415*0Sstevel@tonic-gate 			break;
416*0Sstevel@tonic-gate 		case _URC_END_OF_STACK:
417*0Sstevel@tonic-gate 			ctx->cfa = ctx->ra = ctx->pc = 0;
418*0Sstevel@tonic-gate 			res = (*stop)(1, phase,
419*0Sstevel@tonic-gate 					exception_object->exception_class,
420*0Sstevel@tonic-gate 					exception_object, ctx, stop_parameter);
421*0Sstevel@tonic-gate 			return (_URC_END_OF_STACK);
422*0Sstevel@tonic-gate 			break;
423*0Sstevel@tonic-gate 		default:
424*0Sstevel@tonic-gate 			again = 0;
425*0Sstevel@tonic-gate 			break;
426*0Sstevel@tonic-gate 		}
427*0Sstevel@tonic-gate 		if (again) {
428*0Sstevel@tonic-gate 			if (down_one(ctx, ctx)) {
429*0Sstevel@tonic-gate 				return (_URC_FATAL_PHASE2_ERROR);
430*0Sstevel@tonic-gate 			}
431*0Sstevel@tonic-gate 		}
432*0Sstevel@tonic-gate 	} while (again);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	return (res);
435*0Sstevel@tonic-gate }
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate _Unwind_Reason_Code
438*0Sstevel@tonic-gate _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
439*0Sstevel@tonic-gate 	_Unwind_Stop_Fn stop, void *stop_parameter)
440*0Sstevel@tonic-gate {
441*0Sstevel@tonic-gate 	struct _Unwind_Context context;
442*0Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	_Unw_capture_regs(ctx->current_regs);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	return (_Unwind_ForcedUnwind_Body(exception_object, stop,
447*0Sstevel@tonic-gate 	    stop_parameter, ctx, 0));
448*0Sstevel@tonic-gate }
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate void
451*0Sstevel@tonic-gate _Unwind_Resume(struct _Unwind_Exception *exception_object)
452*0Sstevel@tonic-gate {
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	struct _Unwind_Context context;
455*0Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	_Unw_capture_regs(ctx->current_regs);
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	if (exception_object->private_1)
460*0Sstevel@tonic-gate 		(void) _Unwind_ForcedUnwind_Body(exception_object,
461*0Sstevel@tonic-gate 		    (_Unwind_Stop_Fn)exception_object->private_1,
462*0Sstevel@tonic-gate 		    (void *)exception_object->private_2,
463*0Sstevel@tonic-gate 		    ctx, 1);
464*0Sstevel@tonic-gate 	else
465*0Sstevel@tonic-gate 		(void) _Unwind_RaiseException_Body(exception_object, ctx,
466*0Sstevel@tonic-gate 		    _UA_CLEANUP_PHASE);
467*0Sstevel@tonic-gate }
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate /* Calls destructor function for exception object */
470*0Sstevel@tonic-gate void
471*0Sstevel@tonic-gate _Unwind_DeleteException(struct _Unwind_Exception *exception_object)
472*0Sstevel@tonic-gate {
473*0Sstevel@tonic-gate 	if (exception_object->exception_cleanup != 0)
474*0Sstevel@tonic-gate 		(*(exception_object->exception_cleanup))(_URC_NO_REASON,
475*0Sstevel@tonic-gate 		    exception_object);
476*0Sstevel@tonic-gate }
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate /*
480*0Sstevel@tonic-gate  * stack frame context accessors defined in ABI
481*0Sstevel@tonic-gate  * (despite all the dire text in the ABI these are reliable Get/Set routines)
482*0Sstevel@tonic-gate  * Note: RA is handled as GR value
483*0Sstevel@tonic-gate  */
484*0Sstevel@tonic-gate uint64_t
485*0Sstevel@tonic-gate _Unwind_GetGR(struct _Unwind_Context *context, int index)
486*0Sstevel@tonic-gate {
487*0Sstevel@tonic-gate 	uint64_t res = 0;
488*0Sstevel@tonic-gate 	if (index <= EIR_R15) {
489*0Sstevel@tonic-gate 		res = context->current_regs[index];
490*0Sstevel@tonic-gate 	} else if (index == RET_ADD) {
491*0Sstevel@tonic-gate 		res = context->ra;
492*0Sstevel@tonic-gate 	}
493*0Sstevel@tonic-gate 	return (res);
494*0Sstevel@tonic-gate }
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate void
498*0Sstevel@tonic-gate _Unwind_SetGR(struct _Unwind_Context *context, int index,
499*0Sstevel@tonic-gate uint64_t new_value)
500*0Sstevel@tonic-gate {
501*0Sstevel@tonic-gate 	if (index <= EIR_R15) {
502*0Sstevel@tonic-gate 		context->current_regs[index] = new_value;
503*0Sstevel@tonic-gate 	} else if (index == RET_ADD) {
504*0Sstevel@tonic-gate 		context->ra = new_value;
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate }
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate uint64_t
510*0Sstevel@tonic-gate _Unwind_GetIP(struct _Unwind_Context *context)
511*0Sstevel@tonic-gate {
512*0Sstevel@tonic-gate 	return (context->pc);
513*0Sstevel@tonic-gate }
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate void
516*0Sstevel@tonic-gate _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value)
517*0Sstevel@tonic-gate {
518*0Sstevel@tonic-gate 	context->pc = new_value;
519*0Sstevel@tonic-gate }
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate void *
523*0Sstevel@tonic-gate _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context)
524*0Sstevel@tonic-gate {
525*0Sstevel@tonic-gate 	return (context->lsda);
526*0Sstevel@tonic-gate }
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate uint64_t
530*0Sstevel@tonic-gate _Unwind_GetRegionStart(struct _Unwind_Context *context)
531*0Sstevel@tonic-gate {
532*0Sstevel@tonic-gate 	return (context->func);
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate uint64_t
536*0Sstevel@tonic-gate _Unwind_GetCFA(struct _Unwind_Context *context)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	return (context->cfa);
539*0Sstevel@tonic-gate }
540