| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License, Version 1.0 only |
| * (the "License"). You may not use this file except in compliance |
| * with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| */ |
| /* |
| * Copyright 2004 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| /* |
| * Public interfaces for AMD64 Unwind routines |
| */ |
| |
| #ifndef _STACK_UNWIND_H |
| #define _STACK_UNWIND_H |
| |
| #include <sys/types.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #if defined(__amd64) /* none of this is valid except for AMD64 */ |
| |
| typedef enum { |
| _URC_NO_REASON = 0, |
| _URC_FOREIGN_EXCEPTION_CAUGHT = 1, |
| _URC_FATAL_PHASE2_ERROR = 2, |
| _URC_FATAL_PHASE1_ERROR = 3, |
| _URC_NORMAL_STOP = 4, |
| _URC_END_OF_STACK = 5, |
| _URC_HANDLER_FOUND = 6, |
| _URC_INSTALL_CONTEXT = 7, |
| _URC_CONTINUE_UNWIND = 8 |
| } _Unwind_Reason_Code; |
| |
| typedef int _Unwind_Action; |
| extern const _Unwind_Action _UA_SEARCH_PHASE; |
| extern const _Unwind_Action _UA_CLEANUP_PHASE; |
| extern const _Unwind_Action _UA_HANDLER_FRAME; |
| extern const _Unwind_Action _UA_FORCE_UNWIND; |
| |
| struct _Unwind_Exception; |
| struct _Unwind_Context; |
| |
| |
| /* |
| * Signature of language specific call back for deleting exception object |
| */ |
| typedef void (*_Unwind_Exception_Cleanup_Fn)( |
| _Unwind_Reason_Code reason, |
| struct _Unwind_Exception *exc); |
| |
| /* |
| * Header preceding language specific exception object |
| * For Sun C++ these fields are the beginning of the |
| * language specific structure. |
| */ |
| struct _Unwind_Exception { |
| uint64_t exception_class; |
| _Unwind_Exception_Cleanup_Fn exception_cleanup; |
| uint64_t private_1; |
| uint64_t private_2; |
| }; |
| |
| /* |
| * Signature for language specific routine - address is in eh_frame CIE. |
| * During phase one it predicts whether exception would be caught at this |
| * frame and during phase two selects a handler as predicted. An action |
| * of _UA_FORCE_UNWIND will prevent any catch block from being selected. |
| * |
| * The personality function is the only call back used when |
| * _Unwind_RaiseException() is called. |
| */ |
| typedef _Unwind_Reason_Code (*_Unwind_Personality_Fn)( |
| int version, |
| _Unwind_Action actions, |
| uint64_t exceptionClass, |
| struct _Unwind_Exception *exceptionObject, |
| struct _Unwind_Context *context); |
| |
| /* |
| * Signature of callback function that is used when _Unwind_ForcedUnwind() |
| * is called. It is called at every step of walkback and that can control |
| * the execution of the personality routine at each frame. |
| */ |
| typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)( |
| int version, |
| _Unwind_Action actions, |
| uint64_t exceptionClass, |
| struct _Unwind_Exception *exceptionObject, |
| struct _Unwind_Context *context, |
| void *stop_parameter); |
| |
| /* |
| * Here begins the external functional interface |
| */ |
| |
| /* |
| * Used to implement C++ throw - starts walkback with caller's caller. |
| * The routine in the middle must use %rbp as a frame pointer |
| */ |
| _Unwind_Reason_Code _Unwind_RaiseException( |
| struct _Unwind_Exception *exception_object); |
| |
| /* |
| * Used (with different stop functions) for POSIX thread cancellation |
| * and stack walking - starts walkback with caller's caller. |
| * |
| * Note: must be called by a routine which has a real FP and doesn't use |
| * callee saves registers. |
| */ |
| _Unwind_Reason_Code _Unwind_ForcedUnwind( |
| struct _Unwind_Exception *exception_object, |
| _Unwind_Stop_Fn stop, |
| void *stop_parameter); |
| |
| /* |
| * Used to resume unwinding at end of cleanup (not catch) code |
| * Assumes that caller is language specific cleanup code and |
| * pops the stack one level before resuming walk. |
| */ |
| void _Unwind_Resume(struct _Unwind_Exception *exception_object); |
| |
| /* |
| * Calls destructor function for exception object |
| */ |
| void _Unwind_DeleteException(struct _Unwind_Exception *exception_object); |
| /* |
| * { |
| * (*(exception_object->exception_cleanup))(_URC_NO_REASON, |
| * exception_object); |
| * } |
| */ |
| |
| |
| #if 0 |
| |
| extern "C" _Unwind_Reason_Code |
| __example_stop_fn(int version, int actions, uint64_t exclass, |
| struct _Unwind_Exception *exception_object, |
| struct _Unwind_Context *ctx, void *_Sa) |
| { |
| _Unwind_Reason_Code res; |
| |
| uint64_t fp = _Unwind_GetCFA(ctx); |
| |
| if (fp == 0 || _Unwind_GetGR(ctx, RET_ADD) == 0) { |
| if (no_return) |
| die; |
| res = _URC_END_OF_STACK; |
| } else { |
| /* |
| * Your logic here: |
| * res = ........ |
| */ |
| } |
| switch (res) { |
| case _URC_NO_REASON: |
| /* |
| * framework will call personality routine for current context |
| * then then move one frame back the stack and call here with |
| * updated context. POSIX thread cancellation uses this pattern. |
| * |
| * If this path is taken the exception object passed must have |
| * been constructed by the same language system supplying the |
| * personality routines. i.e. foreign exceptions are not |
| * implemented. |
| * |
| * The Sun Microsystems C++ runtime contains the routine |
| * |
| * _ex_unwind(_Unwind_Stop_fn sfunc, void *sfunc_arg) |
| * |
| * which is a wrapper around _Unwind_ForcedUnwind that |
| * sets up a C++ exception object. |
| * |
| * Once this path is taken, the stack frame from which |
| * _Unwind_ForcedUnwind was called is not guaranteed to |
| * still exist. Thus the return codes listed below which |
| * result in that call returning are rendered bogus. |
| * |
| * A thread reaching the end of the stack during cancellation |
| * must die instead of returning _URC_END_OF_STACK. |
| */ |
| break; |
| case _URC_CONTINUE_UNWIND: |
| /* |
| * framework will move one frame back the stack and |
| * call here with updated context |
| * |
| * The exception record supplied to _Unwind_ForcedUnwind |
| * need only contain the header and may be stack allocated |
| * if this function will never allow the personality |
| * function to run (as in a trace generator). |
| */ |
| break; |
| case _URC_INSTALL_CONTEXT: |
| /* |
| * framework will resume execution of user code at location |
| * specified by (altered) context |
| */ |
| _Unwind_Delete_Exception(res, exception_object); |
| break; |
| case _URC_NORMAL_STOP: |
| /* |
| * call to _Unwind_ForcedUnwind will return _URC_NORMAL_STOP |
| */ |
| _Unwind_Delete_Exception(res, exception_object); |
| break; |
| case _URC_END_OF_STACK: |
| /* |
| * call to _Unwind_ForcedUnwind will return _URC_END_OF_STACK |
| */ |
| _Unwind_Delete_Exception(res, exception_object); |
| break; |
| case _URC_FOREIGN_EXCEPTION_CAUGHT: |
| case _URC_FATAL_PHASE2_ERROR: |
| case _URC_FATAL_PHASE1_ERROR: |
| case _URC_HANDLER_FOUND: |
| /* |
| * call to _Unwind_ForcedUnwind will return |
| * _URC_FATAL_PHASE2_ERROR |
| */ |
| _Unwind_Delete_Exception(res, exception_object); |
| break; |
| } |
| return (res); |
| } |
| |
| #endif |
| |
| /* |
| * Stack frame context accessors defined in ABI |
| * (despite all the dire text in the ABI these are reliable Get/Set routines) |
| * Note: RA is handled as a GR value |
| */ |
| |
| /* |
| * Valid Index values for _Unwind_GetGR |
| */ |
| #define GPR_RBX 3 /* callee saves */ |
| #define FP_RBP 6 /* callee saves (optional frame pointer) */ |
| #define SP_RSP 7 /* callee saves */ |
| #define EIR_R12 12 /* callee saves */ |
| #define EIR_R13 13 /* callee saves */ |
| #define EIR_R14 14 /* callee saves */ |
| #define EIR_R15 15 /* callee saves */ |
| #define RET_ADD 16 /* virtual register - really caller's PC */ |
| |
| /* |
| * Valid Index values for _Unwind_SetGR |
| */ |
| #define GPR_RDX 1 /* landing pad parameter */ |
| #define GPR_RCX 2 /* landing pad parameter */ |
| #define GPR_RSI 4 /* landing pad parameter */ |
| #define GPR_RDI 5 /* landing pad parameter */ |
| |
| uint64_t _Unwind_GetGR(struct _Unwind_Context *context, int index); |
| |
| void _Unwind_SetGR(struct _Unwind_Context *context, int index, |
| uint64_t new_value); |
| |
| uint64_t _Unwind_GetCFA(struct _Unwind_Context *context); |
| |
| uint64_t _Unwind_GetIP(struct _Unwind_Context *context); |
| |
| void _Unwind_SetIP(struct _Unwind_Context *context, uint64_t new_value); |
| |
| void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); |
| |
| uint64_t _Unwind_GetRegionStart(struct _Unwind_Context *context); |
| |
| #endif /* __amd64 */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* _STACK_UNWIND_H */ |