190075Sobrien/* Exception handling and frame unwind runtime interface routines. -*- C -*- 2132718Skan Copyright (C) 2001, 2003 Free Software Foundation, Inc. 390075Sobrien 490075Sobrien This file is part of GCC. 590075Sobrien 690075Sobrien GCC is free software; you can redistribute it and/or modify it 790075Sobrien under the terms of the GNU General Public License as published by 890075Sobrien the Free Software Foundation; either version 2, or (at your option) 990075Sobrien any later version. 1090075Sobrien 11132718Skan In addition to the permissions in the GNU General Public License, the 12132718Skan Free Software Foundation gives you unlimited permission to link the 13132718Skan compiled version of this file into combinations with other programs, 14132718Skan and to distribute those combinations without any restriction coming 15132718Skan from the use of this file. (The General Public License restrictions 16132718Skan do apply in other respects; for example, they cover modification of 17132718Skan the file, and distribution when not linked into a combined 18132718Skan executable.) 19132718Skan 2090075Sobrien GCC is distributed in the hope that it will be useful, but WITHOUT 2190075Sobrien ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 2290075Sobrien or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 2390075Sobrien License for more details. 2490075Sobrien 2590075Sobrien You should have received a copy of the GNU General Public License 2690075Sobrien along with GCC; see the file COPYING. If not, write to the Free 27169689Skan Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 28169689Skan 02110-1301, USA. */ 2990075Sobrien 3090075Sobrien/* This is derived from the C++ ABI for IA-64. Where we diverge 3190075Sobrien for cross-architecture compatibility are noted with "@@@". 3290075Sobrien This file is included from unwind-dw2.c or unwind-ia64.c. */ 3390075Sobrien 3490075Sobrien/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. 3590075Sobrien 3690075Sobrien Unwind the stack calling the personality routine to find both the 3790075Sobrien exception handler and intermediary cleanup code. We'll only locate 3890075Sobrien the first such frame here. Cleanup code will call back into 3990075Sobrien _Unwind_Resume and we'll continue Phase 2 there. */ 4090075Sobrien 4190075Sobrienstatic _Unwind_Reason_Code 4290075Sobrien_Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, 4390075Sobrien struct _Unwind_Context *context) 4490075Sobrien{ 4590075Sobrien _Unwind_Reason_Code code; 4690075Sobrien 4790075Sobrien while (1) 4890075Sobrien { 4990075Sobrien _Unwind_FrameState fs; 5090075Sobrien int match_handler; 5190075Sobrien 5290075Sobrien code = uw_frame_state_for (context, &fs); 5390075Sobrien 5490075Sobrien /* Identify when we've reached the designated handler context. */ 5590075Sobrien match_handler = (uw_identify_context (context) == exc->private_2 5690075Sobrien ? _UA_HANDLER_FRAME : 0); 5790075Sobrien 5890075Sobrien if (code != _URC_NO_REASON) 5990075Sobrien /* Some error encountered. Usually the unwinder doesn't 6090075Sobrien diagnose these and merely crashes. */ 6190075Sobrien return _URC_FATAL_PHASE2_ERROR; 6290075Sobrien 6390075Sobrien /* Unwind successful. Run the personality routine, if any. */ 6490075Sobrien if (fs.personality) 6590075Sobrien { 6690075Sobrien code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, 6790075Sobrien exc->exception_class, exc, context); 6890075Sobrien if (code == _URC_INSTALL_CONTEXT) 6990075Sobrien break; 7090075Sobrien if (code != _URC_CONTINUE_UNWIND) 7190075Sobrien return _URC_FATAL_PHASE2_ERROR; 7290075Sobrien } 7390075Sobrien 7490075Sobrien /* Don't let us unwind past the handler context. */ 75169689Skan gcc_assert (!match_handler); 7690075Sobrien 7790075Sobrien uw_update_context (context, &fs); 7890075Sobrien } 7990075Sobrien 8090075Sobrien return code; 8190075Sobrien} 8290075Sobrien 8390075Sobrien/* Raise an exception, passing along the given exception object. */ 8490075Sobrien 8590075Sobrien_Unwind_Reason_Code 8690075Sobrien_Unwind_RaiseException(struct _Unwind_Exception *exc) 8790075Sobrien{ 8890075Sobrien struct _Unwind_Context this_context, cur_context; 8990075Sobrien _Unwind_Reason_Code code; 9090075Sobrien 91117395Skan /* Set up this_context to describe the current stack frame. */ 9290075Sobrien uw_init_context (&this_context); 9390075Sobrien cur_context = this_context; 9490075Sobrien 9590075Sobrien /* Phase 1: Search. Unwind the stack, calling the personality routine 9690075Sobrien with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */ 9790075Sobrien while (1) 9890075Sobrien { 9990075Sobrien _Unwind_FrameState fs; 10090075Sobrien 101117395Skan /* Set up fs to describe the FDE for the caller of cur_context. The 102117395Skan first time through the loop, that means __cxa_throw. */ 10390075Sobrien code = uw_frame_state_for (&cur_context, &fs); 10490075Sobrien 10590075Sobrien if (code == _URC_END_OF_STACK) 10690075Sobrien /* Hit end of stack with no handler found. */ 10790075Sobrien return _URC_END_OF_STACK; 10890075Sobrien 10990075Sobrien if (code != _URC_NO_REASON) 11090075Sobrien /* Some error encountered. Ususally the unwinder doesn't 11190075Sobrien diagnose these and merely crashes. */ 11290075Sobrien return _URC_FATAL_PHASE1_ERROR; 11390075Sobrien 11490075Sobrien /* Unwind successful. Run the personality routine, if any. */ 11590075Sobrien if (fs.personality) 11690075Sobrien { 11790075Sobrien code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class, 11890075Sobrien exc, &cur_context); 11990075Sobrien if (code == _URC_HANDLER_FOUND) 12090075Sobrien break; 12190075Sobrien else if (code != _URC_CONTINUE_UNWIND) 12290075Sobrien return _URC_FATAL_PHASE1_ERROR; 12390075Sobrien } 12490075Sobrien 125117395Skan /* Update cur_context to describe the same frame as fs. */ 12690075Sobrien uw_update_context (&cur_context, &fs); 12790075Sobrien } 12890075Sobrien 12990075Sobrien /* Indicate to _Unwind_Resume and associated subroutines that this 13090075Sobrien is not a forced unwind. Further, note where we found a handler. */ 13190075Sobrien exc->private_1 = 0; 13290075Sobrien exc->private_2 = uw_identify_context (&cur_context); 13390075Sobrien 13490075Sobrien cur_context = this_context; 13590075Sobrien code = _Unwind_RaiseException_Phase2 (exc, &cur_context); 13690075Sobrien if (code != _URC_INSTALL_CONTEXT) 13790075Sobrien return code; 13890075Sobrien 13990075Sobrien uw_install_context (&this_context, &cur_context); 14090075Sobrien} 14190075Sobrien 14290075Sobrien 14390075Sobrien/* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ 14490075Sobrien 14590075Sobrienstatic _Unwind_Reason_Code 146169689Skan_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, 147169689Skan struct _Unwind_Context *context) 14890075Sobrien{ 14990075Sobrien _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; 15090075Sobrien void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; 15190075Sobrien _Unwind_Reason_Code code, stop_code; 15290075Sobrien 15390075Sobrien while (1) 15490075Sobrien { 15590075Sobrien _Unwind_FrameState fs; 15690075Sobrien int action; 15790075Sobrien 158117395Skan /* Set up fs to describe the FDE for the caller of cur_context. */ 15990075Sobrien code = uw_frame_state_for (context, &fs); 16090075Sobrien if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) 16190075Sobrien return _URC_FATAL_PHASE2_ERROR; 16290075Sobrien 16390075Sobrien /* Unwind successful. */ 16490075Sobrien action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; 16590075Sobrien if (code == _URC_END_OF_STACK) 16690075Sobrien action |= _UA_END_OF_STACK; 16790075Sobrien stop_code = (*stop) (1, action, exc->exception_class, exc, 16890075Sobrien context, stop_argument); 16990075Sobrien if (stop_code != _URC_NO_REASON) 17090075Sobrien return _URC_FATAL_PHASE2_ERROR; 17190075Sobrien 17290075Sobrien /* Stop didn't want to do anything. Invoke the personality 17390075Sobrien handler, if applicable, to run cleanups. */ 17490075Sobrien if (code == _URC_END_OF_STACK) 17590075Sobrien break; 17690075Sobrien 17790075Sobrien if (fs.personality) 17890075Sobrien { 17990075Sobrien code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, 18090075Sobrien exc->exception_class, exc, context); 18190075Sobrien if (code == _URC_INSTALL_CONTEXT) 18290075Sobrien break; 18390075Sobrien if (code != _URC_CONTINUE_UNWIND) 18490075Sobrien return _URC_FATAL_PHASE2_ERROR; 18590075Sobrien } 18690075Sobrien 187169689Skan /* Update cur_context to describe the same frame as fs, and discard 188169689Skan the previous context if necessary. */ 189169689Skan uw_advance_context (context, &fs); 19090075Sobrien } 19190075Sobrien 19290075Sobrien return code; 19390075Sobrien} 19490075Sobrien 19590075Sobrien 19690075Sobrien/* Raise an exception for forced unwinding. */ 19790075Sobrien 19890075Sobrien_Unwind_Reason_Code 19990075Sobrien_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, 20090075Sobrien _Unwind_Stop_Fn stop, void * stop_argument) 20190075Sobrien{ 20290075Sobrien struct _Unwind_Context this_context, cur_context; 20390075Sobrien _Unwind_Reason_Code code; 20490075Sobrien 20590075Sobrien uw_init_context (&this_context); 20690075Sobrien cur_context = this_context; 20790075Sobrien 20890075Sobrien exc->private_1 = (_Unwind_Ptr) stop; 20990075Sobrien exc->private_2 = (_Unwind_Ptr) stop_argument; 21090075Sobrien 21190075Sobrien code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); 21290075Sobrien if (code != _URC_INSTALL_CONTEXT) 21390075Sobrien return code; 21490075Sobrien 21590075Sobrien uw_install_context (&this_context, &cur_context); 21690075Sobrien} 21790075Sobrien 21890075Sobrien 21990075Sobrien/* Resume propagation of an existing exception. This is used after 22090075Sobrien e.g. executing cleanup code, and not to implement rethrowing. */ 22190075Sobrien 22290075Sobrienvoid 22390075Sobrien_Unwind_Resume (struct _Unwind_Exception *exc) 22490075Sobrien{ 22590075Sobrien struct _Unwind_Context this_context, cur_context; 22690075Sobrien _Unwind_Reason_Code code; 22790075Sobrien 22890075Sobrien uw_init_context (&this_context); 22990075Sobrien cur_context = this_context; 23090075Sobrien 23190075Sobrien /* Choose between continuing to process _Unwind_RaiseException 23290075Sobrien or _Unwind_ForcedUnwind. */ 23390075Sobrien if (exc->private_1 == 0) 23490075Sobrien code = _Unwind_RaiseException_Phase2 (exc, &cur_context); 23590075Sobrien else 23690075Sobrien code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); 23790075Sobrien 238169689Skan gcc_assert (code == _URC_INSTALL_CONTEXT); 23990075Sobrien 24090075Sobrien uw_install_context (&this_context, &cur_context); 24190075Sobrien} 24290075Sobrien 243117395Skan 244117395Skan/* Resume propagation of an FORCE_UNWIND exception, or to rethrow 245117395Skan a normal exception that was handled. */ 246117395Skan 247117395Skan_Unwind_Reason_Code 248117395Skan_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) 249117395Skan{ 250117395Skan struct _Unwind_Context this_context, cur_context; 251117395Skan _Unwind_Reason_Code code; 252117395Skan 253117395Skan /* Choose between continuing to process _Unwind_RaiseException 254117395Skan or _Unwind_ForcedUnwind. */ 255117395Skan if (exc->private_1 == 0) 256117395Skan return _Unwind_RaiseException (exc); 257117395Skan 258117395Skan uw_init_context (&this_context); 259117395Skan cur_context = this_context; 260117395Skan 261117395Skan code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); 262117395Skan 263169689Skan gcc_assert (code == _URC_INSTALL_CONTEXT); 264117395Skan 265117395Skan uw_install_context (&this_context, &cur_context); 266117395Skan} 267117395Skan 268117395Skan 26990075Sobrien/* A convenience function that calls the exception_cleanup field. */ 27090075Sobrien 27190075Sobrienvoid 27290075Sobrien_Unwind_DeleteException (struct _Unwind_Exception *exc) 27390075Sobrien{ 274117395Skan if (exc->exception_cleanup) 275117395Skan (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); 27690075Sobrien} 277117395Skan 278117395Skan 279117395Skan/* Perform stack backtrace through unwind data. */ 280117395Skan 281117395Skan_Unwind_Reason_Code 282117395Skan_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) 283117395Skan{ 284117395Skan struct _Unwind_Context context; 285117395Skan _Unwind_Reason_Code code; 286117395Skan 287117395Skan uw_init_context (&context); 288117395Skan 289117395Skan while (1) 290117395Skan { 291117395Skan _Unwind_FrameState fs; 292117395Skan 293117395Skan /* Set up fs to describe the FDE for the caller of context. */ 294117395Skan code = uw_frame_state_for (&context, &fs); 295117395Skan if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) 296117395Skan return _URC_FATAL_PHASE1_ERROR; 297117395Skan 298117395Skan /* Call trace function. */ 299117395Skan if ((*trace) (&context, trace_argument) != _URC_NO_REASON) 300117395Skan return _URC_FATAL_PHASE1_ERROR; 301117395Skan 302117395Skan /* We're done at end of stack. */ 303117395Skan if (code == _URC_END_OF_STACK) 304117395Skan break; 305117395Skan 306117395Skan /* Update context to describe the same frame as fs. */ 307117395Skan uw_update_context (&context, &fs); 308117395Skan } 309117395Skan 310117395Skan return code; 311117395Skan} 312