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"
18 /* The code for a Go exception. */
20 #ifdef __ARM_EABI_UNWINDER__
21 static const _Unwind_Exception_Class __go_exception_class
=
22 { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
24 static const _Unwind_Exception_Class __go_exception_class
=
25 ((((((((_Unwind_Exception_Class
) 'G'
26 << 8 | (_Unwind_Exception_Class
) 'N')
27 << 8 | (_Unwind_Exception_Class
) 'U')
28 << 8 | (_Unwind_Exception_Class
) 'C')
29 << 8 | (_Unwind_Exception_Class
) 'G')
30 << 8 | (_Unwind_Exception_Class
) 'O')
31 << 8 | (_Unwind_Exception_Class
) '\0')
32 << 8 | (_Unwind_Exception_Class
) '\0');
35 /* Rethrow an exception. */
37 void rethrowException (void) __asm__(GOSYM_PREFIX
"runtime.rethrowException");
42 struct _Unwind_Exception
*hdr
;
44 hdr
= (struct _Unwind_Exception
*) runtime_g()->exception
;
46 #ifdef __USING_SJLJ_EXCEPTIONS__
47 _Unwind_SjLj_Resume_or_Rethrow (hdr
);
49 #if defined(_LIBUNWIND_STD_ABI)
50 _Unwind_RaiseException (hdr
);
52 _Unwind_Resume_or_Rethrow (hdr
);
56 /* Rethrowing the exception should not return. */
60 /* Return the size of the type that holds an exception header, so that
61 it can be allocated by Go code. */
63 uintptr
unwindExceptionSize(void)
64 __asm__ (GOSYM_PREFIX
"runtime.unwindExceptionSize");
67 unwindExceptionSize ()
71 ret
= sizeof (struct _Unwind_Exception
);
72 /* Adjust the size fo make sure that we can get an aligned value. */
73 align
= __alignof__ (struct _Unwind_Exception
);
74 if (align
> __alignof__ (uintptr
))
75 ret
+= align
- __alignof__ (uintptr
);
79 /* Throw an exception. This is called with g->exception pointing to
80 an uninitialized _Unwind_Exception instance. */
82 void throwException (void) __asm__(GOSYM_PREFIX
"runtime.throwException");
87 struct _Unwind_Exception
*hdr
;
90 hdr
= (struct _Unwind_Exception
*)runtime_g ()->exception
;
92 /* Make sure the value is correctly aligned. It will be large
93 enough, because of unwindExceptionSize. */
94 align
= __alignof__ (struct _Unwind_Exception
);
95 hdr
= ((struct _Unwind_Exception
*)
96 (((uintptr
) hdr
+ align
- 1) &~ (align
- 1)));
98 __builtin_memcpy (&hdr
->exception_class
, &__go_exception_class
,
99 sizeof hdr
->exception_class
);
100 hdr
->exception_cleanup
= NULL
;
102 #ifdef __USING_SJLJ_EXCEPTIONS__
103 _Unwind_SjLj_RaiseException (hdr
);
105 _Unwind_RaiseException (hdr
);
108 /* Raising an exception should not return. */
112 /* The rest of this code is really similar to gcc/unwind-c.c and
113 libjava/exception.cc. */
119 _Unwind_Ptr ttype_base
;
120 const unsigned char *TType
;
121 const unsigned char *action_table
;
122 unsigned char ttype_encoding
;
123 unsigned char call_site_encoding
;
126 static const unsigned char *
127 parse_lsda_header (struct _Unwind_Context
*context
, const unsigned char *p
,
128 lsda_header_info
*info
)
131 unsigned char lpstart_encoding
;
133 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
135 /* Find @LPStart, the base to which landing pad offsets are relative. */
136 lpstart_encoding
= *p
++;
137 if (lpstart_encoding
!= DW_EH_PE_omit
)
138 p
= read_encoded_value (context
, lpstart_encoding
, p
, &info
->LPStart
);
140 info
->LPStart
= info
->Start
;
142 /* Find @TType, the base of the handler and exception spec type data. */
143 info
->ttype_encoding
= *p
++;
144 if (info
->ttype_encoding
!= DW_EH_PE_omit
)
146 p
= read_uleb128 (p
, &tmp
);
147 info
->TType
= p
+ tmp
;
152 /* The encoding and length of the call-site table; the action table
153 immediately follows. */
154 info
->call_site_encoding
= *p
++;
155 p
= read_uleb128 (p
, &tmp
);
156 info
->action_table
= p
+ tmp
;
161 /* The personality function is invoked when unwinding the stack due to
162 a panic. Its job is to find the cleanup and exception handlers to
163 run. We can't split the stack here, because we won't be able to
164 unwind from that split. */
166 #ifdef __ARM_EABI_UNWINDER__
167 /* ARM EABI personality routines must also unwind the stack. */
168 #define CONTINUE_UNWINDING \
171 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
172 return _URC_FAILURE; \
173 return _URC_CONTINUE_UNWIND; \
177 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
180 #ifdef __USING_SJLJ_EXCEPTIONS__
181 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
182 #define __builtin_eh_return_data_regno(x) x
184 #define PERSONALITY_FUNCTION __gccgo_personality_v0
187 #ifdef __ARM_EABI_UNWINDER__
189 PERSONALITY_FUNCTION (_Unwind_State
, struct _Unwind_Exception
*,
190 struct _Unwind_Context
*)
191 __attribute__ ((no_split_stack
, flatten
));
194 PERSONALITY_FUNCTION (_Unwind_State state
,
195 struct _Unwind_Exception
* ue_header
,
196 struct _Unwind_Context
* context
)
199 PERSONALITY_FUNCTION (int, _Unwind_Action
, _Unwind_Exception_Class
,
200 struct _Unwind_Exception
*, struct _Unwind_Context
*)
201 __attribute__ ((no_split_stack
, flatten
));
204 PERSONALITY_FUNCTION (int version
,
205 _Unwind_Action actions
,
206 _Unwind_Exception_Class exception_class
,
207 struct _Unwind_Exception
*ue_header
,
208 struct _Unwind_Context
*context
)
211 lsda_header_info info
;
212 const unsigned char *language_specific_data
, *p
, *action_record
;
213 _Unwind_Ptr landing_pad
, ip
;
214 int ip_before_insn
= 0;
218 #ifdef __ARM_EABI_UNWINDER__
219 _Unwind_Action actions
;
221 switch (state
& _US_ACTION_MASK
)
223 case _US_VIRTUAL_UNWIND_FRAME
:
224 actions
= _UA_SEARCH_PHASE
;
227 case _US_UNWIND_FRAME_STARTING
:
228 actions
= _UA_CLEANUP_PHASE
;
229 if (!(state
& _US_FORCE_UNWIND
)
230 && ue_header
->barrier_cache
.sp
== _Unwind_GetGR(context
, 13))
231 actions
|= _UA_HANDLER_FRAME
;
234 case _US_UNWIND_FRAME_RESUME
:
241 actions
|= state
& _US_FORCE_UNWIND
;
245 /* The dwarf unwinder assumes the context structure holds things like the
246 function and LSDA pointers. The ARM implementation caches these in
247 the exception header (UCB). To avoid rewriting everything we make the
248 virtual IP register point at the UCB. */
249 ip
= (_Unwind_Ptr
) ue_header
;
250 _Unwind_SetGR (context
, 12, ip
);
253 return _URC_FATAL_PHASE1_ERROR
;
255 is_foreign
= exception_class
!= __go_exception_class
;
258 language_specific_data
= (const unsigned char *)
259 _Unwind_GetLanguageSpecificData (context
);
261 /* If no LSDA, then there are no handlers or cleanups. */
262 if (! language_specific_data
)
265 /* Parse the LSDA header. */
266 p
= parse_lsda_header (context
, language_specific_data
, &info
);
267 #ifdef HAVE_GETIPINFO
268 ip
= _Unwind_GetIPInfo (context
, &ip_before_insn
);
270 ip
= _Unwind_GetIP (context
);
272 if (! ip_before_insn
)
275 action_record
= NULL
;
277 #ifdef __USING_SJLJ_EXCEPTIONS__
278 /* The given "IP" is an index into the call-site table, with two
279 exceptions -- -1 means no-action, and 0 means terminate. But
280 since we're using uleb128 values, we've not got random access
283 return _URC_CONTINUE_UNWIND
;
286 _uleb128_t cs_lp
, cs_action
;
289 p
= read_uleb128 (p
, &cs_lp
);
290 p
= read_uleb128 (p
, &cs_action
);
294 /* Can never have null landing pad for sjlj -- that would have
295 been indicated by a -1 call site index. */
296 landing_pad
= (_Unwind_Ptr
)cs_lp
+ 1;
298 action_record
= info
.action_table
+ cs_action
- 1;
299 goto found_something
;
302 /* Search the call-site table for the action associated with this IP. */
303 while (p
< info
.action_table
)
305 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
306 _uleb128_t cs_action
;
308 /* Note that all call-site encodings are "absolute" displacements. */
309 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
310 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
311 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
312 p
= read_uleb128 (p
, &cs_action
);
314 /* The table is sorted, so if we've passed the ip, stop. */
315 if (ip
< info
.Start
+ cs_start
)
316 p
= info
.action_table
;
317 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
320 landing_pad
= info
.LPStart
+ cs_lp
;
322 action_record
= info
.action_table
+ cs_action
- 1;
323 goto found_something
;
328 /* IP is not in table. No associated cleanups. */
332 if (landing_pad
== 0)
334 /* IP is present, but has a null landing pad.
335 No handler to be run. */
339 if (actions
& _UA_SEARCH_PHASE
)
341 if (action_record
== 0)
343 /* This indicates a cleanup rather than an exception
348 return _URC_HANDLER_FOUND
;
351 /* It's possible for g to be NULL here for an exception thrown by a
352 language other than Go. */
361 g
->exception
= ue_header
;
362 g
->isforeign
= is_foreign
;
365 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
366 (_Unwind_Ptr
) ue_header
);
367 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1), 0);
368 _Unwind_SetIP (context
, landing_pad
);
369 return _URC_INSTALL_CONTEXT
;