xref: /illumos-gate/usr/src/lib/libc/amd64/unwind/unwind.c (revision 1ba82a13)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57257d1b4Sraf  * Common Development and Distribution License (the "License").
67257d1b4Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
210293487cSraf 
227c478bd9Sstevel@tonic-gate /*
237257d1b4Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2533f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
26*1ba82a13SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * UNWIND - Unwind library
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * ===================== stack walk ====================
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * Stack walk-back starts with the user code at the top of the stack
377c478bd9Sstevel@tonic-gate  * calling a language specific support routine which calls the generic
387c478bd9Sstevel@tonic-gate  * unwind code. The unwind code captures
397c478bd9Sstevel@tonic-gate  * information which can be used to partially build an _Unwind_Context
407c478bd9Sstevel@tonic-gate  * for the user code containing:
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  *    callee saves registers <current values>
437c478bd9Sstevel@tonic-gate  *    PC
447c478bd9Sstevel@tonic-gate  *    %rbp
457c478bd9Sstevel@tonic-gate  *    %rsp
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * Using that pc location the unwind info for the function is found.
487c478bd9Sstevel@tonic-gate  * Then the CFA operations encoded in the unwind info are interepreted to get
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  *    callee saves registers <values on entry>
517c478bd9Sstevel@tonic-gate  *    the return address
527c478bd9Sstevel@tonic-gate  *    cannonical frame address
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * completing the context for the user function (See
557c478bd9Sstevel@tonic-gate  * _Unw_Rollback_Registers()) .
567c478bd9Sstevel@tonic-gate  *
577c478bd9Sstevel@tonic-gate  * The values computed above are equivalent to the info which would have been
587c478bd9Sstevel@tonic-gate  * captured from the caller and are used to initialize the callers context
597c478bd9Sstevel@tonic-gate  * (see _Unw_Propagate_Registers()) which can be completed.
607c478bd9Sstevel@tonic-gate  *
617c478bd9Sstevel@tonic-gate  * Using the same two-step procedure
627c478bd9Sstevel@tonic-gate  * context records for each frame down the stack may be constructed
637c478bd9Sstevel@tonic-gate  * in turn.  The ABI defined interface to _Unwind_Context provides
647c478bd9Sstevel@tonic-gate  * access to
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  *    callee saves registers <current values>
677c478bd9Sstevel@tonic-gate  *    current PC
687c478bd9Sstevel@tonic-gate  *    frame pointer
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  * and allows changing
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  *    PC
737c478bd9Sstevel@tonic-gate  *    values of integer argument registers
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * (changed values take effect if context is "installed" - think
767c478bd9Sstevel@tonic-gate  * setcontext(2))
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  * |                              |
837c478bd9Sstevel@tonic-gate  * | local storage for start()    | <FP == 0>
847c478bd9Sstevel@tonic-gate  * |                              |
857c478bd9Sstevel@tonic-gate  * --------------------------------.
867c478bd9Sstevel@tonic-gate  * |                              |
877c478bd9Sstevel@tonic-gate  * |     ..........               |
887c478bd9Sstevel@tonic-gate  * |                              | <-  CFA for bar()
897c478bd9Sstevel@tonic-gate  * --------------------------------.
907c478bd9Sstevel@tonic-gate  * |                              |
917c478bd9Sstevel@tonic-gate  * | local storage for bar()      |
927c478bd9Sstevel@tonic-gate  * |                              | <-  SP for bar(), CFA for foo()
937c478bd9Sstevel@tonic-gate  * ................................
947c478bd9Sstevel@tonic-gate  * |  pc for bar()                |
957c478bd9Sstevel@tonic-gate  * --------------------------------
967c478bd9Sstevel@tonic-gate  * |                              |
977c478bd9Sstevel@tonic-gate  * | local storage for foo()      |
987c478bd9Sstevel@tonic-gate  * |                              | <-  SP for foo(), CFA for ex_throw()
997c478bd9Sstevel@tonic-gate  * ................................
1007c478bd9Sstevel@tonic-gate  * | pc for foo() - PC3           |
1017c478bd9Sstevel@tonic-gate  * ................................
1027c478bd9Sstevel@tonic-gate  * | saved RBP from foo() - BP3   | <-  FP for ex_throw() == FP2
1037c478bd9Sstevel@tonic-gate  * --------------------------------
1047c478bd9Sstevel@tonic-gate  * |                              |
1057c478bd9Sstevel@tonic-gate  * | local storage for ex_throw() |
1067c478bd9Sstevel@tonic-gate  * |                              | <- SP for ex_throw(), CFA for Unw()
1077c478bd9Sstevel@tonic-gate  * ................................
1087c478bd9Sstevel@tonic-gate  * | pc for ex_throw() - PC2      |
1097c478bd9Sstevel@tonic-gate  * ................................
1107c478bd9Sstevel@tonic-gate  * | saved RBP from ex_throw()    | <- FP for Unw() == FP1
1117c478bd9Sstevel@tonic-gate  * --------------------------------
1127c478bd9Sstevel@tonic-gate  * |                              |
1137c478bd9Sstevel@tonic-gate  * | local storage for Unw()      |
1147c478bd9Sstevel@tonic-gate  * |                              | <- SP for Unw() == SP1
1157c478bd9Sstevel@tonic-gate  *
1167c478bd9Sstevel@tonic-gate  * We know that Unw() and ex_throw save and have an FP
1177c478bd9Sstevel@tonic-gate  *
1187c478bd9Sstevel@tonic-gate  */
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate #ifdef _LIBCRUN_
1217c478bd9Sstevel@tonic-gate #define	_Unwind_DeleteException  _SUNW_Unwind_DeleteException
1227c478bd9Sstevel@tonic-gate #define	_Unwind_ForcedUnwind  _SUNW_Unwind_ForcedUnwind
1237c478bd9Sstevel@tonic-gate #define	_Unwind_GetCFA  _SUNW_Unwind_GetCFA
1247c478bd9Sstevel@tonic-gate #define	_Unwind_GetGR  _SUNW_Unwind_GetGR
1257c478bd9Sstevel@tonic-gate #define	_Unwind_GetIP  _SUNW_Unwind_GetIP
1267c478bd9Sstevel@tonic-gate #define	_Unwind_GetLanguageSpecificData _SUNW_Unwind_GetLanguageSpecificData
1277c478bd9Sstevel@tonic-gate #define	_Unwind_GetRegionStart  _SUNW_Unwind_GetRegionStart
1287c478bd9Sstevel@tonic-gate #define	_Unwind_Resume  _SUNW_Unwind_Resume
1297c478bd9Sstevel@tonic-gate #define	_Unwind_SetGR  _SUNW_Unwind_SetGR
1307c478bd9Sstevel@tonic-gate #define	_Unwind_SetIP  _SUNW_Unwind_SetIP
1317c478bd9Sstevel@tonic-gate #else
1327257d1b4Sraf #pragma weak _SUNW_Unwind_DeleteException = _Unwind_DeleteException
1337257d1b4Sraf #pragma weak _SUNW_Unwind_ForcedUnwind = _Unwind_ForcedUnwind
1347257d1b4Sraf #pragma weak _SUNW_Unwind_GetCFA = _Unwind_GetCFA
1357257d1b4Sraf #pragma weak _SUNW_Unwind_GetGR = _Unwind_GetGR
1367257d1b4Sraf #pragma weak _SUNW_Unwind_GetIP = _Unwind_GetIP
1377257d1b4Sraf #pragma weak _SUNW_Unwind_GetLanguageSpecificData = \
1387257d1b4Sraf 		_Unwind_GetLanguageSpecificData
1397257d1b4Sraf #pragma weak _SUNW_Unwind_GetRegionStart = _Unwind_GetRegionStart
1407257d1b4Sraf #pragma weak _SUNW_Unwind_Resume = _Unwind_Resume
1417257d1b4Sraf #pragma weak _SUNW_Unwind_SetGR = _Unwind_SetGR
1427257d1b4Sraf #pragma weak _SUNW_Unwind_SetIP = _Unwind_SetIP
1437c478bd9Sstevel@tonic-gate #endif
1447c478bd9Sstevel@tonic-gate 
1457257d1b4Sraf #include "lint.h"
1460293487cSraf #include <string.h>
1477c478bd9Sstevel@tonic-gate #include "stack_unwind.h"
1487c478bd9Sstevel@tonic-gate #include "reg_num.h"
1497c478bd9Sstevel@tonic-gate #include "unwind_context.h"
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate const _Unwind_Action _UA_SEARCH_PHASE = 1;
1527c478bd9Sstevel@tonic-gate const _Unwind_Action _UA_CLEANUP_PHASE = 2;
1537c478bd9Sstevel@tonic-gate const _Unwind_Action _UA_HANDLER_FRAME = 4;
1547c478bd9Sstevel@tonic-gate const _Unwind_Action _UA_FORCE_UNWIND = 8;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate void _Unw_capture_regs(uint64_t *regs);
1577c478bd9Sstevel@tonic-gate void _Unw_jmp(uint64_t pc, uint64_t *regs);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static void
copy_ctx(struct _Unwind_Context * ctx1,struct _Unwind_Context * ctx2)1607c478bd9Sstevel@tonic-gate copy_ctx(struct _Unwind_Context *ctx1, struct _Unwind_Context *ctx2)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	if (ctx1 != ctx2) {
1630293487cSraf 		(void) memcpy(ctx2, ctx1, sizeof (*ctx2));
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate static _Unwind_Personality_Fn
ctx_who(struct _Unwind_Context * ctx)1687c478bd9Sstevel@tonic-gate ctx_who(struct _Unwind_Context *ctx)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	return (ctx->pfn);
1717c478bd9Sstevel@tonic-gate }
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /* ARGSUSED */
1747c478bd9Sstevel@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)1757c478bd9Sstevel@tonic-gate _Unw_very_boring_personality(int version, int actions, uint64_t exclass,
176*1ba82a13SAndy Fiddaman     struct _Unwind_Exception *exception_object, struct _Unwind_Context *ctx)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	_Unwind_Reason_Code res = _URC_CONTINUE_UNWIND;
1797c478bd9Sstevel@tonic-gate 	uint64_t fp;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	fp =  _Unwind_GetCFA(ctx);
1827c478bd9Sstevel@tonic-gate 	if (fp == 0 || _Unwind_GetIP(ctx) == 0) {
1837c478bd9Sstevel@tonic-gate 		return (_URC_END_OF_STACK);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 	return (res);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * The only static variables in this code - changed by debugging hook below
1907c478bd9Sstevel@tonic-gate  */
1917c478bd9Sstevel@tonic-gate static int using_ehf = 1;
1927c478bd9Sstevel@tonic-gate static uintptr_t def_per_fcn = (uintptr_t)&_Unw_very_boring_personality;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate void
_SUNW_Unw_set_defaults(int use,uintptr_t def_per)1957c478bd9Sstevel@tonic-gate _SUNW_Unw_set_defaults(int use, uintptr_t def_per)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	using_ehf = use;
1987c478bd9Sstevel@tonic-gate 	def_per_fcn = def_per;
1997c478bd9Sstevel@tonic-gate }
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate static void
complete_context(struct _Unwind_Context * ctx)2027c478bd9Sstevel@tonic-gate complete_context(struct _Unwind_Context *ctx)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	struct eh_frame_fields sf;
2057c478bd9Sstevel@tonic-gate 	struct eh_frame_fields *sfp = 0;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	ctx->pfn = (_Unwind_Personality_Fn)def_per_fcn;
2087c478bd9Sstevel@tonic-gate 	ctx->lsda = 0;
2097c478bd9Sstevel@tonic-gate 	ctx->func = 0;
2107c478bd9Sstevel@tonic-gate 	ctx->range = 0;
2117c478bd9Sstevel@tonic-gate 	ctx->fde = 0;
2127c478bd9Sstevel@tonic-gate 	if (using_ehf && (0 != _Unw_EhfhLookup(ctx))) {
2137c478bd9Sstevel@tonic-gate 		sfp = _Unw_Decode_FDE(&sf, ctx);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	(void) _Unw_Rollback_Registers(sfp, ctx);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * input: FP1 (or FP2 if from _Unwind_Resume (from_landing_pad))
2207c478bd9Sstevel@tonic-gate  *
2217c478bd9Sstevel@tonic-gate  * FP2 = FP1[0];
2227c478bd9Sstevel@tonic-gate  * BP3 = FP2[0];
2237c478bd9Sstevel@tonic-gate  * PC3 = FP2[1];
2247c478bd9Sstevel@tonic-gate  * SP3 = FP2 + 16;
2257c478bd9Sstevel@tonic-gate  *
2267c478bd9Sstevel@tonic-gate  * output: PC3, SP3, and BP3
2277c478bd9Sstevel@tonic-gate  *
2287c478bd9Sstevel@tonic-gate  * remaining callee saves registers are also captured in context
2297c478bd9Sstevel@tonic-gate  */
2307c478bd9Sstevel@tonic-gate static void
finish_capture(struct _Unwind_Context * ctx,int from_landing_pad)2317c478bd9Sstevel@tonic-gate finish_capture(struct _Unwind_Context *ctx, int from_landing_pad)
2327c478bd9Sstevel@tonic-gate {
2337c478bd9Sstevel@tonic-gate 	uint64_t fp1 = ctx->current_regs[FP_RBP];
2347c478bd9Sstevel@tonic-gate 	uint64_t fp2 = from_landing_pad ? fp1 : ((uint64_t *)fp1)[0];
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	ctx->pc = ((uint64_t *)fp2)[1];
2377c478bd9Sstevel@tonic-gate 	ctx->current_regs[SP_RSP] = fp2 + 16;
2387c478bd9Sstevel@tonic-gate 	ctx->current_regs[FP_RBP] = ((uint64_t *)fp2)[0];
2397c478bd9Sstevel@tonic-gate 	complete_context(ctx);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate static int
down_one(struct _Unwind_Context * old_ctx,struct _Unwind_Context * new_ctx)2437c478bd9Sstevel@tonic-gate down_one(struct _Unwind_Context *old_ctx, struct _Unwind_Context *new_ctx)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	uint64_t old_cfa = old_ctx->cfa;
2467c478bd9Sstevel@tonic-gate 	uint64_t old_pc = old_ctx->pc;
2477c478bd9Sstevel@tonic-gate 	uint64_t new_cfa;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (old_cfa == 0 || old_pc == 0) {
2507c478bd9Sstevel@tonic-gate 		new_ctx->pc = 0;
2517c478bd9Sstevel@tonic-gate 		new_ctx->cfa = 0;
2527c478bd9Sstevel@tonic-gate 		new_ctx->ra = 0;
2537c478bd9Sstevel@tonic-gate 		return (1);
2547c478bd9Sstevel@tonic-gate 	}
2557c478bd9Sstevel@tonic-gate 	if (old_ctx->ra == 0) {
2567c478bd9Sstevel@tonic-gate 		new_ctx->pc = 0;
2577c478bd9Sstevel@tonic-gate 		new_ctx->cfa = 0;
2587c478bd9Sstevel@tonic-gate 		new_ctx->ra = 0;
2597c478bd9Sstevel@tonic-gate 		return (0);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 	/* now shift ----------------------------- */
2627c478bd9Sstevel@tonic-gate 	_Unw_Propagate_Registers(old_ctx, new_ctx);
2637c478bd9Sstevel@tonic-gate 	complete_context(new_ctx);
2647c478bd9Sstevel@tonic-gate 	new_cfa = new_ctx->cfa;
2657c478bd9Sstevel@tonic-gate 	if ((new_cfa < old_cfa) || (new_cfa & 7)) {
2667c478bd9Sstevel@tonic-gate 		new_ctx->pc = 0;
2677c478bd9Sstevel@tonic-gate 		new_ctx->cfa = 0;
2687c478bd9Sstevel@tonic-gate 		new_ctx->ra = 0;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	return (0);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate static void
jmp_ctx(struct _Unwind_Context * ctx)2747c478bd9Sstevel@tonic-gate jmp_ctx(struct _Unwind_Context *ctx)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate 	_Unw_jmp(ctx->pc, ctx->current_regs);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * Here starts the real work - the entry points from either a language
2817c478bd9Sstevel@tonic-gate  * runtime or directly from user code.
2827c478bd9Sstevel@tonic-gate  *
2837c478bd9Sstevel@tonic-gate  * The two ..._Body functions are intended as private interfaces for
2847c478bd9Sstevel@tonic-gate  * Sun code as well so should remain accessible.
2857c478bd9Sstevel@tonic-gate  */
2867c478bd9Sstevel@tonic-gate _Unwind_Reason_Code
_Unwind_RaiseException_Body(struct _Unwind_Exception * exception_object,struct _Unwind_Context * entry_ctx,int phase)2877c478bd9Sstevel@tonic-gate _Unwind_RaiseException_Body(struct _Unwind_Exception *exception_object,
288*1ba82a13SAndy Fiddaman     struct _Unwind_Context *entry_ctx, int phase)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	struct _Unwind_Context context;
2917c478bd9Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
2927c478bd9Sstevel@tonic-gate 	_Unwind_Reason_Code res;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	if (phase & _UA_SEARCH_PHASE) {
2957c478bd9Sstevel@tonic-gate 		finish_capture(entry_ctx, 0);
2967c478bd9Sstevel@tonic-gate 		copy_ctx(entry_ctx, ctx);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 		for (;;) {
2997c478bd9Sstevel@tonic-gate 			res = (*ctx_who(ctx))(1, phase,
3007c478bd9Sstevel@tonic-gate 			    exception_object->exception_class,
3017c478bd9Sstevel@tonic-gate 			    exception_object, ctx);
3027c478bd9Sstevel@tonic-gate 			if (res != _URC_CONTINUE_UNWIND)
3037c478bd9Sstevel@tonic-gate 				break;
3047c478bd9Sstevel@tonic-gate 			if (down_one(ctx, ctx))
3057c478bd9Sstevel@tonic-gate 				return (_URC_FATAL_PHASE1_ERROR);
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 		switch (res) {
3087c478bd9Sstevel@tonic-gate 		case _URC_HANDLER_FOUND:
3097c478bd9Sstevel@tonic-gate 			exception_object->private_2 = _Unwind_GetCFA(ctx);
3107c478bd9Sstevel@tonic-gate 			break;
3117c478bd9Sstevel@tonic-gate 		default:
3127c478bd9Sstevel@tonic-gate 			return (res);
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 	} else {
3157c478bd9Sstevel@tonic-gate 		finish_capture(entry_ctx, 1);
3167c478bd9Sstevel@tonic-gate 		if (down_one(entry_ctx, entry_ctx))
3177c478bd9Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	phase = _UA_CLEANUP_PHASE;
3217c478bd9Sstevel@tonic-gate 	copy_ctx(entry_ctx, ctx);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	for (;;) {
3247c478bd9Sstevel@tonic-gate 		if (exception_object->private_2 == _Unwind_GetCFA(ctx)) {
3257c478bd9Sstevel@tonic-gate 			phase |= _UA_HANDLER_FRAME;
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 		res = (*ctx_who(ctx))(1, phase,
3287c478bd9Sstevel@tonic-gate 		    exception_object->exception_class,
3297c478bd9Sstevel@tonic-gate 		    exception_object, ctx);
3307c478bd9Sstevel@tonic-gate 		if ((phase & _UA_HANDLER_FRAME) && res != _URC_INSTALL_CONTEXT)
3317c478bd9Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
3327c478bd9Sstevel@tonic-gate 		if (res != _URC_CONTINUE_UNWIND)
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		if (down_one(ctx, ctx))
3357c478bd9Sstevel@tonic-gate 			return (_URC_FATAL_PHASE2_ERROR);
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 	switch (res) {
3387c478bd9Sstevel@tonic-gate 	case _URC_INSTALL_CONTEXT:
3397c478bd9Sstevel@tonic-gate 		exception_object->private_1 = 0;
3407c478bd9Sstevel@tonic-gate 		jmp_ctx(ctx); /* does not return */
3417c478bd9Sstevel@tonic-gate 		break;
3427c478bd9Sstevel@tonic-gate 	default:
3437c478bd9Sstevel@tonic-gate 		break;
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	return (res);
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate 
348*1ba82a13SAndy Fiddaman /*
349*1ba82a13SAndy Fiddaman  * Unfortunately, the closed source libCrun.so library calls into the
350*1ba82a13SAndy Fiddaman  * _Unwind_RaiseException function without ensuring that the stack pointer
351*1ba82a13SAndy Fiddaman  * is properly aligned. Some of the downstream functions use SSE instructions
352*1ba82a13SAndy Fiddaman  * and raise GP when the stack is not aligned.
353*1ba82a13SAndy Fiddaman  * To work around this, the entry point for _Unwind_RaiseException is
354*1ba82a13SAndy Fiddaman  * implemented in assembler (in unwind_wrap.s) and it properly aligns the stack
355*1ba82a13SAndy Fiddaman  * before calling the real function here.
356*1ba82a13SAndy Fiddaman  */
3577c478bd9Sstevel@tonic-gate _Unwind_Reason_Code
__Unwind_RaiseException_Backend(struct _Unwind_Exception * exception_object)358*1ba82a13SAndy Fiddaman __Unwind_RaiseException_Backend(struct _Unwind_Exception *exception_object)
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate 	struct _Unwind_Context entry_context;
3617c478bd9Sstevel@tonic-gate 	struct _Unwind_Context *entry_ctx = &entry_context;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	_Unw_capture_regs(entry_ctx->current_regs);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	return (_Unwind_RaiseException_Body(exception_object, entry_ctx,
3667c478bd9Sstevel@tonic-gate 	    _UA_SEARCH_PHASE));
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@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)3707c478bd9Sstevel@tonic-gate _Unwind_ForcedUnwind_Body(struct _Unwind_Exception *exception_object,
371*1ba82a13SAndy Fiddaman     _Unwind_Stop_Fn stop, void *stop_parameter,
372*1ba82a13SAndy Fiddaman     struct _Unwind_Context *ctx, int resume)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	_Unwind_Reason_Code res;
3757c478bd9Sstevel@tonic-gate 	int phase = _UA_CLEANUP_PHASE | _UA_FORCE_UNWIND;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	int again;
3787c478bd9Sstevel@tonic-gate 	int doper;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	finish_capture(ctx, resume);
3817c478bd9Sstevel@tonic-gate 	if (resume && down_one(ctx, ctx))
3827257d1b4Sraf 		return (_URC_FATAL_PHASE2_ERROR);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	do {
3857c478bd9Sstevel@tonic-gate 		again = 0;
3867c478bd9Sstevel@tonic-gate 		doper = 0;
3877c478bd9Sstevel@tonic-gate 		res = (*stop)(1, phase,
3887c478bd9Sstevel@tonic-gate 		    exception_object->exception_class,
3897c478bd9Sstevel@tonic-gate 		    exception_object, ctx, stop_parameter);
3907c478bd9Sstevel@tonic-gate 		switch (res) {
3917c478bd9Sstevel@tonic-gate 		case _URC_CONTINUE_UNWIND:
3927c478bd9Sstevel@tonic-gate 			/* keep going - don't call personality */
3937c478bd9Sstevel@tonic-gate 			again = 1;
3947c478bd9Sstevel@tonic-gate 			break;
3957c478bd9Sstevel@tonic-gate 		case _URC_NO_REASON:
3967c478bd9Sstevel@tonic-gate 			/* keep going - do call personality */
3977c478bd9Sstevel@tonic-gate 			again = 1;
3987c478bd9Sstevel@tonic-gate 			doper = 1;
3997c478bd9Sstevel@tonic-gate 			break;
4007c478bd9Sstevel@tonic-gate 		case _URC_NORMAL_STOP:  /* done */
4017c478bd9Sstevel@tonic-gate 			break;
4027c478bd9Sstevel@tonic-gate 		case _URC_INSTALL_CONTEXT:  /* resume execution */
4037c478bd9Sstevel@tonic-gate 			break;
4047c478bd9Sstevel@tonic-gate 		default:		/* failure */
4057c478bd9Sstevel@tonic-gate 			break;
4067c478bd9Sstevel@tonic-gate 		}
4077c478bd9Sstevel@tonic-gate 		if (doper) {
4087c478bd9Sstevel@tonic-gate 			res = (*ctx_who(ctx))(1, phase,
4097c478bd9Sstevel@tonic-gate 			    exception_object->exception_class,
4107c478bd9Sstevel@tonic-gate 			    exception_object, ctx);
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		switch (res) {
4137c478bd9Sstevel@tonic-gate 		case _URC_INSTALL_CONTEXT:
4147c478bd9Sstevel@tonic-gate 			exception_object->private_1 = (uint64_t)stop;
4157c478bd9Sstevel@tonic-gate 			exception_object->private_2 = (uint64_t)stop_parameter;
4167c478bd9Sstevel@tonic-gate 			jmp_ctx(ctx); /* does not return */
4177c478bd9Sstevel@tonic-gate 			break;
4187c478bd9Sstevel@tonic-gate 		case _URC_CONTINUE_UNWIND:
4197c478bd9Sstevel@tonic-gate 		case _URC_NO_REASON:
4207c478bd9Sstevel@tonic-gate 			break;
4217c478bd9Sstevel@tonic-gate 		case _URC_END_OF_STACK:
4227c478bd9Sstevel@tonic-gate 			ctx->cfa = ctx->ra = ctx->pc = 0;
4237c478bd9Sstevel@tonic-gate 			res = (*stop)(1, phase,
4247257d1b4Sraf 			    exception_object->exception_class,
4257257d1b4Sraf 			    exception_object, ctx, stop_parameter);
4267c478bd9Sstevel@tonic-gate 			return (_URC_END_OF_STACK);
4277c478bd9Sstevel@tonic-gate 		default:
4287c478bd9Sstevel@tonic-gate 			again = 0;
4297c478bd9Sstevel@tonic-gate 			break;
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 		if (again) {
4327c478bd9Sstevel@tonic-gate 			if (down_one(ctx, ctx)) {
4337c478bd9Sstevel@tonic-gate 				return (_URC_FATAL_PHASE2_ERROR);
4347c478bd9Sstevel@tonic-gate 			}
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 	} while (again);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	return (res);
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate _Unwind_Reason_Code
_Unwind_ForcedUnwind(struct _Unwind_Exception * exception_object,_Unwind_Stop_Fn stop,void * stop_parameter)4427c478bd9Sstevel@tonic-gate _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
443*1ba82a13SAndy Fiddaman     _Unwind_Stop_Fn stop, void *stop_parameter)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	struct _Unwind_Context context;
4467c478bd9Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	_Unw_capture_regs(ctx->current_regs);
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	return (_Unwind_ForcedUnwind_Body(exception_object, stop,
4517c478bd9Sstevel@tonic-gate 	    stop_parameter, ctx, 0));
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate void
_Unwind_Resume(struct _Unwind_Exception * exception_object)4557c478bd9Sstevel@tonic-gate _Unwind_Resume(struct _Unwind_Exception *exception_object)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	struct _Unwind_Context context;
4597c478bd9Sstevel@tonic-gate 	struct _Unwind_Context *ctx = &context;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	_Unw_capture_regs(ctx->current_regs);
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (exception_object->private_1)
4647c478bd9Sstevel@tonic-gate 		(void) _Unwind_ForcedUnwind_Body(exception_object,
4657c478bd9Sstevel@tonic-gate 		    (_Unwind_Stop_Fn)exception_object->private_1,
4667c478bd9Sstevel@tonic-gate 		    (void *)exception_object->private_2,
4677c478bd9Sstevel@tonic-gate 		    ctx, 1);
4687c478bd9Sstevel@tonic-gate 	else
4697c478bd9Sstevel@tonic-gate 		(void) _Unwind_RaiseException_Body(exception_object, ctx,
4707c478bd9Sstevel@tonic-gate 		    _UA_CLEANUP_PHASE);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate /* Calls destructor function for exception object */
4747c478bd9Sstevel@tonic-gate void
_Unwind_DeleteException(struct _Unwind_Exception * exception_object)4757c478bd9Sstevel@tonic-gate _Unwind_DeleteException(struct _Unwind_Exception *exception_object)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	if (exception_object->exception_cleanup != 0)
4787c478bd9Sstevel@tonic-gate 		(*(exception_object->exception_cleanup))(_URC_NO_REASON,
4797c478bd9Sstevel@tonic-gate 		    exception_object);
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate /*
4847c478bd9Sstevel@tonic-gate  * stack frame context accessors defined in ABI
4857c478bd9Sstevel@tonic-gate  * (despite all the dire text in the ABI these are reliable Get/Set routines)
4867c478bd9Sstevel@tonic-gate  * Note: RA is handled as GR value
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate uint64_t
_Unwind_GetGR(struct _Unwind_Context * context,int index)4897c478bd9Sstevel@tonic-gate _Unwind_GetGR(struct _Unwind_Context *context, int index)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	uint64_t res = 0;
4927c478bd9Sstevel@tonic-gate 	if (index <= EIR_R15) {
4937c478bd9Sstevel@tonic-gate 		res = context->current_regs[index];
4947c478bd9Sstevel@tonic-gate 	} else if (index == RET_ADD) {
4957c478bd9Sstevel@tonic-gate 		res = context->ra;
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 	return (res);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate void
_Unwind_SetGR(struct _Unwind_Context * context,int index,uint64_t new_value)502*1ba82a13SAndy Fiddaman _Unwind_SetGR(struct _Unwind_Context *context, int index, uint64_t new_value)
5037c478bd9Sstevel@tonic-gate {
5047c478bd9Sstevel@tonic-gate 	if (index <= EIR_R15) {
5057c478bd9Sstevel@tonic-gate 		context->current_regs[index] = new_value;
5067c478bd9Sstevel@tonic-gate 	} else if (index == RET_ADD) {
5077c478bd9Sstevel@tonic-gate 		context->ra = new_value;
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate uint64_t
_Unwind_GetIP(struct _Unwind_Context * context)5137c478bd9Sstevel@tonic-gate _Unwind_GetIP(struct _Unwind_Context *context)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	return (context->pc);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate void
_Unwind_SetIP(struct _Unwind_Context * context,uint64_t new_value)5197c478bd9Sstevel@tonic-gate _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value)
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	context->pc = new_value;
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate void *
_Unwind_GetLanguageSpecificData(struct _Unwind_Context * context)5267c478bd9Sstevel@tonic-gate _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context)
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate 	return (context->lsda);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate uint64_t
_Unwind_GetRegionStart(struct _Unwind_Context * context)5337c478bd9Sstevel@tonic-gate _Unwind_GetRegionStart(struct _Unwind_Context *context)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate 	return (context->func);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate uint64_t
_Unwind_GetCFA(struct _Unwind_Context * context)5397c478bd9Sstevel@tonic-gate _Unwind_GetCFA(struct _Unwind_Context *context)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	return (context->cfa);
5427c478bd9Sstevel@tonic-gate }
543