OSDN Git Service

Fix calling make with slice whose element type is size zero.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / go-unwind.c
1 /* go-unwind.c -- unwind the stack for panic/recover.
2
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.  */
6
7 #include "config.h"
8
9 #include <stdlib.h>
10 #include <unistd.h>
11
12 #include "unwind.h"
13 #define NO_SIZE_OF_ENCODED_VALUE
14 #include "unwind-pe.h"
15
16 #include "go-alloc.h"
17 #include "go-defer.h"
18 #include "go-panic.h"
19
20 /* The code for a Go exception.  */
21
22 #ifdef __ARM_EABI_UNWINDER__
23 static const _Unwind_Exception_Class __go_exception_class =
24   { 'G', 'N', 'U', 'C', 'G', 'O', '\0', '\0' };
25 #else
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');
35 #endif
36
37
38 /* This function is called by exception handlers used when unwinding
39    the stack after a recovered panic.  The exception handler looks
40    like this:
41      __go_check_defer (frame);
42      return;
43    If we have not yet reached the frame we are looking for, we
44    continue unwinding.  */
45
46 void
47 __go_check_defer (_Bool *frame)
48 {
49   struct _Unwind_Exception *hdr;
50
51   if (__go_panic_defer == NULL)
52     {
53       /* Some other language has thrown an exception.  We know there
54          are no defer handlers, so there is nothing to do.  */
55     }
56   else if (__go_panic_defer->__is_foreign)
57     {
58       struct __go_panic_stack *n;
59       _Bool was_recovered;
60
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.  */
64
65       n = ((struct __go_panic_stack *)
66            __go_alloc (sizeof (struct __go_panic_stack)));
67
68       n->__arg.__type_descriptor = NULL;
69       n->__arg.__object = NULL;
70       n->__was_recovered = 0;
71       n->__is_foreign = 1;
72       n->__next = __go_panic_defer->__panic;
73       __go_panic_defer->__panic = n;
74
75       while (1)
76         {
77           struct __go_defer_stack *d;
78           void (*pfn) (void *);
79
80           d = __go_panic_defer->__defer;
81           if (d == NULL || d->__frame != frame || d->__pfn == NULL)
82             break;
83
84           pfn = d->__pfn;
85           __go_panic_defer->__defer = d->__next;
86
87           (*pfn) (d->__arg);
88
89           __go_free (d);
90
91           if (n->__was_recovered)
92             {
93               /* The recover function caught the panic thrown by some
94                  other language.  */
95               break;
96             }
97         }
98
99       was_recovered = n->__was_recovered;
100       __go_panic_defer->__panic = n->__next;
101       __go_free (n);
102
103       if (was_recovered)
104         {
105           /* Just return and continue executing Go code.  */
106           *frame = 1;
107           return;
108         }
109
110       /* We are panicing through this function.  */
111       *frame = 0;
112     }
113   else if (__go_panic_defer->__defer != NULL
114            && __go_panic_defer->__defer->__pfn == NULL
115            && __go_panic_defer->__defer->__frame == frame)
116     {
117       struct __go_defer_stack *d;
118
119       /* This is the defer function which called recover.  Simply
120          return to stop the stack unwind, and let the Go code continue
121          to execute.  */
122       d = __go_panic_defer->__defer;
123       __go_panic_defer->__defer = d->__next;
124       __go_free (d);
125
126       /* We are returning from this function.  */
127       *frame = 1;
128
129       return;
130     }
131
132   /* This is some other defer function.  It was already run by the
133      call to panic, or just above.  Rethrow the exception.  */
134
135   hdr = (struct _Unwind_Exception *) __go_panic_defer->__exception;
136
137 #ifdef LIBGO_SJLJ_EXCEPTIONS
138   _Unwind_SjLj_Resume_or_Rethrow (hdr);
139 #else
140 #if defined(_LIBUNWIND_STD_ABI)
141   _Unwind_RaiseException (hdr);
142 #else
143   _Unwind_Resume_or_Rethrow (hdr);
144 #endif
145 #endif
146
147   /* Rethrowing the exception should not return.  */
148   abort();
149 }
150
151 /* Unwind function calls until we reach the one which used a defer
152    function which called recover.  Each function which uses a defer
153    statement will have an exception handler, as shown above.  */
154
155 void
156 __go_unwind_stack ()
157 {
158   struct _Unwind_Exception *hdr;
159
160   hdr = ((struct _Unwind_Exception *)
161          __go_alloc (sizeof (struct _Unwind_Exception)));
162   __builtin_memcpy (&hdr->exception_class, &__go_exception_class,
163                     sizeof hdr->exception_class);
164   hdr->exception_cleanup = NULL;
165
166   __go_panic_defer->__exception = hdr;
167
168 #ifdef __USING_SJLJ_EXCEPTIONS__
169   _Unwind_SjLj_RaiseException (hdr);
170 #else
171   _Unwind_RaiseException (hdr);
172 #endif
173
174   /* Raising an exception should not return.  */
175   abort ();
176 }
177
178 /* The rest of this code is really similar to gcc/unwind-c.c and
179    libjava/exception.cc.  */
180
181 typedef struct
182 {
183   _Unwind_Ptr Start;
184   _Unwind_Ptr LPStart;
185   _Unwind_Ptr ttype_base;
186   const unsigned char *TType;
187   const unsigned char *action_table;
188   unsigned char ttype_encoding;
189   unsigned char call_site_encoding;
190 } lsda_header_info;
191
192 static const unsigned char *
193 parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
194                    lsda_header_info *info)
195 {
196   _uleb128_t tmp;
197   unsigned char lpstart_encoding;
198
199   info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
200
201   /* Find @LPStart, the base to which landing pad offsets are relative.  */
202   lpstart_encoding = *p++;
203   if (lpstart_encoding != DW_EH_PE_omit)
204     p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
205   else
206     info->LPStart = info->Start;
207
208   /* Find @TType, the base of the handler and exception spec type data.  */
209   info->ttype_encoding = *p++;
210   if (info->ttype_encoding != DW_EH_PE_omit)
211     {
212       p = read_uleb128 (p, &tmp);
213       info->TType = p + tmp;
214     }
215   else
216     info->TType = 0;
217
218   /* The encoding and length of the call-site table; the action table
219      immediately follows.  */
220   info->call_site_encoding = *p++;
221   p = read_uleb128 (p, &tmp);
222   info->action_table = p + tmp;
223
224   return p;
225 }
226
227 /* The personality function is invoked when unwinding the stack due to
228    a panic.  Its job is to find the cleanup and exception handlers to
229    run.  We can't split the stack here, because we won't be able to
230    unwind from that split.  */
231
232 #ifdef __ARM_EABI_UNWINDER__
233 /* ARM EABI personality routines must also unwind the stack.  */
234 #define CONTINUE_UNWINDING \
235   do                                                            \
236     {                                                           \
237       if (__gnu_unwind_frame (ue_header, context) != _URC_OK)   \
238         return _URC_FAILURE;                                    \
239       return _URC_CONTINUE_UNWIND;                              \
240     }                                                           \
241   while (0)
242 #else
243 #define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND
244 #endif
245
246 #ifdef __USING_SJLJ_EXCEPTIONS__
247 #define PERSONALITY_FUNCTION    __gccgo_personality_sj0
248 #define __builtin_eh_return_data_regno(x) x
249 #else
250 #define PERSONALITY_FUNCTION    __gccgo_personality_v0
251 #endif
252
253 #ifdef __ARM_EABI_UNWINDER__
254 _Unwind_Reason_Code
255 PERSONALITY_FUNCTION (_Unwind_State, struct _Unwind_Exception *,
256                       struct _Unwind_Context *)
257   __attribute__ ((no_split_stack, flatten));
258
259 _Unwind_Reason_Code
260 PERSONALITY_FUNCTION (_Unwind_State state,
261                       struct _Unwind_Exception * ue_header,
262                       struct _Unwind_Context * context)
263 #else
264 _Unwind_Reason_Code
265 PERSONALITY_FUNCTION (int, _Unwind_Action, _Unwind_Exception_Class,
266                       struct _Unwind_Exception *, struct _Unwind_Context *)
267   __attribute__ ((no_split_stack, flatten));
268
269 _Unwind_Reason_Code
270 PERSONALITY_FUNCTION (int version,
271                       _Unwind_Action actions,
272                       _Unwind_Exception_Class exception_class,
273                       struct _Unwind_Exception *ue_header,
274                       struct _Unwind_Context *context)
275 #endif
276 {
277   lsda_header_info info;
278   const unsigned char *language_specific_data, *p, *action_record;
279   _Unwind_Ptr landing_pad, ip;
280   int ip_before_insn = 0;
281   _Bool is_foreign;
282
283 #ifdef __ARM_EABI_UNWINDER__
284   _Unwind_Action actions;
285
286   switch (state & _US_ACTION_MASK)
287     {
288     case _US_VIRTUAL_UNWIND_FRAME:
289       actions = _UA_SEARCH_PHASE;
290       break;
291
292     case _US_UNWIND_FRAME_STARTING:
293       actions = _UA_CLEANUP_PHASE;
294       if (!(state & _US_FORCE_UNWIND)
295           && ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13))
296         actions |= _UA_HANDLER_FRAME;
297       break;
298
299     case _US_UNWIND_FRAME_RESUME:
300       CONTINUE_UNWINDING;
301       break;
302
303     default:
304       abort();
305     }
306   actions |= state & _US_FORCE_UNWIND;
307
308   is_foreign = 0;
309
310   /* The dwarf unwinder assumes the context structure holds things like the
311      function and LSDA pointers.  The ARM implementation caches these in
312      the exception header (UCB).  To avoid rewriting everything we make the
313      virtual IP register point at the UCB.  */
314   ip = (_Unwind_Ptr) ue_header;
315   _Unwind_SetGR (context, 12, ip);
316 #else
317   if (version != 1)
318     return _URC_FATAL_PHASE1_ERROR;
319
320   is_foreign = exception_class != __go_exception_class;
321 #endif
322
323   language_specific_data = (const unsigned char *)
324     _Unwind_GetLanguageSpecificData (context);
325
326   /* If no LSDA, then there are no handlers or cleanups.  */
327   if (! language_specific_data)
328     CONTINUE_UNWINDING;
329
330   /* Parse the LSDA header.  */
331   p = parse_lsda_header (context, language_specific_data, &info);
332 #ifdef HAVE_GETIPINFO
333   ip = _Unwind_GetIPInfo (context, &ip_before_insn);
334 #else
335   ip = _Unwind_GetIP (context);
336 #endif
337   if (! ip_before_insn)
338     --ip;
339   landing_pad = 0;
340   action_record = NULL;
341
342 #ifdef __USING_SJLJ_EXCEPTIONS__
343   /* The given "IP" is an index into the call-site table, with two
344      exceptions -- -1 means no-action, and 0 means terminate.  But
345      since we're using uleb128 values, we've not got random access
346      to the array.  */
347   if ((int) ip <= 0)
348     return _URC_CONTINUE_UNWIND;
349   else
350     {
351       _uleb128_t cs_lp, cs_action;
352       do
353         {
354           p = read_uleb128 (p, &cs_lp);
355           p = read_uleb128 (p, &cs_action);
356         }
357       while (--ip);
358
359       /* Can never have null landing pad for sjlj -- that would have
360          been indicated by a -1 call site index.  */
361       landing_pad = (_Unwind_Ptr)cs_lp + 1;
362       if (cs_action)
363         action_record = info.action_table + cs_action - 1;
364       goto found_something;
365     }
366 #else
367   /* Search the call-site table for the action associated with this IP.  */
368   while (p < info.action_table)
369     {
370       _Unwind_Ptr cs_start, cs_len, cs_lp;
371       _uleb128_t cs_action;
372
373       /* Note that all call-site encodings are "absolute" displacements.  */
374       p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
375       p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
376       p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
377       p = read_uleb128 (p, &cs_action);
378
379       /* The table is sorted, so if we've passed the ip, stop.  */
380       if (ip < info.Start + cs_start)
381         p = info.action_table;
382       else if (ip < info.Start + cs_start + cs_len)
383         {
384           if (cs_lp)
385             landing_pad = info.LPStart + cs_lp;
386           if (cs_action)
387             action_record = info.action_table + cs_action - 1;
388           goto found_something;
389         }
390     }
391 #endif
392
393   /* IP is not in table.  No associated cleanups.  */
394   CONTINUE_UNWINDING;
395
396  found_something:
397   if (landing_pad == 0)
398     {
399       /* IP is present, but has a null landing pad.
400          No handler to be run.  */
401       CONTINUE_UNWINDING;
402     }
403
404   if (actions & _UA_SEARCH_PHASE)
405     {
406       if (action_record == 0)
407         {
408           /* This indicates a cleanup rather than an exception
409              handler.  */
410           CONTINUE_UNWINDING;
411         }
412
413       return _URC_HANDLER_FOUND;
414     }
415
416   /* It's possible for __go_panic_defer to be NULL here for an
417      exception thrown by a language other than Go.  */
418   if (__go_panic_defer == NULL)
419     {
420       if (!is_foreign)
421         abort ();
422     }
423   else
424     {
425       __go_panic_defer->__exception = ue_header;
426       __go_panic_defer->__is_foreign = is_foreign;
427     }
428
429   _Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
430                  (_Unwind_Ptr) ue_header);
431   _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), 0);
432   _Unwind_SetIP (context, landing_pad);
433   return _URC_INSTALL_CONTEXT;
434 }