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