xref: /onnv-gate/usr/src/lib/libc/amd64/unwind/unwind.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6812Sraf  * Common Development and Distribution License (the "License").
6*6812Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211111Sraf 
220Sstevel@tonic-gate /*
23*6812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * UNWIND - Unwind library
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate /*
340Sstevel@tonic-gate  * ===================== stack walk ====================
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * Stack walk-back starts with the user code at the top of the stack
370Sstevel@tonic-gate  * calling a language specific support routine which calls the generic
380Sstevel@tonic-gate  * unwind code. The unwind code captures
390Sstevel@tonic-gate  * information which can be used to partially build an _Unwind_Context
400Sstevel@tonic-gate  * for the user code containing:
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  *    callee saves registers <current values>
430Sstevel@tonic-gate  *    PC
440Sstevel@tonic-gate  *    %rbp
450Sstevel@tonic-gate  *    %rsp
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * Using that pc location the unwind info for the function is found.
480Sstevel@tonic-gate  * Then the CFA operations encoded in the unwind info are interepreted to get
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  *    callee saves registers <values on entry>
510Sstevel@tonic-gate  *    the return address
520Sstevel@tonic-gate  *    cannonical frame address
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * completing the context for the user function (See
550Sstevel@tonic-gate  * _Unw_Rollback_Registers()) .
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * The values computed above are equivalent to the info which would have been
580Sstevel@tonic-gate  * captured from the caller and are used to initialize the callers context
590Sstevel@tonic-gate  * (see _Unw_Propagate_Registers()) which can be completed.
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  * Using the same two-step procedure
620Sstevel@tonic-gate  * context records for each frame down the stack may be constructed
630Sstevel@tonic-gate  * in turn.  The ABI defined interface to _Unwind_Context provides
640Sstevel@tonic-gate  * access to
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  *    callee saves registers <current values>
670Sstevel@tonic-gate  *    current PC
680Sstevel@tonic-gate  *    frame pointer
690Sstevel@tonic-gate  *
700Sstevel@tonic-gate  * and allows changing
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  *    PC
730Sstevel@tonic-gate  *    values of integer argument registers
740Sstevel@tonic-gate  *
750Sstevel@tonic-gate  * (changed values take effect if context is "installed" - think
760Sstevel@tonic-gate  * setcontext(2))
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  */
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  * |                              |
830Sstevel@tonic-gate  * | local storage for start()    | <FP == 0>
840Sstevel@tonic-gate  * |                              |
850Sstevel@tonic-gate  * --------------------------------.
860Sstevel@tonic-gate  * |                              |
870Sstevel@tonic-gate  * |     ..........               |
880Sstevel@tonic-gate  * |                              | <-  CFA for bar()
890Sstevel@tonic-gate  * --------------------------------.
900Sstevel@tonic-gate  * |                              |
910Sstevel@tonic-gate  * | local storage for bar()      |
920Sstevel@tonic-gate  * |                              | <-  SP for bar(), CFA for foo()
930Sstevel@tonic-gate  * ................................
940Sstevel@tonic-gate  * |  pc for bar()                |
950Sstevel@tonic-gate  * --------------------------------
960Sstevel@tonic-gate  * |                              |
970Sstevel@tonic-gate  * | local storage for foo()      |
980Sstevel@tonic-gate  * |                              | <-  SP for foo(), CFA for ex_throw()
990Sstevel@tonic-gate  * ................................
1000Sstevel@tonic-gate  * | pc for foo() - PC3           |
1010Sstevel@tonic-gate  * ................................
1020Sstevel@tonic-gate  * | saved RBP from foo() - BP3   | <-  FP for ex_throw() == FP2
1030Sstevel@tonic-gate  * --------------------------------
1040Sstevel@tonic-gate  * |                              |
1050Sstevel@tonic-gate  * | local storage for ex_throw() |
1060Sstevel@tonic-gate  * |                              | <- SP for ex_throw(), CFA for Unw()
1070Sstevel@tonic-gate  * ................................
1080Sstevel@tonic-gate  * | pc for ex_throw() - PC2      |
1090Sstevel@tonic-gate  * ................................
1100Sstevel@tonic-gate  * | saved RBP from ex_throw()    | <- FP for Unw() == FP1
1110Sstevel@tonic-gate  * --------------------------------
1120Sstevel@tonic-gate  * |                              |
1130Sstevel@tonic-gate  * | local storage for Unw()      |
1140Sstevel@tonic-gate  * |                              | <- SP for Unw() == SP1
1150Sstevel@tonic-gate  *
1160Sstevel@tonic-gate  * We know that Unw() and ex_throw save and have an FP
1170Sstevel@tonic-gate  *
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate #ifdef _LIBCRUN_
1210Sstevel@tonic-gate #define	_Unwind_DeleteException  _SUNW_Unwind_DeleteException
1220Sstevel@tonic-gate #define	_Unwind_ForcedUnwind  _SUNW_Unwind_ForcedUnwind
1230Sstevel@tonic-gate #define	_Unwind_GetCFA  _SUNW_Unwind_GetCFA
1240Sstevel@tonic-gate #define	_Unwind_GetGR  _SUNW_Unwind_GetGR
1250Sstevel@tonic-gate #define	_Unwind_GetIP  _SUNW_Unwind_GetIP
1260Sstevel@tonic-gate #define	_Unwind_GetLanguageSpecificData _SUNW_Unwind_GetLanguageSpecificData
1270Sstevel@tonic-gate #define	_Unwind_GetRegionStart  _SUNW_Unwind_GetRegionStart
1280Sstevel@tonic-gate #define	_Unwind_RaiseException  _SUNW_Unwind_RaiseException
1290Sstevel@tonic-gate #define	_Unwind_Resume  _SUNW_Unwind_Resume
1300Sstevel@tonic-gate #define	_Unwind_SetGR  _SUNW_Unwind_SetGR
1310Sstevel@tonic-gate #define	_Unwind_SetIP  _SUNW_Unwind_SetIP
1320Sstevel@tonic-gate #else
133*6812Sraf #pragma weak _SUNW_Unwind_DeleteException = _Unwind_DeleteException
134*6812Sraf #pragma weak _SUNW_Unwind_ForcedUnwind = _Unwind_ForcedUnwind
135*6812Sraf #pragma weak _SUNW_Unwind_GetCFA = _Unwind_GetCFA
136*6812Sraf #pragma weak _SUNW_Unwind_GetGR = _Unwind_GetGR
137*6812Sraf #pragma weak _SUNW_Unwind_GetIP = _Unwind_GetIP
138*6812Sraf #pragma weak _SUNW_Unwind_GetLanguageSpecificData = \
139*6812Sraf 		_Unwind_GetLanguageSpecificData
140*6812Sraf #pragma weak _SUNW_Unwind_GetRegionStart = _Unwind_GetRegionStart
141*6812Sraf #pragma weak _SUNW_Unwind_RaiseException = _Unwind_RaiseException
142*6812Sraf #pragma weak _SUNW_Unwind_Resume = _Unwind_Resume
143*6812Sraf #pragma weak _SUNW_Unwind_SetGR = _Unwind_SetGR
144*6812Sraf #pragma weak _SUNW_Unwind_SetIP = _Unwind_SetIP
1450Sstevel@tonic-gate #endif
1460Sstevel@tonic-gate 
147*6812Sraf #include "lint.h"
1481111Sraf #include <string.h>
1490Sstevel@tonic-gate #include "stack_unwind.h"
1500Sstevel@tonic-gate #include "reg_num.h"
1510Sstevel@tonic-gate #include "unwind_context.h"
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate const _Unwind_Action _UA_SEARCH_PHASE = 1;
1540Sstevel@tonic-gate const _Unwind_Action _UA_CLEANUP_PHASE = 2;
1550Sstevel@tonic-gate const _Unwind_Action _UA_HANDLER_FRAME = 4;
1560Sstevel@tonic-gate const _Unwind_Action _UA_FORCE_UNWIND = 8;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate void _Unw_capture_regs(uint64_t *regs);
1590Sstevel@tonic-gate void _Unw_jmp(uint64_t pc, uint64_t *regs);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static void
copy_ctx(struct _Unwind_Context * ctx1,struct _Unwind_Context * ctx2)1620Sstevel@tonic-gate copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	if (ctx1 != ctx2) {
1651111Sraf 		(void) memcpy(ctx2, ctx1, sizeof (*ctx2));
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static _Unwind_Personality_Fn
ctx_who(struct _Unwind_Context * ctx)1700Sstevel@tonic-gate ctx_who(struct _Unwind_Context *ctx)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	return (ctx->pfn);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /* ARGSUSED */
1760Sstevel@tonic-gate _Unwind_Reason_Code
_Unw_very_boring_personality(int version,int actions,uint64_t exclass,struct _Unwind_Exception * exception_object,struct _Unwind_Context * ctx)1770Sstevel@tonic-gate _Unw_very_boring_personality(int version, int actions, uint64_t exclass,
1780Sstevel@tonic-gate 	struct _Unwind_Exception *exception_object,
1790Sstevel@tonic-gate 	struct _Unwind_Context *ctx)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	_Unwind_Reason_Code res = _URC_CONTINUE_UNWIND;
1820Sstevel@tonic-gate 	uint64_t fp;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	fp =  _Unwind_GetCFA(ctx);
1850Sstevel@tonic-gate 	if (fp == 0 || _Unwind_GetIP(ctx) == 0) {
1860Sstevel@tonic-gate 		return (_URC_END_OF_STACK);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 	return (res);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate  * The only static variables in this code - changed by debugging hook below
1930Sstevel@tonic-gate  */
1940Sstevel@tonic-gate static int using_ehf = 1;
1950Sstevel@tonic-gate static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate void
_SUNW_Unw_set_defaults(int use,uintptr_t def_per)1980Sstevel@tonic-gate _SUNW_Unw_set_defaults(int use, uintptr_t def_per)
1990Sstevel@tonic-gate {
2000Sstevel@tonic-gate 	using_ehf = use;
2010Sstevel@tonic-gate 	def_per_fcn = def_per;
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate static void
complete_context(struct _Unwind_Context * ctx)2050Sstevel@tonic-gate complete_context(struct _Unwind_Context *ctx)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate 	struct eh_frame_fields sf;
2080Sstevel@tonic-gate 	struct eh_frame_fields *sfp = 0;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn;
2110Sstevel@tonic-gate 	ctx->lsda = 0;
2120Sstevel@tonic-gate 	ctx->func = 0;
2130Sstevel@tonic-gate 	ctx->range = 0;
2140Sstevel@tonic-gate 	ctx->fde = 0;
2150Sstevel@tonic-gate 	if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) {
2160Sstevel@tonic-gate 		sfp = _Unw_Decode_FDE(&sf, ctx);
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 	(void) _Unw_Rollback_Registers(sfp, ctx);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate  * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad))
2230Sstevel@tonic-gate  *
2240Sstevel@tonic-gate  * FP2 = FP1[0];
2250Sstevel@tonic-gate  * BP3 = FP2[0];
2260Sstevel@tonic-gate  * PC3 = FP2[1];
2270Sstevel@tonic-gate  * SP3 = FP2 + 16;
2280Sstevel@tonic-gate  *
2290Sstevel@tonic-gate  * output: PC3, SP3, and BP3
2300Sstevel@tonic-gate  *
2310Sstevel@tonic-gate  * remaining callee saves registers are also captured in context
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate static void
finish_capture(struct _Unwind_Context * ctx,int from_landing_pad)2340Sstevel@tonic-gate finish_capture(struct _Unwind_Context *ctx, int from_landing_pad)
2350Sstevel@tonic-gate {
2360Sstevel@tonic-gate 	uint64_t fp1 = ctx->current_regs[FP_RBP];
2370Sstevel@tonic-gate 	uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0];
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	ctx->pc = ((uint64_t *)fp2)[1];
2400Sstevel@tonic-gate 	ctx->current_regs[SP_RSP] = fp2 + 16;
2410Sstevel@tonic-gate 	ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0];
2420Sstevel@tonic-gate 	complete_context(ctx);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static int
down_one(struct _Unwind_Context * old_ctx,struct _Unwind_Context * new_ctx)2460Sstevel@tonic-gate down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate 	uint64_t old_cfa = old_ctx->cfa;
2490Sstevel@tonic-gate 	uint64_t old_pc = old_ctx->pc;
2500Sstevel@tonic-gate 	uint64_t new_cfa;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (old_cfa == 0 || old_pc == 0) {
2530Sstevel@tonic-gate 		new_ctx->pc = 0;
2540Sstevel@tonic-gate 		new_ctx->cfa = 0;
2550Sstevel@tonic-gate 		new_ctx->ra = 0;
2560Sstevel@tonic-gate 		return (1);
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 	if (old_ctx->ra == 0) {
2590Sstevel@tonic-gate 		new_ctx->pc = 0;
2600Sstevel@tonic-gate 		new_ctx->cfa = 0;
2610Sstevel@tonic-gate 		new_ctx->ra = 0;
2620Sstevel@tonic-gate 		return (0);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	/* now shift ----------------------------- */
2650Sstevel@tonic-gate 	_Unw_Propagate_Registers(old_ctx, new_ctx);
2660Sstevel@tonic-gate 	complete_context(new_ctx);
2670Sstevel@tonic-gate 	new_cfa = new_ctx->cfa;
2680Sstevel@tonic-gate 	if ((new_cfa < old_cfa) || (new_cfa & 7)) {
2690Sstevel@tonic-gate 		new_ctx->pc = 0;
2700Sstevel@tonic-gate 		new_ctx->cfa = 0;
2710Sstevel@tonic-gate 		new_ctx->ra = 0;
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 	return (0);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate static void
jmp_ctx(struct _Unwind_Context * ctx)2770Sstevel@tonic-gate jmp_ctx(struct _Unwind_Context *ctx)
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate 	_Unw_jmp(ctx->pc, ctx->current_regs);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate  * Here starts the real work - the entry points from either a language
2840Sstevel@tonic-gate  * runtime or directly from user code.
2850Sstevel@tonic-gate  *
2860Sstevel@tonic-gate  * The two ..._Body functions are intended as private interfaces for
2870Sstevel@tonic-gate  * Sun code as well so should remain accessible.
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate _Unwind_Reason_Code
_Unwind_RaiseException_Body(struct _Unwind_Exception * exception_object,struct _Unwind_Context * entry_ctx,int phase)2900Sstevel@tonic-gate _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object,
2910Sstevel@tonic-gate 	struct _Unwind_Context *entry_ctx, int phase)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	struct _Unwind_Context context;
2940Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
2950Sstevel@tonic-gate 	_Unwind_Reason_Code res;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (phase & _UA_SEARCH_PHASE) {
2980Sstevel@tonic-gate 		finish_capture(entry_ctx, 0);
2990Sstevel@tonic-gate 		copy_ctx(entry_ctx, ctx);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 		for (;;) {
3020Sstevel@tonic-gate 			res = (*ctx_who(ctx))(1, phase,
3030Sstevel@tonic-gate 			    exception_object->exception_class,
3040Sstevel@tonic-gate 			    exception_object, ctx);
3050Sstevel@tonic-gate 			if (res != _URC_CONTINUE_UNWIND)
3060Sstevel@tonic-gate 				break;
3070Sstevel@tonic-gate 			if (down_one(ctx, ctx))
3080Sstevel@tonic-gate 				return (_URC_FATAL_PHASE1_ERROR);
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 		switch (res) {
3110Sstevel@tonic-gate 		case _URC_HANDLER_FOUND:
3120Sstevel@tonic-gate 			exception_object->private_2 = _Unwind_GetCFA(ctx);
3130Sstevel@tonic-gate 			break;
3140Sstevel@tonic-gate 		default:
3150Sstevel@tonic-gate 			return (res);
3160Sstevel@tonic-gate 			break;
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 	} else {
3190Sstevel@tonic-gate 		finish_capture(entry_ctx, 1);
3200Sstevel@tonic-gate 		if (down_one(entry_ctx, entry_ctx))
3210Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	phase = _UA_CLEANUP_PHASE;
3250Sstevel@tonic-gate 	copy_ctx(entry_ctx, ctx);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	for (;;) {
3280Sstevel@tonic-gate 		if (exception_object->private_2 == _Unwind_GetCFA(ctx)) {
3290Sstevel@tonic-gate 			phase |= _UA_HANDLER_FRAME;
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 		res = (*ctx_who(ctx))(1, phase,
3320Sstevel@tonic-gate 		    exception_object->exception_class,
3330Sstevel@tonic-gate 		    exception_object, ctx);
3340Sstevel@tonic-gate 		if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT)
3350Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
3360Sstevel@tonic-gate 		if (res != _URC_CONTINUE_UNWIND)
3370Sstevel@tonic-gate 			break;
3380Sstevel@tonic-gate 		if (down_one(ctx, ctx))
3390Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 	switch (res) {
3420Sstevel@tonic-gate 	case _URC_INSTALL_CONTEXT:
3430Sstevel@tonic-gate 		exception_object->private_1 = 0;
3440Sstevel@tonic-gate 		jmp_ctx(ctx); /* does not return */
3450Sstevel@tonic-gate 		break;
3460Sstevel@tonic-gate 	default:
3470Sstevel@tonic-gate 		break;
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 	return (res);
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate _Unwind_Reason_Code
_Unwind_RaiseException(struct _Unwind_Exception * exception_object)3530Sstevel@tonic-gate _Unwind_RaiseException(struct _Unwind_Exception *exception_object)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	struct _Unwind_Context entry_context;
3560Sstevel@tonic-gate 	struct _Unwind_Context *entry_ctx = &entry_context;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	_Unw_capture_regs(entry_ctx->current_regs);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	return (_Unwind_RaiseException_Body(exception_object, entry_ctx,
3610Sstevel@tonic-gate 	    _UA_SEARCH_PHASE));
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate _Unwind_Reason_Code
_Unwind_ForcedUnwind_Body(struct _Unwind_Exception * exception_object,_Unwind_Stop_Fn stop,void * stop_parameter,struct _Unwind_Context * ctx,int resume)3650Sstevel@tonic-gate _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object,
3660Sstevel@tonic-gate 	_Unwind_Stop_Fn stop, void *stop_parameter,
3670Sstevel@tonic-gate 	struct _Unwind_Context *ctx, int resume)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate 	_Unwind_Reason_Code res;
3700Sstevel@tonic-gate 	int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	int again;
3730Sstevel@tonic-gate 	int doper;
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	finish_capture(ctx, resume);
3760Sstevel@tonic-gate 	if (resume && down_one(ctx, ctx))
377*6812Sraf 		return (_URC_FATAL_PHASE2_ERROR);
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	do {
3800Sstevel@tonic-gate 		again = 0;
3810Sstevel@tonic-gate 		doper = 0;
3820Sstevel@tonic-gate 		res = (*stop)(1, phase,
3830Sstevel@tonic-gate 		    exception_object->exception_class,
3840Sstevel@tonic-gate 		    exception_object, ctx, stop_parameter);
3850Sstevel@tonic-gate 		switch (res) {
3860Sstevel@tonic-gate 		case _URC_CONTINUE_UNWIND:
3870Sstevel@tonic-gate 			/* keep going - don't call personality */
3880Sstevel@tonic-gate 			again = 1;
3890Sstevel@tonic-gate 			break;
3900Sstevel@tonic-gate 		case _URC_NO_REASON:
3910Sstevel@tonic-gate 			/* keep going - do call personality */
3920Sstevel@tonic-gate 			again = 1;
3930Sstevel@tonic-gate 			doper = 1;
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 		case _URC_NORMAL_STOP:  /* done */
3960Sstevel@tonic-gate 			break;
3970Sstevel@tonic-gate 		case _URC_INSTALL_CONTEXT:  /* resume execution */
3980Sstevel@tonic-gate 			break;
3990Sstevel@tonic-gate 		default:		/* failure */
4000Sstevel@tonic-gate 			break;
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate 		if (doper) {
4030Sstevel@tonic-gate 			res = (*ctx_who(ctx))(1, phase,
4040Sstevel@tonic-gate 			    exception_object->exception_class,
4050Sstevel@tonic-gate 			    exception_object, ctx);
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 		switch (res) {
4080Sstevel@tonic-gate 		case _URC_INSTALL_CONTEXT:
4090Sstevel@tonic-gate 			exception_object->private_1 = (uint64_t)stop;
4100Sstevel@tonic-gate 			exception_object->private_2 = (uint64_t)stop_parameter;
4110Sstevel@tonic-gate 			jmp_ctx(ctx); /* does not return */
4120Sstevel@tonic-gate 			break;
4130Sstevel@tonic-gate 		case _URC_CONTINUE_UNWIND:
4140Sstevel@tonic-gate 		case _URC_NO_REASON:
4150Sstevel@tonic-gate 			break;
4160Sstevel@tonic-gate 		case _URC_END_OF_STACK:
4170Sstevel@tonic-gate 			ctx->cfa = ctx->ra = ctx->pc = 0;
4180Sstevel@tonic-gate 			res = (*stop)(1, phase,
419*6812Sraf 			    exception_object->exception_class,
420*6812Sraf 			    exception_object, ctx, stop_parameter);
4210Sstevel@tonic-gate 			return (_URC_END_OF_STACK);
4220Sstevel@tonic-gate 			break;
4230Sstevel@tonic-gate 		default:
4240Sstevel@tonic-gate 			again = 0;
4250Sstevel@tonic-gate 			break;
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 		if (again) {
4280Sstevel@tonic-gate 			if (down_one(ctx, ctx)) {
4290Sstevel@tonic-gate 				return (_URC_FATAL_PHASE2_ERROR);
4300Sstevel@tonic-gate 			}
4310Sstevel@tonic-gate 		}
4320Sstevel@tonic-gate 	} while (again);
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	return (res);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate _Unwind_Reason_Code
_Unwind_ForcedUnwind(struct _Unwind_Exception * exception_object,_Unwind_Stop_Fn stop,void * stop_parameter)4380Sstevel@tonic-gate _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
4390Sstevel@tonic-gate 	_Unwind_Stop_Fn stop, void *stop_parameter)
4400Sstevel@tonic-gate {
4410Sstevel@tonic-gate 	struct _Unwind_Context context;
4420Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	_Unw_capture_regs(ctx->current_regs);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (_Unwind_ForcedUnwind_Body(exception_object, stop,
4470Sstevel@tonic-gate 	    stop_parameter, ctx, 0));
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate void
_Unwind_Resume(struct _Unwind_Exception * exception_object)4510Sstevel@tonic-gate _Unwind_Resume(struct _Unwind_Exception *exception_object)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	struct _Unwind_Context context;
4550Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	_Unw_capture_regs(ctx->current_regs);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	if (exception_object->private_1)
4600Sstevel@tonic-gate 		(void) _Unwind_ForcedUnwind_Body(exception_object,
4610Sstevel@tonic-gate 		    (_Unwind_Stop_Fn)exception_object->private_1,
4620Sstevel@tonic-gate 		    (void *)exception_object->private_2,
4630Sstevel@tonic-gate 		    ctx, 1);
4640Sstevel@tonic-gate 	else
4650Sstevel@tonic-gate 		(void) _Unwind_RaiseException_Body(exception_object, ctx,
4660Sstevel@tonic-gate 		    _UA_CLEANUP_PHASE);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate /* Calls destructor function for exception object */
4700Sstevel@tonic-gate void
_Unwind_DeleteException(struct _Unwind_Exception * exception_object)4710Sstevel@tonic-gate _Unwind_DeleteException(struct _Unwind_Exception *exception_object)
4720Sstevel@tonic-gate {
4730Sstevel@tonic-gate 	if (exception_object->exception_cleanup != 0)
4740Sstevel@tonic-gate 		(*(exception_object->exception_cleanup))(_URC_NO_REASON,
4750Sstevel@tonic-gate 		    exception_object);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate /*
4800Sstevel@tonic-gate  * stack frame context accessors defined in ABI
4810Sstevel@tonic-gate  * (despite all the dire text in the ABI these are reliable Get/Set routines)
4820Sstevel@tonic-gate  * Note: RA is handled as GR value
4830Sstevel@tonic-gate  */
4840Sstevel@tonic-gate uint64_t
_Unwind_GetGR(struct _Unwind_Context * context,int index)4850Sstevel@tonic-gate _Unwind_GetGR(struct _Unwind_Context *context, int index)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	uint64_t res = 0;
4880Sstevel@tonic-gate 	if (index <= EIR_R15) {
4890Sstevel@tonic-gate 		res = context->current_regs[index];
4900Sstevel@tonic-gate 	} else if (index == RET_ADD) {
4910Sstevel@tonic-gate 		res = context->ra;
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 	return (res);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate void
_Unwind_SetGR(struct _Unwind_Context * context,int index,uint64_t new_value)4980Sstevel@tonic-gate _Unwind_SetGR(struct _Unwind_Context *context, int index,
4990Sstevel@tonic-gate uint64_t new_value)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	if (index <= EIR_R15) {
5020Sstevel@tonic-gate 		context->current_regs[index] = new_value;
5030Sstevel@tonic-gate 	} else if (index == RET_ADD) {
5040Sstevel@tonic-gate 		context->ra = new_value;
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate }
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate uint64_t
_Unwind_GetIP(struct _Unwind_Context * context)5100Sstevel@tonic-gate _Unwind_GetIP(struct _Unwind_Context *context)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	return (context->pc);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate void
_Unwind_SetIP(struct _Unwind_Context * context,uint64_t new_value)5160Sstevel@tonic-gate _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	context->pc = new_value;
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate void *
_Unwind_GetLanguageSpecificData(struct _Unwind_Context * context)5230Sstevel@tonic-gate _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	return (context->lsda);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate uint64_t
_Unwind_GetRegionStart(struct _Unwind_Context * context)5300Sstevel@tonic-gate _Unwind_GetRegionStart(struct _Unwind_Context *context)
5310Sstevel@tonic-gate {
5320Sstevel@tonic-gate 	return (context->func);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate uint64_t
_Unwind_GetCFA(struct _Unwind_Context * context)5360Sstevel@tonic-gate _Unwind_GetCFA(struct _Unwind_Context *context)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	return (context->cfa);
5390Sstevel@tonic-gate }
540