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. */
13 #define NO_SIZE_OF_ENCODED_VALUE
14 #include "unwind-pe.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' };
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');
38 /* This function is called by exception handlers used when unwinding
39 the stack after a recovered panic. The exception handler looks
41 __go_check_defer (frame);
43 If we have not yet reached the frame we are looking for, we
44 continue unwinding. */
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
;
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;
72 n
->__next
= __go_panic_defer
->__panic
;
73 __go_panic_defer
->__panic
= n
;
77 struct __go_defer_stack
*d
;
80 d
= __go_panic_defer
->__defer
;
81 if (d
== NULL
|| d
->__frame
!= frame
|| d
->__pfn
== NULL
)
85 __go_panic_defer
->__defer
= d
->__next
;
91 if (n
->__was_recovered
)
93 /* The recover function caught the panic thrown by some
99 was_recovered
= n
->__was_recovered
;
100 __go_panic_defer
->__panic
= n
->__next
;
105 /* Just return and continue executing Go code. */
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
118 d
= __go_panic_defer
->__defer
;
119 __go_panic_defer
->__defer
= d
->__next
;
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
);
132 #if defined(_LIBUNWIND_STD_ABI)
133 _Unwind_RaiseException (hdr
);
135 _Unwind_Resume_or_Rethrow (hdr
);
139 /* Rethrowing the exception should not return. */
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. */
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
);
163 _Unwind_RaiseException (hdr
);
166 /* Raising an exception should not return. */
170 /* The rest of this code is really similar to gcc/unwind-c.c and
171 libjava/exception.cc. */
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
;
184 static const unsigned char *
185 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
186 lsda_header_info
*info
)
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
);
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
;
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
;
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 \
229 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
230 return _URC_FAILURE; \
231 return _URC_CONTINUE_UNWIND; \
235 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
238 #ifdef __USING_SJLJ_EXCEPTIONS__
239 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
240 #define __builtin_eh_return_data_regno(x) x
242 #define PERSONALITY_FUNCTION __gccgo_personality_v0
245 #ifdef __ARM_EABI_UNWINDER__
247 PERSONALITY_FUNCTION (_Unwind_State
, struct _Unwind_Exception
*,
248 struct _Unwind_Context
*)
249 __attribute__ ((no_split_stack
, flatten
));
252 PERSONALITY_FUNCTION (_Unwind_State state
,
253 struct _Unwind_Exception
* ue_header
,
254 struct _Unwind_Context
* context
)
257 PERSONALITY_FUNCTION (int, _Unwind_Action
, _Unwind_Exception_Class
,
258 struct _Unwind_Exception
*, struct _Unwind_Context
*)
259 __attribute__ ((no_split_stack
, flatten
));
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
)
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;
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
;
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
;
291 case _US_UNWIND_FRAME_RESUME
:
298 actions
|= state
& _US_FORCE_UNWIND
;
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
);
310 return _URC_FATAL_PHASE1_ERROR
;
312 is_foreign
= exception_class
!= __go_exception_class
;
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
)
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
);
327 ip
= _Unwind_GetIP (context
);
329 if (! ip_before_insn
)
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
340 return _URC_CONTINUE_UNWIND
;
343 _uleb128_t cs_lp
, cs_action
;
346 p
= read_uleb128 (p
, &cs_lp
);
347 p
= read_uleb128 (p
, &cs_action
);
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;
355 action_record
= info
.action_table
+ cs_action
- 1;
356 goto found_something
;
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
)
377 landing_pad
= info
.LPStart
+ cs_lp
;
379 action_record
= info
.action_table
+ cs_action
- 1;
380 goto found_something
;
385 /* IP is not in table. No associated cleanups. */
389 if (landing_pad
== 0)
391 /* IP is present, but has a null landing pad.
392 No handler to be run. */
396 if (actions
& _UA_SEARCH_PHASE
)
398 if (action_record
== 0)
400 /* This indicates a cleanup rather than an exception
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
)
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
;