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