/* * 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 #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 */