unwind.inc revision 169690
112657Skvn/* Exception handling and frame unwind runtime interface routines. -*- C -*- 212657Skvn Copyright (C) 2001, 2003 Free Software Foundation, Inc. 312657Skvn 412657Skvn This file is part of GCC. 512657Skvn 612657Skvn GCC is free software; you can redistribute it and/or modify it 712657Skvn under the terms of the GNU General Public License as published by 812657Skvn the Free Software Foundation; either version 2, or (at your option) 912657Skvn any later version. 1012657Skvn 1112657Skvn In addition to the permissions in the GNU General Public License, the 1212657Skvn Free Software Foundation gives you unlimited permission to link the 1312657Skvn compiled version of this file into combinations with other programs, 1412657Skvn and to distribute those combinations without any restriction coming 1512657Skvn from the use of this file. (The General Public License restrictions 1612657Skvn do apply in other respects; for example, they cover modification of 1712657Skvn the file, and distribution when not linked into a combined 1812657Skvn executable.) 1912657Skvn 2012657Skvn GCC is distributed in the hope that it will be useful, but WITHOUT 2112657Skvn ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 2212657Skvn or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 2312657Skvn License for more details. 2412657Skvn 2512657Skvn You should have received a copy of the GNU General Public License 2612657Skvn along with GCC; see the file COPYING. If not, write to the Free 2712657Skvn Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 2812657Skvn 02110-1301, USA. */ 2912657Skvn 3012657Skvn/* This is derived from the C++ ABI for IA-64. Where we diverge 3112657Skvn for cross-architecture compatibility are noted with "@@@". 3212657Skvn This file is included from unwind-dw2.c or unwind-ia64.c. */ 3312657Skvn 3412657Skvn/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. 3512657Skvn 3612657Skvn Unwind the stack calling the personality routine to find both the 3712657Skvn exception handler and intermediary cleanup code. We'll only locate 3812657Skvn the first such frame here. Cleanup code will call back into 3912657Skvn _Unwind_Resume and we'll continue Phase 2 there. */ 4012657Skvn 4112657Skvnstatic _Unwind_Reason_Code 4212657Skvn_Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, 4312657Skvn struct _Unwind_Context *context) 4412657Skvn{ 4512657Skvn _Unwind_Reason_Code code; 4612657Skvn 4712657Skvn while (1) 4812657Skvn { 4912657Skvn _Unwind_FrameState fs; 5012657Skvn int match_handler; 5112657Skvn 5212657Skvn code = uw_frame_state_for (context, &fs); 5312657Skvn 5412657Skvn /* Identify when we've reached the designated handler context. */ 5512657Skvn match_handler = (uw_identify_context (context) == exc->private_2 5612657Skvn ? _UA_HANDLER_FRAME : 0); 5712657Skvn 5812657Skvn if (code != _URC_NO_REASON) 5912657Skvn /* Some error encountered. Usually the unwinder doesn't 6012657Skvn diagnose these and merely crashes. */ 6112657Skvn return _URC_FATAL_PHASE2_ERROR; 6212657Skvn 6312657Skvn /* Unwind successful. Run the personality routine, if any. */ 6412657Skvn if (fs.personality) 6512657Skvn { 6612657Skvn code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, 6712657Skvn exc->exception_class, exc, context); 6812657Skvn if (code == _URC_INSTALL_CONTEXT) 6912657Skvn break; 7012657Skvn if (code != _URC_CONTINUE_UNWIND) 7112657Skvn return _URC_FATAL_PHASE2_ERROR; 7212657Skvn } 7312657Skvn 7412657Skvn /* Don't let us unwind past the handler context. */ 7512657Skvn gcc_assert (!match_handler); 7612657Skvn 7712657Skvn uw_update_context (context, &fs); 7812657Skvn } 7912657Skvn 8012657Skvn return code; 8112657Skvn} 8212657Skvn 8312657Skvn/* Raise an exception, passing along the given exception object. */ 8412657Skvn 8512657Skvn_Unwind_Reason_Code 8612657Skvn_Unwind_RaiseException(struct _Unwind_Exception *exc) 8712657Skvn{ 8812657Skvn struct _Unwind_Context this_context, cur_context; 8912657Skvn _Unwind_Reason_Code code; 9012657Skvn 9112657Skvn /* Set up this_context to describe the current stack frame. */ 9212657Skvn uw_init_context (&this_context); 9312657Skvn cur_context = this_context; 9412657Skvn 9512657Skvn /* Phase 1: Search. Unwind the stack, calling the personality routine 9612657Skvn with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */ 9712657Skvn while (1) 9812657Skvn { 9912657Skvn _Unwind_FrameState fs; 10012657Skvn 10112657Skvn /* Set up fs to describe the FDE for the caller of cur_context. The 10212657Skvn first time through the loop, that means __cxa_throw. */ 10312657Skvn code = uw_frame_state_for (&cur_context, &fs); 10412657Skvn 10512657Skvn if (code == _URC_END_OF_STACK) 10612657Skvn /* Hit end of stack with no handler found. */ 10712657Skvn return _URC_END_OF_STACK; 10812657Skvn 10912657Skvn if (code != _URC_NO_REASON) 11012657Skvn /* Some error encountered. Ususally the unwinder doesn't 11112657Skvn diagnose these and merely crashes. */ 11212657Skvn return _URC_FATAL_PHASE1_ERROR; 11312657Skvn 11412657Skvn /* Unwind successful. Run the personality routine, if any. */ 11512657Skvn if (fs.personality) 11612657Skvn { 11712657Skvn code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class, 11812657Skvn exc, &cur_context); 11912657Skvn if (code == _URC_HANDLER_FOUND) 12012657Skvn break; 12112657Skvn else if (code != _URC_CONTINUE_UNWIND) 12212657Skvn return _URC_FATAL_PHASE1_ERROR; 12312657Skvn } 12412657Skvn 12512657Skvn /* Update cur_context to describe the same frame as fs. */ 12612657Skvn uw_update_context (&cur_context, &fs); 12712968Siveresov } 12812657Skvn 12912657Skvn /* Indicate to _Unwind_Resume and associated subroutines that this 13012657Skvn is not a forced unwind. Further, note where we found a handler. */ 13112657Skvn exc->private_1 = 0; 13212657Skvn exc->private_2 = uw_identify_context (&cur_context); 13312657Skvn 13412657Skvn cur_context = this_context; 13512657Skvn code = _Unwind_RaiseException_Phase2 (exc, &cur_context); 13612657Skvn if (code != _URC_INSTALL_CONTEXT) 13712657Skvn return code; 13812657Skvn 13912657Skvn uw_install_context (&this_context, &cur_context); 14012657Skvn} 14112657Skvn 14212657Skvn 14312657Skvn/* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ 14412657Skvn 14512657Skvnstatic _Unwind_Reason_Code 14612657Skvn_Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, 14712657Skvn struct _Unwind_Context *context) 14812657Skvn{ 14912657Skvn _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; 15012657Skvn void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; 15112657Skvn _Unwind_Reason_Code code, stop_code; 15212657Skvn 15312657Skvn while (1) 15412657Skvn { 15512657Skvn _Unwind_FrameState fs; 15612657Skvn int action; 15712657Skvn 15812657Skvn /* Set up fs to describe the FDE for the caller of cur_context. */ 15912657Skvn code = uw_frame_state_for (context, &fs); 16012657Skvn if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) 16112657Skvn return _URC_FATAL_PHASE2_ERROR; 16212657Skvn 16312657Skvn /* Unwind successful. */ 16412657Skvn action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; 16512657Skvn if (code == _URC_END_OF_STACK) 16612657Skvn action |= _UA_END_OF_STACK; 16712657Skvn stop_code = (*stop) (1, action, exc->exception_class, exc, 16812657Skvn context, stop_argument); 16912657Skvn if (stop_code != _URC_NO_REASON) 17012657Skvn return _URC_FATAL_PHASE2_ERROR; 17112657Skvn 17212657Skvn /* Stop didn't want to do anything. Invoke the personality 17312657Skvn handler, if applicable, to run cleanups. */ 17412657Skvn if (code == _URC_END_OF_STACK) 17512657Skvn break; 17612657Skvn 17712657Skvn if (fs.personality) 17812657Skvn { 17912657Skvn code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, 18012657Skvn exc->exception_class, exc, context); 18112657Skvn if (code == _URC_INSTALL_CONTEXT) 18212657Skvn break; 18312657Skvn if (code != _URC_CONTINUE_UNWIND) 18412657Skvn return _URC_FATAL_PHASE2_ERROR; 18512657Skvn } 18612657Skvn 18712657Skvn /* Update cur_context to describe the same frame as fs, and discard 18812657Skvn the previous context if necessary. */ 18912657Skvn uw_advance_context (context, &fs); 19012657Skvn } 19112657Skvn 19212657Skvn return code; 19312657Skvn} 19412657Skvn 19512657Skvn 19612657Skvn/* Raise an exception for forced unwinding. */ 19712657Skvn 19812657Skvn_Unwind_Reason_Code 19912657Skvn_Unwind_ForcedUnwind (struct _Unwind_Exception *exc, 20012657Skvn _Unwind_Stop_Fn stop, void * stop_argument) 20112657Skvn{ 20212657Skvn struct _Unwind_Context this_context, cur_context; 20312657Skvn _Unwind_Reason_Code code; 20412657Skvn 20512657Skvn uw_init_context (&this_context); 20612657Skvn cur_context = this_context; 20712657Skvn 20812657Skvn exc->private_1 = (_Unwind_Ptr) stop; 20912657Skvn exc->private_2 = (_Unwind_Ptr) stop_argument; 21012657Skvn 21112657Skvn code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); 21212657Skvn if (code != _URC_INSTALL_CONTEXT) 21312657Skvn return code; 21412657Skvn 21512657Skvn uw_install_context (&this_context, &cur_context); 21612657Skvn} 21712657Skvn 21812657Skvn 21912657Skvn/* Resume propagation of an existing exception. This is used after 22012657Skvn e.g. executing cleanup code, and not to implement rethrowing. */ 22112657Skvn 22212657Skvnvoid 22312657Skvn_Unwind_Resume (struct _Unwind_Exception *exc) 22412657Skvn{ 22512657Skvn struct _Unwind_Context this_context, cur_context; 22612657Skvn _Unwind_Reason_Code code; 22712657Skvn 22812657Skvn uw_init_context (&this_context); 22912657Skvn cur_context = this_context; 23012657Skvn 23112657Skvn /* Choose between continuing to process _Unwind_RaiseException 23212657Skvn or _Unwind_ForcedUnwind. */ 23312657Skvn if (exc->private_1 == 0) 23412657Skvn code = _Unwind_RaiseException_Phase2 (exc, &cur_context); 23512657Skvn else 23612657Skvn code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); 23712657Skvn 23812657Skvn gcc_assert (code == _URC_INSTALL_CONTEXT); 23912657Skvn 24012657Skvn uw_install_context (&this_context, &cur_context); 24112657Skvn} 24212657Skvn 24312657Skvn 24412657Skvn/* Resume propagation of an FORCE_UNWIND exception, or to rethrow 24512657Skvn a normal exception that was handled. */ 24612657Skvn 24712657Skvn_Unwind_Reason_Code 24812657Skvn_Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) 24912657Skvn{ 25012657Skvn struct _Unwind_Context this_context, cur_context; 25112657Skvn _Unwind_Reason_Code code; 25212657Skvn 25312657Skvn /* Choose between continuing to process _Unwind_RaiseException 25412657Skvn or _Unwind_ForcedUnwind. */ 25512657Skvn if (exc->private_1 == 0) 25612657Skvn return _Unwind_RaiseException (exc); 25712657Skvn 25812657Skvn uw_init_context (&this_context); 25912657Skvn cur_context = this_context; 26012657Skvn 26112657Skvn code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); 26212657Skvn 26312657Skvn gcc_assert (code == _URC_INSTALL_CONTEXT); 26412657Skvn 26512657Skvn uw_install_context (&this_context, &cur_context); 26612657Skvn} 26712657Skvn 26812657Skvn 26912657Skvn/* A convenience function that calls the exception_cleanup field. */ 27012657Skvn 27112657Skvnvoid 27212657Skvn_Unwind_DeleteException (struct _Unwind_Exception *exc) 27312657Skvn{ 27412657Skvn if (exc->exception_cleanup) 27512657Skvn (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); 27612657Skvn} 27712657Skvn 27812657Skvn 27912657Skvn/* Perform stack backtrace through unwind data. */ 28012657Skvn 28112657Skvn_Unwind_Reason_Code 28212657Skvn_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) 28312657Skvn{ 28412657Skvn struct _Unwind_Context context; 285 _Unwind_Reason_Code code; 286 287 uw_init_context (&context); 288 289 while (1) 290 { 291 _Unwind_FrameState fs; 292 293 /* Set up fs to describe the FDE for the caller of context. */ 294 code = uw_frame_state_for (&context, &fs); 295 if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) 296 return _URC_FATAL_PHASE1_ERROR; 297 298 /* Call trace function. */ 299 if ((*trace) (&context, trace_argument) != _URC_NO_REASON) 300 return _URC_FATAL_PHASE1_ERROR; 301 302 /* We're done at end of stack. */ 303 if (code == _URC_END_OF_STACK) 304 break; 305 306 /* Update context to describe the same frame as fs. */ 307 uw_update_context (&context, &fs); 308 } 309 310 return code; 311} 312