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