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"
19 /* The code for a Go exception. */
21 #ifdef __ARM_EABI_UNWINDER__
22 static const _Unwind_Exception_Class __go_exception_class
=
23 { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
25 static const _Unwind_Exception_Class __go_exception_class
=
26 ((((((((_Unwind_Exception_Class
) 'G'
27 << 8 | (_Unwind_Exception_Class
) 'N')
28 << 8 | (_Unwind_Exception_Class
) 'U')
29 << 8 | (_Unwind_Exception_Class
) 'C')
30 << 8 | (_Unwind_Exception_Class
) 'G')
31 << 8 | (_Unwind_Exception_Class
) 'O')
32 << 8 | (_Unwind_Exception_Class
) '\0')
33 << 8 | (_Unwind_Exception_Class
) '\0');
36 /* Rethrow an exception. */
38 void rethrowException (void) __asm__(GOSYM_PREFIX
"runtime.rethrowException");
43 struct _Unwind_Exception
*hdr
;
45 hdr
= (struct _Unwind_Exception
*) runtime_g()->exception
;
47 #ifdef __USING_SJLJ_EXCEPTIONS__
48 _Unwind_SjLj_Resume_or_Rethrow (hdr
);
50 #if defined(_LIBUNWIND_STD_ABI)
51 _Unwind_RaiseException (hdr
);
53 _Unwind_Resume_or_Rethrow (hdr
);
57 /* Rethrowing the exception should not return. */
61 /* Return the size of the type that holds an exception header, so that
62 it can be allocated by Go code. */
64 uintptr
unwindExceptionSize(void)
65 __asm__ (GOSYM_PREFIX
"runtime.unwindExceptionSize");
68 unwindExceptionSize ()
72 ret
= sizeof (struct _Unwind_Exception
);
73 /* Adjust the size fo make sure that we can get an aligned value. */
74 align
= __alignof__ (struct _Unwind_Exception
);
75 if (align
> __alignof__ (uintptr
))
76 ret
+= align
- __alignof__ (uintptr
);
80 /* Throw an exception. This is called with g->exception pointing to
81 an uninitialized _Unwind_Exception instance. */
83 void throwException (void) __asm__(GOSYM_PREFIX
"runtime.throwException");
88 struct _Unwind_Exception
*hdr
;
91 hdr
= (struct _Unwind_Exception
*)runtime_g ()->exception
;
93 /* Make sure the value is correctly aligned. It will be large
94 enough, because of unwindExceptionSize. */
95 align
= __alignof__ (struct _Unwind_Exception
);
96 hdr
= ((struct _Unwind_Exception
*)
97 (((uintptr
) hdr
+ align
- 1) &~ (align
- 1)));
99 __builtin_memcpy (&hdr
->exception_class
, &__go_exception_class
,
100 sizeof hdr
->exception_class
);
101 hdr
->exception_cleanup
= NULL
;
103 #ifdef __USING_SJLJ_EXCEPTIONS__
104 _Unwind_SjLj_RaiseException (hdr
);
106 _Unwind_RaiseException (hdr
);
109 /* Raising an exception should not return. */
113 /* The rest of this code is really similar to gcc/unwind-c.c and
114 libjava/exception.cc. */
120 _Unwind_Ptr ttype_base
;
121 const unsigned char *TType
;
122 const unsigned char *action_table
;
123 unsigned char ttype_encoding
;
124 unsigned char call_site_encoding
;
127 static const unsigned char *
128 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
129 lsda_header_info
*info
)
132 unsigned char lpstart_encoding
;
134 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
136 /* Find @LPStart, the base to which landing pad offsets are relative. */
137 lpstart_encoding
= *p
++;
138 if (lpstart_encoding
!= DW_EH_PE_omit
)
139 p
= read_encoded_value (context
, lpstart_encoding
, p
, &info
->LPStart
);
141 info
->LPStart
= info
->Start
;
143 /* Find @TType, the base of the handler and exception spec type data. */
144 info
->ttype_encoding
= *p
++;
145 if (info
->ttype_encoding
!= DW_EH_PE_omit
)
147 p
= read_uleb128 (p
, &tmp
);
148 info
->TType
= p
+ tmp
;
153 /* The encoding and length of the call-site table; the action table
154 immediately follows. */
155 info
->call_site_encoding
= *p
++;
156 p
= read_uleb128 (p
, &tmp
);
157 info
->action_table
= p
+ tmp
;
162 /* The personality function is invoked when unwinding the stack due to
163 a panic. Its job is to find the cleanup and exception handlers to
164 run. We can't split the stack here, because we won't be able to
165 unwind from that split. */
167 #ifdef __ARM_EABI_UNWINDER__
168 /* ARM EABI personality routines must also unwind the stack. */
169 #define CONTINUE_UNWINDING \
172 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
173 return _URC_FAILURE; \
174 return _URC_CONTINUE_UNWIND; \
178 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
181 #ifdef __USING_SJLJ_EXCEPTIONS__
182 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
183 #define __builtin_eh_return_data_regno(x) x
185 #define PERSONALITY_FUNCTION __gccgo_personality_v0
188 #ifdef __ARM_EABI_UNWINDER__
190 PERSONALITY_FUNCTION (_Unwind_State
, struct _Unwind_Exception
*,
191 struct _Unwind_Context
*)
192 __attribute__ ((no_split_stack
, flatten
));
195 PERSONALITY_FUNCTION (_Unwind_State state
,
196 struct _Unwind_Exception
* ue_header
,
197 struct _Unwind_Context
* context
)
200 PERSONALITY_FUNCTION (int, _Unwind_Action
, _Unwind_Exception_Class
,
201 struct _Unwind_Exception
*, struct _Unwind_Context
*)
202 __attribute__ ((no_split_stack
, flatten
));
205 PERSONALITY_FUNCTION (int version
,
206 _Unwind_Action actions
,
207 _Unwind_Exception_Class exception_class
,
208 struct _Unwind_Exception
*ue_header
,
209 struct _Unwind_Context
*context
)
212 lsda_header_info info
;
213 const unsigned char *language_specific_data
, *p
, *action_record
;
214 _Unwind_Ptr landing_pad
, ip
;
215 int ip_before_insn
= 0;
219 #ifdef __ARM_EABI_UNWINDER__
220 _Unwind_Action actions
;
222 switch (state
& _US_ACTION_MASK
)
224 case _US_VIRTUAL_UNWIND_FRAME
:
225 actions
= _UA_SEARCH_PHASE
;
228 case _US_UNWIND_FRAME_STARTING
:
229 actions
= _UA_CLEANUP_PHASE
;
230 if (!(state
& _US_FORCE_UNWIND
)
231 && ue_header
->barrier_cache
.sp
== _Unwind_GetGR(context
, 13))
232 actions
|= _UA_HANDLER_FRAME
;
235 case _US_UNWIND_FRAME_RESUME
:
242 actions
|= state
& _US_FORCE_UNWIND
;
246 /* The dwarf unwinder assumes the context structure holds things like the
247 function and LSDA pointers. The ARM implementation caches these in
248 the exception header (UCB). To avoid rewriting everything we make the
249 virtual IP register point at the UCB. */
250 ip
= (_Unwind_Ptr
) ue_header
;
251 _Unwind_SetGR (context
, 12, ip
);
254 return _URC_FATAL_PHASE1_ERROR
;
256 is_foreign
= exception_class
!= __go_exception_class
;
259 language_specific_data
= (const unsigned char *)
260 _Unwind_GetLanguageSpecificData (context
);
262 /* If no LSDA, then there are no handlers or cleanups. */
263 if (! language_specific_data
)
266 /* Parse the LSDA header. */
267 p
= parse_lsda_header (context
, language_specific_data
, &info
);
268 #ifdef HAVE_GETIPINFO
269 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
271 ip
= _Unwind_GetIP (context
);
273 if (! ip_before_insn
)
276 action_record
= NULL
;
278 #ifdef __USING_SJLJ_EXCEPTIONS__
279 /* The given "IP" is an index into the call-site table, with two
280 exceptions -- -1 means no-action, and 0 means terminate. But
281 since we're using uleb128 values, we've not got random access
284 return _URC_CONTINUE_UNWIND
;
287 _uleb128_t cs_lp
, cs_action
;
290 p
= read_uleb128 (p
, &cs_lp
);
291 p
= read_uleb128 (p
, &cs_action
);
295 /* Can never have null landing pad for sjlj -- that would have
296 been indicated by a -1 call site index. */
297 landing_pad
= (_Unwind_Ptr
)cs_lp
+ 1;
299 action_record
= info
.action_table
+ cs_action
- 1;
300 goto found_something
;
303 /* Search the call-site table for the action associated with this IP. */
304 while (p
< info
.action_table
)
306 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
307 _uleb128_t cs_action
;
309 /* Note that all call-site encodings are "absolute" displacements. */
310 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
311 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
312 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
313 p
= read_uleb128 (p
, &cs_action
);
315 /* The table is sorted, so if we've passed the ip, stop. */
316 if (ip
< info
.Start
+ cs_start
)
317 p
= info
.action_table
;
318 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
321 landing_pad
= info
.LPStart
+ cs_lp
;
323 action_record
= info
.action_table
+ cs_action
- 1;
324 goto found_something
;
329 /* IP is not in table. No associated cleanups. */
333 if (landing_pad
== 0)
335 /* IP is present, but has a null landing pad.
336 No handler to be run. */
340 if (actions
& _UA_SEARCH_PHASE
)
342 if (action_record
== 0)
344 /* This indicates a cleanup rather than an exception
349 return _URC_HANDLER_FOUND
;
352 /* It's possible for g to be NULL here for an exception thrown by a
353 language other than Go. */
362 g
->exception
= ue_header
;
363 g
->isforeign
= is_foreign
;
366 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
367 (_Unwind_Ptr
) ue_header
);
368 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1), 0);
369 _Unwind_SetIP (context
, landing_pad
);
370 return _URC_INSTALL_CONTEXT
;