github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-unwind.c (about)

     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
    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
   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 *
   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
   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  }