PR debug/47620
[official-gcc.git] / libgo / runtime / go-unwind.c
blobc0fc59cef84f889c0cbda2c28fca36701f7b68c6
1 /* go-unwind.c -- unwind the stack for panic/recover.
3 Copyright 2010 The Go Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file. */
7 #include "config.h"
9 #include <stdlib.h>
10 #include <unistd.h>
12 #include "unwind.h"
13 #define NO_SIZE_OF_ENCODED_VALUE
14 #include "unwind-pe.h"
16 #include "go-alloc.h"
17 #include "go-defer.h"
18 #include "go-panic.h"
20 /* The code for a Go exception. */
22 #ifdef __ARM_EABI_UNWINDER__
23 static const _Unwind_Exception_Class __go_exception_class =
24 { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
25 #else
26 static const _Unwind_Exception_Class __go_exception_class =
27 ((((((((_Unwind_Exception_Class) 'G'
28 << 8 | (_Unwind_Exception_Class) 'N')
29 << 8 | (_Unwind_Exception_Class) 'U')
30 << 8 | (_Unwind_Exception_Class) 'C')
31 << 8 | (_Unwind_Exception_Class) 'G')
32 << 8 | (_Unwind_Exception_Class) 'O')
33 << 8 | (_Unwind_Exception_Class) '\0')
34 << 8 | (_Unwind_Exception_Class) '\0');
35 #endif
38 /* This function is called by exception handlers used when unwinding
39 the stack after a recovered panic. The exception handler looks
40 like this:
41 __go_check_defer (frame);
42 return;
43 If we have not yet reached the frame we are looking for, we
44 continue unwinding. */
46 void
47 __go_check_defer (void *frame)
49 struct _Unwind_Exception *hdr;
51 if (__go_panic_defer == NULL)
53 /* Some other language has thrown an exception. We know there
54 are no defer handlers, so there is nothing to do. */
56 else if (__go_panic_defer->__is_foreign)
58 struct __go_panic_stack *n;
59 _Bool was_recovered;
61 /* Some other language has thrown an exception. We need to run
62 the local defer handlers. If they call recover, we stop
63 unwinding the stack here. */
65 n = ((struct __go_panic_stack *)
66 __go_alloc (sizeof (struct __go_panic_stack)));
68 n->__arg.__type_descriptor = NULL;
69 n->__arg.__object = NULL;
70 n->__was_recovered = 0;
71 n->__is_foreign = 1;
72 n->__next = __go_panic_defer->__panic;
73 __go_panic_defer->__panic = n;
75 while (1)
77 struct __go_defer_stack *d;
78 void (*pfn) (void *);
80 d = __go_panic_defer->__defer;
81 if (d == NULL || d->__frame != frame || d->__pfn == NULL)
82 break;
84 pfn = d->__pfn;
85 __go_panic_defer->__defer = d->__next;
87 (*pfn) (d->__arg);
89 __go_free (d);
91 if (n->__was_recovered)
93 /* The recover function caught the panic thrown by some
94 other language. */
95 break;
99 was_recovered = n->__was_recovered;
100 __go_panic_defer->__panic = n->__next;
101 __go_free (n);
103 if (was_recovered)
105 /* Just return and continue executing Go code. */
106 return;
109 else if (__go_panic_defer->__defer != NULL
110 && __go_panic_defer->__defer->__pfn == NULL
111 && __go_panic_defer->__defer->__frame == frame)
113 struct __go_defer_stack *d;
115 /* This is the defer function which called recover. Simply
116 return to stop the stack unwind, and let the Go code continue
117 to execute. */
118 d = __go_panic_defer->__defer;
119 __go_panic_defer->__defer = d->__next;
120 __go_free (d);
121 return;
124 /* This is some other defer function. It was already run by the
125 call to panic, or just above. Rethrow the exception. */
127 hdr = (struct _Unwind_Exception *) __go_panic_defer->__exception;
129 #ifdef LIBGO_SJLJ_EXCEPTIONS
130 _Unwind_SjLj_Resume_or_Rethrow (hdr);
131 #else
132 #if defined(_LIBUNWIND_STD_ABI)
133 _Unwind_RaiseException (hdr);
134 #else
135 _Unwind_Resume_or_Rethrow (hdr);
136 #endif
137 #endif
139 /* Rethrowing the exception should not return. */
140 abort();
143 /* Unwind function calls until we reach the one which used a defer
144 function which called recover. Each function which uses a defer
145 statement will have an exception handler, as shown above. */
147 void
148 __go_unwind_stack ()
150 struct _Unwind_Exception *hdr;
152 hdr = ((struct _Unwind_Exception *)
153 __go_alloc (sizeof (struct _Unwind_Exception)));
154 __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
155 sizeof hdr->exception_class);
156 hdr->exception_cleanup = NULL;
158 __go_panic_defer->__exception = hdr;
160 #ifdef __USING_SJLJ_EXCEPTIONS__
161 _Unwind_SjLj_RaiseException (hdr);
162 #else
163 _Unwind_RaiseException (hdr);
164 #endif
166 /* Raising an exception should not return. */
167 abort ();
170 /* The rest of this code is really similar to gcc/unwind-c.c and
171 libjava/exception.cc. */
173 typedef struct
175 _Unwind_Ptr Start;
176 _Unwind_Ptr LPStart;
177 _Unwind_Ptr ttype_base;
178 const unsigned char *TType;
179 const unsigned char *action_table;
180 unsigned char ttype_encoding;
181 unsigned char call_site_encoding;
182 } lsda_header_info;
184 static const unsigned char *
185 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
186 lsda_header_info *info)
188 _uleb128_t tmp;
189 unsigned char lpstart_encoding;
191 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
193 /* Find @LPStart, the base to which landing pad offsets are relative. */
194 lpstart_encoding = *p++;
195 if (lpstart_encoding != DW_EH_PE_omit)
196 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
197 else
198 info->LPStart = info->Start;
200 /* Find @TType, the base of the handler and exception spec type data. */
201 info->ttype_encoding = *p++;
202 if (info->ttype_encoding != DW_EH_PE_omit)
204 p = read_uleb128 (p, &tmp);
205 info->TType = p + tmp;
207 else
208 info->TType = 0;
210 /* The encoding and length of the call-site table; the action table
211 immediately follows. */
212 info->call_site_encoding = *p++;
213 p = read_uleb128 (p, &tmp);
214 info->action_table = p + tmp;
216 return p;
219 /* The personality function is invoked when unwinding the stack due to
220 a panic. Its job is to find the cleanup and exception handlers to
221 run. We can't split the stack here, because we won't be able to
222 unwind from that split. */
224 #ifdef __ARM_EABI_UNWINDER__
225 /* ARM EABI personality routines must also unwind the stack. */
226 #define CONTINUE_UNWINDING \
227 do \
229 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
230 return _URC_FAILURE; \
231 return _URC_CONTINUE_UNWIND; \
233 while (0)
234 #else
235 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
236 #endif
238 #ifdef __USING_SJLJ_EXCEPTIONS__
239 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
240 #define __builtin_eh_return_data_regno(x) x
241 #else
242 #define PERSONALITY_FUNCTION __gccgo_personality_v0
243 #endif
245 #ifdef __ARM_EABI_UNWINDER__
246 _Unwind_Reason_Code
247 PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
248 struct _Unwind_Context *)
249 __attribute__ ((no_split_stack, flatten));
251 _Unwind_Reason_Code
252 PERSONALITY_FUNCTION (_Unwind_State state,
253 struct _Unwind_Exception * ue_header,
254 struct _Unwind_Context * context)
255 #else
256 _Unwind_Reason_Code
257 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
258 struct _Unwind_Exception *, struct _Unwind_Context *)
259 __attribute__ ((no_split_stack, flatten));
261 _Unwind_Reason_Code
262 PERSONALITY_FUNCTION (int version,
263 _Unwind_Action actions,
264 _Unwind_Exception_Class exception_class,
265 struct _Unwind_Exception *ue_header,
266 struct _Unwind_Context *context)
267 #endif
269 lsda_header_info info;
270 const unsigned char *language_specific_data, *p, *action_record;
271 _Unwind_Ptr landing_pad, ip;
272 int ip_before_insn = 0;
273 _Bool is_foreign;
275 #ifdef __ARM_EABI_UNWINDER__
276 _Unwind_Action actions;
278 switch (state & _US_ACTION_MASK)
280 case _US_VIRTUAL_UNWIND_FRAME:
281 actions = _UA_SEARCH_PHASE;
282 break;
284 case _US_UNWIND_FRAME_STARTING:
285 actions = _UA_CLEANUP_PHASE;
286 if (!(state & _US_FORCE_UNWIND)
287 && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
288 actions |= _UA_HANDLER_FRAME;
289 break;
291 case _US_UNWIND_FRAME_RESUME:
292 CONTINUE_UNWINDING;
293 break;
295 default:
296 std::abort();
298 actions |= state & _US_FORCE_UNWIND;
300 is_foreign = 0;
302 /* The dwarf unwinder assumes the context structure holds things like the
303 function and LSDA pointers. The ARM implementation caches these in
304 the exception header (UCB). To avoid rewriting everything we make the
305 virtual IP register point at the UCB. */
306 ip = (_Unwind_Ptr) ue_header;
307 _Unwind_SetGR (context, 12, ip);
308 #else
309 if (version != 1)
310 return _URC_FATAL_PHASE1_ERROR;
312 is_foreign = exception_class != __go_exception_class;
313 #endif
315 language_specific_data = (const unsigned char *)
316 _Unwind_GetLanguageSpecificData (context);
318 /* If no LSDA, then there are no handlers or cleanups. */
319 if (! language_specific_data)
320 CONTINUE_UNWINDING;
322 /* Parse the LSDA header. */
323 p = parse_lsda_header (context, language_specific_data, &info);
324 #ifdef HAVE_GETIPINFO
325 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
326 #else
327 ip = _Unwind_GetIP (context);
328 #endif
329 if (! ip_before_insn)
330 --ip;
331 landing_pad = 0;
332 action_record = NULL;
334 #ifdef __USING_SJLJ_EXCEPTIONS__
335 /* The given "IP" is an index into the call-site table, with two
336 exceptions -- -1 means no-action, and 0 means terminate. But
337 since we're using uleb128 values, we've not got random access
338 to the array. */
339 if ((int) ip <= 0)
340 return _URC_CONTINUE_UNWIND;
341 else
343 _uleb128_t cs_lp, cs_action;
346 p = read_uleb128 (p, &cs_lp);
347 p = read_uleb128 (p, &cs_action);
349 while (--ip);
351 /* Can never have null landing pad for sjlj -- that would have
352 been indicated by a -1 call site index. */
353 landing_pad = (_Unwind_Ptr)cs_lp + 1;
354 if (cs_action)
355 action_record = info.action_table + cs_action - 1;
356 goto found_something;
358 #else
359 /* Search the call-site table for the action associated with this IP. */
360 while (p < info.action_table)
362 _Unwind_Ptr cs_start, cs_len, cs_lp;
363 _uleb128_t cs_action;
365 /* Note that all call-site encodings are "absolute" displacements. */
366 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
367 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
368 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
369 p = read_uleb128 (p, &cs_action);
371 /* The table is sorted, so if we've passed the ip, stop. */
372 if (ip < info.Start + cs_start)
373 p = info.action_table;
374 else if (ip < info.Start + cs_start + cs_len)
376 if (cs_lp)
377 landing_pad = info.LPStart + cs_lp;
378 if (cs_action)
379 action_record = info.action_table + cs_action - 1;
380 goto found_something;
383 #endif
385 /* IP is not in table. No associated cleanups. */
386 CONTINUE_UNWINDING;
388 found_something:
389 if (landing_pad == 0)
391 /* IP is present, but has a null landing pad.
392 No handler to be run. */
393 CONTINUE_UNWINDING;
396 if (actions & _UA_SEARCH_PHASE)
398 if (action_record == 0)
400 /* This indicates a cleanup rather than an exception
401 handler. */
402 CONTINUE_UNWINDING;
405 return _URC_HANDLER_FOUND;
408 /* It's possible for __go_panic_defer to be NULL here for an
409 exception thrown by a language other than Go. */
410 if (__go_panic_defer == NULL)
412 if (!is_foreign)
413 abort ();
415 else
417 __go_panic_defer->__exception = ue_header;
418 __go_panic_defer->__is_foreign = is_foreign;
421 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
422 (_Unwind_Ptr) ue_header);
423 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
424 _Unwind_SetIP (context, landing_pad);
425 return _URC_INSTALL_CONTEXT;