unwind.inc revision 96489
1/* Exception handling and frame unwind runtime interface routines. -*- C -*-
2   Copyright (C) 2001 Free Software Foundation, Inc.
3
4   This file is part of GCC.
5
6   GCC is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   GCC is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14   License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with GCC; see the file COPYING.  If not, write to the Free
18   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.  */
20
21/* This is derived from the C++ ABI for IA-64.  Where we diverge
22   for cross-architecture compatibility are noted with "@@@".
23   This file is included from unwind-dw2.c or unwind-ia64.c.  */
24
25/* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume.
26
27   Unwind the stack calling the personality routine to find both the
28   exception handler and intermediary cleanup code.  We'll only locate
29   the first such frame here.  Cleanup code will call back into
30   _Unwind_Resume and we'll continue Phase 2 there.  */
31
32static _Unwind_Reason_Code
33_Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc,
34			      struct _Unwind_Context *context)
35{
36  _Unwind_Reason_Code code;
37
38  while (1)
39    {
40      _Unwind_FrameState fs;
41      int match_handler;
42
43      code = uw_frame_state_for (context, &fs);
44
45      /* Identify when we've reached the designated handler context.  */
46      match_handler = (uw_identify_context (context) == exc->private_2
47		       ? _UA_HANDLER_FRAME : 0);
48
49      if (code != _URC_NO_REASON)
50	/* Some error encountered.  Usually the unwinder doesn't
51	   diagnose these and merely crashes.  */
52	return _URC_FATAL_PHASE2_ERROR;
53
54      /* Unwind successful.  Run the personality routine, if any.  */
55      if (fs.personality)
56	{
57	  code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler,
58				    exc->exception_class, exc, context);
59	  if (code == _URC_INSTALL_CONTEXT)
60	    break;
61	  if (code != _URC_CONTINUE_UNWIND)
62	    return _URC_FATAL_PHASE2_ERROR;
63	}
64
65      /* Don't let us unwind past the handler context.  */
66      if (match_handler)
67	abort ();
68
69      uw_update_context (context, &fs);
70    }
71
72  return code;
73}
74
75
76/* Raise an exception, passing along the given exception object.  */
77
78_Unwind_Reason_Code
79_Unwind_RaiseException(struct _Unwind_Exception *exc)
80{
81  struct _Unwind_Context this_context, cur_context;
82  _Unwind_Reason_Code code;
83
84  uw_init_context (&this_context);
85  cur_context = this_context;
86
87  /* Phase 1: Search.  Unwind the stack, calling the personality routine
88     with the _UA_SEARCH_PHASE flag set.  Do not modify the stack yet.  */
89  while (1)
90    {
91      _Unwind_FrameState fs;
92
93      code = uw_frame_state_for (&cur_context, &fs);
94
95      if (code == _URC_END_OF_STACK)
96	/* Hit end of stack with no handler found.  */
97	return _URC_END_OF_STACK;
98
99      if (code != _URC_NO_REASON)
100	/* Some error encountered.  Ususally the unwinder doesn't
101	   diagnose these and merely crashes.  */
102	return _URC_FATAL_PHASE1_ERROR;
103
104      /* Unwind successful.  Run the personality routine, if any.  */
105      if (fs.personality)
106	{
107	  code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class,
108				    exc, &cur_context);
109	  if (code == _URC_HANDLER_FOUND)
110	    break;
111	  else if (code != _URC_CONTINUE_UNWIND)
112	    return _URC_FATAL_PHASE1_ERROR;
113	}
114
115      uw_update_context (&cur_context, &fs);
116    }
117
118  /* Indicate to _Unwind_Resume and associated subroutines that this
119     is not a forced unwind.  Further, note where we found a handler.  */
120  exc->private_1 = 0;
121  exc->private_2 = uw_identify_context (&cur_context);
122
123  cur_context = this_context;
124  code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
125  if (code != _URC_INSTALL_CONTEXT)
126    return code;
127
128  uw_install_context (&this_context, &cur_context);
129}
130
131
132/* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume.  */
133
134static _Unwind_Reason_Code
135_Unwind_ForcedUnwind_Phase2(struct _Unwind_Exception *exc,
136			    struct _Unwind_Context *context)
137{
138  _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1;
139  void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2;
140  _Unwind_Reason_Code code, stop_code;
141
142  while (1)
143    {
144      _Unwind_FrameState fs;
145      int action;
146
147      code = uw_frame_state_for (context, &fs);
148      if (code != _URC_NO_REASON && code != _URC_END_OF_STACK)
149	return _URC_FATAL_PHASE2_ERROR;
150
151      /* Unwind successful.  */
152      action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE;
153      if (code == _URC_END_OF_STACK)
154	action |= _UA_END_OF_STACK;
155      stop_code = (*stop) (1, action, exc->exception_class, exc,
156			   context, stop_argument);
157      if (stop_code != _URC_NO_REASON)
158	return _URC_FATAL_PHASE2_ERROR;
159
160      /* Stop didn't want to do anything.  Invoke the personality
161	 handler, if applicable, to run cleanups.  */
162      if (code == _URC_END_OF_STACK)
163	break;
164
165      if (fs.personality)
166	{
167	  code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE,
168				    exc->exception_class, exc, context);
169	  if (code == _URC_INSTALL_CONTEXT)
170	    break;
171	  if (code != _URC_CONTINUE_UNWIND)
172	    return _URC_FATAL_PHASE2_ERROR;
173	}
174
175      uw_update_context (context, &fs);
176    }
177
178  return code;
179}
180
181
182/* Raise an exception for forced unwinding.  */
183
184_Unwind_Reason_Code
185_Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
186		      _Unwind_Stop_Fn stop, void * stop_argument)
187{
188  struct _Unwind_Context this_context, cur_context;
189  _Unwind_Reason_Code code;
190
191  uw_init_context (&this_context);
192  cur_context = this_context;
193
194  exc->private_1 = (_Unwind_Ptr) stop;
195  exc->private_2 = (_Unwind_Ptr) stop_argument;
196
197  code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
198  if (code != _URC_INSTALL_CONTEXT)
199    return code;
200
201  uw_install_context (&this_context, &cur_context);
202}
203
204
205/* Resume propagation of an existing exception.  This is used after
206   e.g. executing cleanup code, and not to implement rethrowing.  */
207
208void
209_Unwind_Resume (struct _Unwind_Exception *exc)
210{
211  struct _Unwind_Context this_context, cur_context;
212  _Unwind_Reason_Code code;
213
214  uw_init_context (&this_context);
215  cur_context = this_context;
216
217  /* Choose between continuing to process _Unwind_RaiseException
218     or _Unwind_ForcedUnwind.  */
219  if (exc->private_1 == 0)
220    code = _Unwind_RaiseException_Phase2 (exc, &cur_context);
221  else
222    code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context);
223
224  if (code != _URC_INSTALL_CONTEXT)
225    abort ();
226
227  uw_install_context (&this_context, &cur_context);
228}
229
230/* A convenience function that calls the exception_cleanup field.  */
231
232void
233_Unwind_DeleteException (struct _Unwind_Exception *exc)
234{
235  (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
236}
237