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