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