/cp
[official-gcc.git] / libgo / runtime / go-unwind.c
bloba059acbc22aa01c1b35637b4b71fa6a3b090e798
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"
14 #include "runtime.h"
16 /* These constants are documented here:
17 https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/dwarfext.html
20 #define DW_EH_PE_omit 0xff
21 #define DW_EH_PE_absptr 0x00
22 #define DW_EH_PE_uleb128 0x01
23 #define DW_EH_PE_udata2 0x02
24 #define DW_EH_PE_udata4 0x03
25 #define DW_EH_PE_udata8 0x04
26 #define DW_EH_PE_sleb128 0x09
27 #define DW_EH_PE_sdata2 0x0A
28 #define DW_EH_PE_sdata4 0x0B
29 #define DW_EH_PE_sdata8 0x0C
30 #define DW_EH_PE_pcrel 0x10
31 #define DW_EH_PE_textrel 0x20
32 #define DW_EH_PE_datarel 0x30
33 #define DW_EH_PE_funcrel 0x40
34 #define DW_EH_PE_aligned 0x50
35 #define DW_EH_PE_indirect 0x80
37 /* The code for a Go exception. */
39 #ifdef __ARM_EABI_UNWINDER__
40 static const _Unwind_Exception_Class __go_exception_class =
41 { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
42 #else
43 static const _Unwind_Exception_Class __go_exception_class =
44 ((((((((_Unwind_Exception_Class) 'G'
45 << 8 | (_Unwind_Exception_Class) 'N')
46 << 8 | (_Unwind_Exception_Class) 'U')
47 << 8 | (_Unwind_Exception_Class) 'C')
48 << 8 | (_Unwind_Exception_Class) 'G')
49 << 8 | (_Unwind_Exception_Class) 'O')
50 << 8 | (_Unwind_Exception_Class) '\0')
51 << 8 | (_Unwind_Exception_Class) '\0');
52 #endif
54 /* Rethrow an exception. */
56 void rethrowException (void) __asm__(GOSYM_PREFIX "runtime.rethrowException");
58 void
59 rethrowException ()
61 struct _Unwind_Exception *hdr;
63 hdr = (struct _Unwind_Exception *) runtime_g()->exception;
65 #ifdef __USING_SJLJ_EXCEPTIONS__
66 _Unwind_SjLj_Resume_or_Rethrow (hdr);
67 #else
68 #if defined(_LIBUNWIND_STD_ABI)
69 _Unwind_RaiseException (hdr);
70 #else
71 _Unwind_Resume_or_Rethrow (hdr);
72 #endif
73 #endif
75 /* Rethrowing the exception should not return. */
76 abort();
79 /* Return the size of the type that holds an exception header, so that
80 it can be allocated by Go code. */
82 uintptr unwindExceptionSize(void)
83 __asm__ (GOSYM_PREFIX "runtime.unwindExceptionSize");
85 uintptr
86 unwindExceptionSize ()
88 uintptr ret, align;
90 ret = sizeof (struct _Unwind_Exception);
91 /* Adjust the size fo make sure that we can get an aligned value. */
92 align = __alignof__ (struct _Unwind_Exception);
93 if (align > __alignof__ (uintptr))
94 ret += align - __alignof__ (uintptr);
95 return ret;
98 /* Throw an exception. This is called with g->exception pointing to
99 an uninitialized _Unwind_Exception instance. */
101 void throwException (void) __asm__(GOSYM_PREFIX "runtime.throwException");
103 void
104 throwException ()
106 struct _Unwind_Exception *hdr;
107 uintptr align;
109 hdr = (struct _Unwind_Exception *)runtime_g ()->exception;
111 /* Make sure the value is correctly aligned. It will be large
112 enough, because of unwindExceptionSize. */
113 align = __alignof__ (struct _Unwind_Exception);
114 hdr = ((struct _Unwind_Exception *)
115 (((uintptr) hdr + align - 1) &~ (align - 1)));
117 __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
118 sizeof hdr->exception_class);
119 hdr->exception_cleanup = NULL;
121 #ifdef __USING_SJLJ_EXCEPTIONS__
122 _Unwind_SjLj_RaiseException (hdr);
123 #else
124 _Unwind_RaiseException (hdr);
125 #endif
127 /* Raising an exception should not return. */
128 abort ();
131 static inline _Unwind_Ptr
132 encoded_value_base (uint8_t encoding, struct _Unwind_Context *context)
134 if (encoding == DW_EH_PE_omit)
135 return 0;
136 switch (encoding & 0x70)
138 case DW_EH_PE_absptr:
139 case DW_EH_PE_pcrel:
140 case DW_EH_PE_aligned:
141 return 0;
142 case DW_EH_PE_textrel:
143 return _Unwind_GetTextRelBase(context);
144 case DW_EH_PE_datarel:
145 return _Unwind_GetDataRelBase(context);
146 case DW_EH_PE_funcrel:
147 return _Unwind_GetRegionStart(context);
149 abort ();
152 /* Read an unsigned leb128 value. */
154 static inline const uint8_t *
155 read_uleb128 (const uint8_t *p, _uleb128_t *val)
157 unsigned int shift = 0;
158 _uleb128_t result = 0;
159 uint8_t byte;
163 byte = *p++;
164 result |= ((_uleb128_t)byte & 0x7f) << shift;
165 shift += 7;
167 while (byte & 0x80);
169 *val = result;
170 return p;
173 /* Similar, but read a signed leb128 value. */
175 static inline const uint8_t *
176 read_sleb128 (const uint8_t *p, _sleb128_t *val)
178 unsigned int shift = 0;
179 _uleb128_t result = 0;
180 uint8_t byte;
184 byte = *p++;
185 result |= ((_uleb128_t)byte & 0x7f) << shift;
186 shift += 7;
188 while (byte & 0x80);
190 /* sign extension */
191 if (shift < (8 * sizeof(result)) && (byte & 0x40) != 0)
192 result |= (((_uleb128_t)~0) << shift);
194 *val = (_sleb128_t)result;
195 return p;
198 #define ROUND_UP_TO_PVB(x) (x + sizeof(void *) - 1) &- sizeof(void *)
200 static inline const uint8_t *
201 read_encoded_value (struct _Unwind_Context *context, uint8_t encoding,
202 const uint8_t *p, _Unwind_Ptr *val)
204 _Unwind_Ptr base = encoded_value_base (encoding, context);
205 _Unwind_Internal_Ptr decoded = 0;
206 const uint8_t *origp = p;
208 if (encoding == DW_EH_PE_aligned)
210 _Unwind_Internal_Ptr uip = (_Unwind_Internal_Ptr)p;
211 uip = ROUND_UP_TO_PVB (uip);
212 decoded = *(_Unwind_Internal_Ptr *)uip;
213 p = (const uint8_t *)(uip + sizeof(void *));
215 else
217 switch (encoding & 0x0f)
219 case DW_EH_PE_sdata2:
221 int16_t result;
222 __builtin_memcpy (&result, p, sizeof(int16_t));
223 decoded = result;
224 p += sizeof(int16_t);
225 break;
227 case DW_EH_PE_udata2:
229 uint16_t result;
230 __builtin_memcpy (&result, p, sizeof(uint16_t));
231 decoded = result;
232 p += sizeof(uint16_t);
233 break;
235 case DW_EH_PE_sdata4:
237 int32_t result;
238 __builtin_memcpy (&result, p, sizeof(int32_t));
239 decoded = result;
240 p += sizeof(int32_t);
241 break;
243 case DW_EH_PE_udata4:
245 uint32_t result;
246 __builtin_memcpy (&result, p, sizeof(uint32_t));
247 decoded = result;
248 p += sizeof(uint32_t);
249 break;
251 case DW_EH_PE_sdata8:
253 int64_t result;
254 __builtin_memcpy (&result, p, sizeof(int64_t));
255 decoded = result;
256 p += sizeof(int64_t);
257 break;
259 case DW_EH_PE_udata8:
261 uint64_t result;
262 __builtin_memcpy (&result, p, sizeof(uint64_t));
263 decoded = result;
264 p += sizeof(uint64_t);
265 break;
267 case DW_EH_PE_uleb128:
269 _uleb128_t value;
270 p = read_uleb128 (p, &value);
271 decoded = (_Unwind_Internal_Ptr)value;
272 break;
274 case DW_EH_PE_sleb128:
276 _sleb128_t value;
277 p = read_sleb128 (p, &value);
278 decoded = (_Unwind_Internal_Ptr)value;
279 break;
281 case DW_EH_PE_absptr:
282 __builtin_memcpy (&decoded, (const void *)p, sizeof(const void*));
283 p += sizeof(void *);
284 break;
285 default:
286 abort ();
289 if (decoded == 0)
291 *val = decoded;
292 return p;
295 if ((encoding & 0x70) == DW_EH_PE_pcrel)
296 decoded += ((_Unwind_Internal_Ptr)origp);
297 else
298 decoded += base;
300 if ((encoding & DW_EH_PE_indirect) != 0)
301 decoded = *(_Unwind_Internal_Ptr *)decoded;
303 *val = decoded;
304 return p;
307 /* The rest of this code is really similar to gcc/unwind-c.c and
308 libjava/exception.cc. */
310 typedef struct
312 _Unwind_Ptr Start;
313 _Unwind_Ptr LPStart;
314 _Unwind_Ptr ttype_base;
315 const unsigned char *TType;
316 const unsigned char *action_table;
317 unsigned char ttype_encoding;
318 unsigned char call_site_encoding;
319 } lsda_header_info;
321 static const unsigned char *
322 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
323 lsda_header_info *info)
325 _uleb128_t tmp;
326 unsigned char lpstart_encoding;
328 info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
330 /* Find @LPStart, the base to which landing pad offsets are relative. */
331 lpstart_encoding = *p++;
332 if (lpstart_encoding != DW_EH_PE_omit)
333 p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
334 else
335 info->LPStart = info->Start;
337 /* Find @TType, the base of the handler and exception spec type data. */
338 info->ttype_encoding = *p++;
339 if (info->ttype_encoding != DW_EH_PE_omit)
341 p = read_uleb128 (p, &tmp);
342 info->TType = p + tmp;
344 else
345 info->TType = 0;
347 /* The encoding and length of the call-site table; the action table
348 immediately follows. */
349 info->call_site_encoding = *p++;
350 p = read_uleb128 (p, &tmp);
351 info->action_table = p + tmp;
353 return p;
356 /* The personality function is invoked when unwinding the stack due to
357 a panic. Its job is to find the cleanup and exception handlers to
358 run. We can't split the stack here, because we won't be able to
359 unwind from that split. */
361 #ifdef __ARM_EABI_UNWINDER__
362 /* ARM EABI personality routines must also unwind the stack. */
363 #define CONTINUE_UNWINDING \
364 do \
366 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
367 return _URC_FAILURE; \
368 return _URC_CONTINUE_UNWIND; \
370 while (0)
371 #else
372 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
373 #endif
375 #ifdef __USING_SJLJ_EXCEPTIONS__
376 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
377 #define __builtin_eh_return_data_regno(x) x
378 #else
379 #define PERSONALITY_FUNCTION __gccgo_personality_v0
380 #endif
382 #ifdef __ARM_EABI_UNWINDER__
383 _Unwind_Reason_Code
384 PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
385 struct _Unwind_Context *)
386 __attribute__ ((no_split_stack, flatten));
388 _Unwind_Reason_Code
389 PERSONALITY_FUNCTION (_Unwind_State state,
390 struct _Unwind_Exception * ue_header,
391 struct _Unwind_Context * context)
392 #else
393 _Unwind_Reason_Code
394 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
395 struct _Unwind_Exception *, struct _Unwind_Context *)
396 __attribute__ ((no_split_stack, flatten));
398 _Unwind_Reason_Code
399 PERSONALITY_FUNCTION (int version,
400 _Unwind_Action actions,
401 _Unwind_Exception_Class exception_class,
402 struct _Unwind_Exception *ue_header,
403 struct _Unwind_Context *context)
404 #endif
406 lsda_header_info info;
407 const unsigned char *language_specific_data, *p, *action_record;
408 _Unwind_Ptr landing_pad, ip;
409 int ip_before_insn = 0;
410 _Bool is_foreign;
411 G *g;
413 #ifdef __ARM_EABI_UNWINDER__
414 _Unwind_Action actions;
416 switch (state & _US_ACTION_MASK)
418 case _US_VIRTUAL_UNWIND_FRAME:
419 actions = _UA_SEARCH_PHASE;
420 break;
422 case _US_UNWIND_FRAME_STARTING:
423 actions = _UA_CLEANUP_PHASE;
424 if (!(state & _US_FORCE_UNWIND)
425 && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
426 actions |= _UA_HANDLER_FRAME;
427 break;
429 case _US_UNWIND_FRAME_RESUME:
430 CONTINUE_UNWINDING;
431 break;
433 default:
434 abort();
436 actions |= state & _US_FORCE_UNWIND;
438 is_foreign = 0;
440 /* The dwarf unwinder assumes the context structure holds things like the
441 function and LSDA pointers. The ARM implementation caches these in
442 the exception header (UCB). To avoid rewriting everything we make the
443 virtual IP register point at the UCB. */
444 ip = (_Unwind_Ptr) ue_header;
445 _Unwind_SetGR (context, 12, ip);
446 #else
447 if (version != 1)
448 return _URC_FATAL_PHASE1_ERROR;
450 is_foreign = exception_class != __go_exception_class;
451 #endif
453 language_specific_data = (const unsigned char *)
454 _Unwind_GetLanguageSpecificData (context);
456 /* If no LSDA, then there are no handlers or cleanups. */
457 if (! language_specific_data)
458 CONTINUE_UNWINDING;
460 /* Parse the LSDA header. */
461 p = parse_lsda_header (context, language_specific_data, &info);
462 #ifdef HAVE_GETIPINFO
463 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
464 #else
465 ip = _Unwind_GetIP (context);
466 #endif
467 if (! ip_before_insn)
468 --ip;
469 landing_pad = 0;
470 action_record = NULL;
472 #ifdef __USING_SJLJ_EXCEPTIONS__
473 /* The given "IP" is an index into the call-site table, with two
474 exceptions -- -1 means no-action, and 0 means terminate. But
475 since we're using uleb128 values, we've not got random access
476 to the array. */
477 if ((int) ip <= 0)
478 return _URC_CONTINUE_UNWIND;
479 else
481 _uleb128_t cs_lp, cs_action;
484 p = read_uleb128 (p, &cs_lp);
485 p = read_uleb128 (p, &cs_action);
487 while (--ip);
489 /* Can never have null landing pad for sjlj -- that would have
490 been indicated by a -1 call site index. */
491 landing_pad = (_Unwind_Ptr)cs_lp + 1;
492 if (cs_action)
493 action_record = info.action_table + cs_action - 1;
494 goto found_something;
496 #else
497 /* Search the call-site table for the action associated with this IP. */
498 while (p < info.action_table)
500 _Unwind_Ptr cs_start, cs_len, cs_lp;
501 _uleb128_t cs_action;
503 /* Note that all call-site encodings are "absolute" displacements. */
504 p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
505 p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
506 p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
507 p = read_uleb128 (p, &cs_action);
509 /* The table is sorted, so if we've passed the ip, stop. */
510 if (ip < info.Start + cs_start)
511 p = info.action_table;
512 else if (ip < info.Start + cs_start + cs_len)
514 if (cs_lp)
515 landing_pad = info.LPStart + cs_lp;
516 if (cs_action)
517 action_record = info.action_table + cs_action - 1;
518 goto found_something;
521 #endif
523 /* IP is not in table. No associated cleanups. */
524 CONTINUE_UNWINDING;
526 found_something:
527 if (landing_pad == 0)
529 /* IP is present, but has a null landing pad.
530 No handler to be run. */
531 CONTINUE_UNWINDING;
534 if (actions & _UA_SEARCH_PHASE)
536 if (action_record == 0)
538 /* This indicates a cleanup rather than an exception
539 handler. */
540 CONTINUE_UNWINDING;
543 return _URC_HANDLER_FOUND;
546 /* It's possible for g to be NULL here for an exception thrown by a
547 language other than Go. */
548 g = runtime_g ();
549 if (g == NULL)
551 if (!is_foreign)
552 abort ();
554 else
556 g->exception = ue_header;
557 g->isforeign = is_foreign;
560 _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
561 (_Unwind_Ptr) ue_header);
562 _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
563 _Unwind_SetIP (context, landing_pad);
564 return _URC_INSTALL_CONTEXT;