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