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