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. */
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' };
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');
54 /* Rethrow an exception. */
56 void rethrowException (void) __asm__(GOSYM_PREFIX
"runtime.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
);
68 #if defined(_LIBUNWIND_STD_ABI)
69 _Unwind_RaiseException (hdr
);
71 _Unwind_Resume_or_Rethrow (hdr
);
75 /* Rethrowing the exception should not return. */
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");
86 unwindExceptionSize ()
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
);
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");
106 struct _Unwind_Exception
*hdr
;
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
);
124 _Unwind_RaiseException (hdr
);
127 /* Raising an exception should not return. */
131 static inline _Unwind_Ptr
132 encoded_value_base (uint8_t encoding
, struct _Unwind_Context
*context
)
134 if (encoding
== DW_EH_PE_omit
)
136 switch (encoding
& 0x70)
138 case DW_EH_PE_absptr
:
140 case DW_EH_PE_aligned
:
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
);
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;
164 result
|= ((_uleb128_t
)byte
& 0x7f) << shift
;
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;
185 result
|= ((_uleb128_t
)byte
& 0x7f) << shift
;
191 if (shift
< (8 * sizeof(result
)) && (byte
& 0x40) != 0)
192 result
|= (((_uleb128_t
)~0) << shift
);
194 *val
= (_sleb128_t
)result
;
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 *));
217 switch (encoding
& 0x0f)
219 case DW_EH_PE_sdata2
:
222 __builtin_memcpy (&result
, p
, sizeof(int16_t));
224 p
+= sizeof(int16_t);
227 case DW_EH_PE_udata2
:
230 __builtin_memcpy (&result
, p
, sizeof(uint16_t));
232 p
+= sizeof(uint16_t);
235 case DW_EH_PE_sdata4
:
238 __builtin_memcpy (&result
, p
, sizeof(int32_t));
240 p
+= sizeof(int32_t);
243 case DW_EH_PE_udata4
:
246 __builtin_memcpy (&result
, p
, sizeof(uint32_t));
248 p
+= sizeof(uint32_t);
251 case DW_EH_PE_sdata8
:
254 __builtin_memcpy (&result
, p
, sizeof(int64_t));
256 p
+= sizeof(int64_t);
259 case DW_EH_PE_udata8
:
262 __builtin_memcpy (&result
, p
, sizeof(uint64_t));
264 p
+= sizeof(uint64_t);
267 case DW_EH_PE_uleb128
:
270 p
= read_uleb128 (p
, &value
);
271 decoded
= (_Unwind_Internal_Ptr
)value
;
274 case DW_EH_PE_sleb128
:
277 p
= read_sleb128 (p
, &value
);
278 decoded
= (_Unwind_Internal_Ptr
)value
;
281 case DW_EH_PE_absptr
:
282 __builtin_memcpy (&decoded
, (const void *)p
, sizeof(const void*));
295 if ((encoding
& 0x70) == DW_EH_PE_pcrel
)
296 decoded
+= ((_Unwind_Internal_Ptr
)origp
);
300 if ((encoding
& DW_EH_PE_indirect
) != 0)
301 decoded
= *(_Unwind_Internal_Ptr
*)decoded
;
307 /* The rest of this code is really similar to gcc/unwind-c.c and
308 libjava/exception.cc. */
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
;
321 static const unsigned char *
322 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
323 lsda_header_info
*info
)
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
);
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
;
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
;
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 \
366 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
367 return _URC_FAILURE; \
368 return _URC_CONTINUE_UNWIND; \
372 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
375 #ifdef __USING_SJLJ_EXCEPTIONS__
376 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
377 #define __builtin_eh_return_data_regno(x) x
379 #define PERSONALITY_FUNCTION __gccgo_personality_v0
382 #ifdef __ARM_EABI_UNWINDER__
384 PERSONALITY_FUNCTION (_Unwind_State
, struct _Unwind_Exception
*,
385 struct _Unwind_Context
*)
386 __attribute__ ((no_split_stack
, flatten
));
389 PERSONALITY_FUNCTION (_Unwind_State state
,
390 struct _Unwind_Exception
* ue_header
,
391 struct _Unwind_Context
* context
)
394 PERSONALITY_FUNCTION (int, _Unwind_Action
, _Unwind_Exception_Class
,
395 struct _Unwind_Exception
*, struct _Unwind_Context
*)
396 __attribute__ ((no_split_stack
, flatten
));
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
)
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;
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
;
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
;
429 case _US_UNWIND_FRAME_RESUME
:
436 actions
|= state
& _US_FORCE_UNWIND
;
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
);
448 return _URC_FATAL_PHASE1_ERROR
;
450 is_foreign
= exception_class
!= __go_exception_class
;
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
)
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
);
465 ip
= _Unwind_GetIP (context
);
467 if (! ip_before_insn
)
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
478 return _URC_CONTINUE_UNWIND
;
481 _uleb128_t cs_lp
, cs_action
;
484 p
= read_uleb128 (p
, &cs_lp
);
485 p
= read_uleb128 (p
, &cs_action
);
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;
493 action_record
= info
.action_table
+ cs_action
- 1;
494 goto found_something
;
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
)
515 landing_pad
= info
.LPStart
+ cs_lp
;
517 action_record
= info
.action_table
+ cs_action
- 1;
518 goto found_something
;
523 /* IP is not in table. No associated cleanups. */
527 if (landing_pad
== 0)
529 /* IP is present, but has a null landing pad.
530 No handler to be run. */
534 if (actions
& _UA_SEARCH_PHASE
)
536 if (action_record
== 0)
538 /* This indicates a cleanup rather than an exception
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. */
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
;