[Patch Doc] Update documentation for __fp16 type
[official-gcc.git] / libgo / runtime / go-unwind.c
blob9e85b4b81475ec012ae3a6cc779d6b4c6399522d
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"
13 #define NO_SIZE_OF_ENCODED_VALUE
14 #include "unwind-pe.h"
16 #include "runtime.h"
17 #include "go-alloc.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' };
24 #else
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');
34 #endif
36 /* Rethrow an exception. */
38 void rethrowException (void) __asm__(GOSYM_PREFIX "runtime.rethrowException");
40 void
41 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);
49 #else
50 #if defined(_LIBUNWIND_STD_ABI)
51 _Unwind_RaiseException (hdr);
52 #else
53 _Unwind_Resume_or_Rethrow (hdr);
54 #endif
55 #endif
57 /* Rethrowing the exception should not return. */
58 abort();
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");
67 uintptr
68 unwindExceptionSize ()
70 uintptr ret, align;
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);
77 return ret;
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");
85 void
86 throwException ()
88 struct _Unwind_Exception *hdr;
89 uintptr align;
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);
105 #else
106 _Unwind_RaiseException (hdr);
107 #endif
109 /* Raising an exception should not return. */
110 abort ();
113 /* The rest of this code is really similar to gcc/unwind-c.c and
114 libjava/exception.cc. */
116 typedef struct
118 _Unwind_Ptr Start;
119 _Unwind_Ptr LPStart;
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;
125 } lsda_header_info;
127 static const unsigned char *
128 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
129 lsda_header_info *info)
131 _uleb128_t tmp;
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);
140 else
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;
150 else
151 info->TType = 0;
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;
159 return p;
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 \
170 do \
172 if (__gnu_unwind_frame (ue_header, context) != _URC_OK) \
173 return _URC_FAILURE; \
174 return _URC_CONTINUE_UNWIND; \
176 while (0)
177 #else
178 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
179 #endif
181 #ifdef __USING_SJLJ_EXCEPTIONS__
182 #define PERSONALITY_FUNCTION __gccgo_personality_sj0
183 #define __builtin_eh_return_data_regno(x) x
184 #else
185 #define PERSONALITY_FUNCTION __gccgo_personality_v0
186 #endif
188 #ifdef __ARM_EABI_UNWINDER__
189 _Unwind_Reason_Code
190 PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
191 struct _Unwind_Context *)
192 __attribute__ ((no_split_stack, flatten));
194 _Unwind_Reason_Code
195 PERSONALITY_FUNCTION (_Unwind_State state,
196 struct _Unwind_Exception * ue_header,
197 struct _Unwind_Context * context)
198 #else
199 _Unwind_Reason_Code
200 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
201 struct _Unwind_Exception *, struct _Unwind_Context *)
202 __attribute__ ((no_split_stack, flatten));
204 _Unwind_Reason_Code
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)
210 #endif
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;
216 _Bool is_foreign;
217 G *g;
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;
226 break;
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;
233 break;
235 case _US_UNWIND_FRAME_RESUME:
236 CONTINUE_UNWINDING;
237 break;
239 default:
240 abort();
242 actions |= state & _US_FORCE_UNWIND;
244 is_foreign = 0;
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);
252 #else
253 if (version != 1)
254 return _URC_FATAL_PHASE1_ERROR;
256 is_foreign = exception_class != __go_exception_class;
257 #endif
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)
264 CONTINUE_UNWINDING;
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);
270 #else
271 ip = _Unwind_GetIP (context);
272 #endif
273 if (! ip_before_insn)
274 --ip;
275 landing_pad = 0;
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
282 to the array. */
283 if ((int) ip <= 0)
284 return _URC_CONTINUE_UNWIND;
285 else
287 _uleb128_t cs_lp, cs_action;
290 p = read_uleb128 (p, &cs_lp);
291 p = read_uleb128 (p, &cs_action);
293 while (--ip);
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;
298 if (cs_action)
299 action_record = info.action_table + cs_action - 1;
300 goto found_something;
302 #else
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)
320 if (cs_lp)
321 landing_pad = info.LPStart + cs_lp;
322 if (cs_action)
323 action_record = info.action_table + cs_action - 1;
324 goto found_something;
327 #endif
329 /* IP is not in table. No associated cleanups. */
330 CONTINUE_UNWINDING;
332 found_something:
333 if (landing_pad == 0)
335 /* IP is present, but has a null landing pad.
336 No handler to be run. */
337 CONTINUE_UNWINDING;
340 if (actions & _UA_SEARCH_PHASE)
342 if (action_record == 0)
344 /* This indicates a cleanup rather than an exception
345 handler. */
346 CONTINUE_UNWINDING;
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. */
354 g = runtime_g ();
355 if (g == NULL)
357 if (!is_foreign)
358 abort ();
360 else
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;