(root)/
gcc-13.2.0/
libgcc/
unwind-sjlj.c
       1  /* SJLJ exception handling and frame unwind runtime interface routines.
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of GCC.
       5  
       6     GCC is free software; you can redistribute it and/or modify it
       7     under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     GCC is distributed in the hope that it will be useful, but WITHOUT
      12     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      13     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      14     License for more details.
      15  
      16     Under Section 7 of GPL version 3, you are granted additional
      17     permissions described in the GCC Runtime Library Exception, version
      18     3.1, as published by the Free Software Foundation.
      19  
      20     You should have received a copy of the GNU General Public License and
      21     a copy of the GCC Runtime Library Exception along with this program;
      22     see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23     <http://www.gnu.org/licenses/>.  */
      24  
      25  #include "tconfig.h"
      26  #include "tsystem.h"
      27  #include "coretypes.h"
      28  #include "tm.h"
      29  #include "libgcc_tm.h"
      30  #include "unwind.h"
      31  #include "gthr.h"
      32  
      33  #ifdef __USING_SJLJ_EXCEPTIONS__
      34  
      35  #ifdef __LIBGCC_DONT_USE_BUILTIN_SETJMP__
      36  #ifndef inhibit_libc
      37  #include <setjmp.h>
      38  #else
      39  typedef void *jmp_buf[__LIBGCC_JMP_BUF_SIZE__];
      40  extern void longjmp(jmp_buf, int) __attribute__((noreturn));
      41  #endif
      42  #else
      43  #define longjmp __builtin_longjmp
      44  #endif
      45  
      46  /* The setjmp side is dealt with in the except.c file.  */
      47  #undef setjmp
      48  #define setjmp setjmp_should_not_be_used_in_this_file
      49  
      50  
      51  /* This structure is allocated on the stack of the target function.
      52     This must match the definition created in except.c:init_eh.  */
      53  struct SjLj_Function_Context
      54  {
      55    /* This is the chain through all registered contexts.  It is
      56       filled in by _Unwind_SjLj_Register.  */
      57    struct SjLj_Function_Context *prev;
      58  
      59    /* This is assigned in by the target function before every call
      60       to the index of the call site in the lsda.  It is assigned by
      61       the personality routine to the landing pad index.  */
      62    int call_site;
      63  
      64    /* This is how data is returned from the personality routine to
      65       the target function's handler.  */
      66    _Unwind_Word data[4];
      67  
      68    /* These are filled in once by the target function before any
      69       exceptions are expected to be handled.  */
      70    _Unwind_Personality_Fn personality;
      71    void *lsda;
      72  
      73  #ifdef __LIBGCC_DONT_USE_BUILTIN_SETJMP__
      74    /* We don't know what sort of alignment requirements the system
      75       jmp_buf has.  We over estimated in except.c, and now we have
      76       to match that here just in case the system *didn't* have more
      77       restrictive requirements.  */
      78    jmp_buf jbuf __attribute__((aligned));
      79  #else
      80    void *jbuf[];
      81  #endif
      82  };
      83  
      84  struct _Unwind_Context
      85  {
      86    struct SjLj_Function_Context *fc;
      87  };
      88  
      89  typedef struct
      90  {
      91    _Unwind_Personality_Fn personality;
      92  } _Unwind_FrameState;
      93  
      94  
      95  /* Manage the chain of registered function contexts.  */
      96  
      97  /* Single threaded fallback chain.  */
      98  static struct SjLj_Function_Context *fc_static;
      99  
     100  #if __GTHREADS
     101  static __gthread_key_t fc_key;
     102  static int use_fc_key = -1;
     103  
     104  static void
     105  fc_key_init (void)
     106  {
     107    use_fc_key = __gthread_key_create (&fc_key, 0) == 0;
     108  }
     109  
     110  static void
     111  fc_key_init_once (void)
     112  {
     113    static __gthread_once_t once = __GTHREAD_ONCE_INIT;
     114    if (__gthread_once (&once, fc_key_init) != 0 || use_fc_key < 0)
     115      use_fc_key = 0;
     116  }
     117  #endif
     118  
     119  void
     120  _Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
     121  {
     122  #if __GTHREADS
     123    if (use_fc_key < 0)
     124      fc_key_init_once ();
     125  
     126    if (use_fc_key)
     127      {
     128        fc->prev = __gthread_getspecific (fc_key);
     129        __gthread_setspecific (fc_key, fc);
     130      }
     131    else
     132  #endif
     133      {
     134        fc->prev = fc_static;
     135        fc_static = fc;
     136      }
     137  }
     138  
     139  static inline struct SjLj_Function_Context *
     140  _Unwind_SjLj_GetContext (void)
     141  {
     142  #if __GTHREADS
     143    if (use_fc_key < 0)
     144      fc_key_init_once ();
     145  
     146    if (use_fc_key)
     147      return __gthread_getspecific (fc_key);
     148  #endif
     149    return fc_static;
     150  }
     151  
     152  static inline void
     153  _Unwind_SjLj_SetContext (struct SjLj_Function_Context *fc)
     154  {
     155  #if __GTHREADS
     156    if (use_fc_key < 0)
     157      fc_key_init_once ();
     158  
     159    if (use_fc_key)
     160      __gthread_setspecific (fc_key, fc);
     161    else
     162  #endif
     163      fc_static = fc;
     164  }
     165  
     166  void
     167  _Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
     168  {
     169    _Unwind_SjLj_SetContext (fc->prev);
     170  }
     171  
     172  
     173  /* Get/set the return data value at INDEX in CONTEXT.  */
     174  
     175  _Unwind_Word
     176  _Unwind_GetGR (struct _Unwind_Context *context, int index)
     177  {
     178    return context->fc->data[index];
     179  }
     180  
     181  /* Get the value of the CFA as saved in CONTEXT.  */
     182  
     183  _Unwind_Word
     184  _Unwind_GetCFA (struct _Unwind_Context *context __attribute__((unused)))
     185  {
     186    /* ??? Ideally __builtin_setjmp places the CFA in the jmpbuf.  */
     187  
     188  #ifndef __LIBGCC_DONT_USE_BUILTIN_SETJMP__
     189    /* This is a crude imitation of the CFA: the saved stack pointer.
     190       This is roughly the CFA of the frame before CONTEXT.  When using the
     191       DWARF-2 unwinder _Unwind_GetCFA returns the CFA of the frame described
     192       by CONTEXT instead; but for DWARF-2 the cleanups associated with
     193       CONTEXT have already been run, and for SJLJ they have not yet been.  */
     194    if (context->fc != NULL)
     195      return (_Unwind_Word) context->fc->jbuf[2];
     196  #endif
     197  
     198    /* Otherwise we're out of luck for now.  */
     199    return (_Unwind_Word) 0;
     200  }
     201  
     202  void
     203  _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
     204  {
     205    context->fc->data[index] = val;
     206  }
     207  
     208  /* Get the call-site index as saved in CONTEXT.  */
     209  
     210  _Unwind_Ptr
     211  _Unwind_GetIP (struct _Unwind_Context *context)
     212  {
     213    return context->fc->call_site + 1;
     214  }
     215  
     216  _Unwind_Ptr
     217  _Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
     218  {
     219    *ip_before_insn = 0;
     220    if (context->fc != NULL)
     221      return context->fc->call_site + 1;
     222    else
     223      return 0;
     224  }
     225  
     226  /* Set the return landing pad index in CONTEXT.  */
     227  
     228  void
     229  _Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
     230  {
     231    context->fc->call_site = val - 1;
     232  }
     233  
     234  void *
     235  _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
     236  {
     237    return context->fc->lsda;
     238  }
     239  
     240  _Unwind_Ptr
     241  _Unwind_GetRegionStart (struct _Unwind_Context *context __attribute__((unused)) )
     242  {
     243    return 0;
     244  }
     245  
     246  void *
     247  _Unwind_FindEnclosingFunction (void *pc __attribute__((unused)))
     248  {
     249    return NULL;
     250  }
     251  
     252  #ifndef __ia64__
     253  _Unwind_Ptr
     254  _Unwind_GetDataRelBase (struct _Unwind_Context *context __attribute__((unused)) )
     255  {
     256    return 0;
     257  }
     258  
     259  _Unwind_Ptr
     260  _Unwind_GetTextRelBase (struct _Unwind_Context *context __attribute__((unused)) )
     261  {
     262    return 0;
     263  }
     264  #endif
     265  
     266  static inline _Unwind_Reason_Code
     267  uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     268  {
     269    if (context->fc == NULL)
     270      {
     271        fs->personality = NULL;
     272        return _URC_END_OF_STACK;
     273      }
     274    else
     275      {
     276        fs->personality = context->fc->personality;
     277        return _URC_NO_REASON;
     278      }
     279  }
     280  
     281  static inline void
     282  uw_update_context (struct _Unwind_Context *context,
     283  		   _Unwind_FrameState *fs __attribute__((unused)) )
     284  {
     285    context->fc = context->fc->prev;
     286  }
     287  
     288  static void
     289  uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
     290  {
     291    _Unwind_SjLj_Unregister (context->fc);
     292    uw_update_context (context, fs);
     293  }
     294  
     295  static inline void
     296  uw_init_context (struct _Unwind_Context *context)
     297  {
     298    context->fc = _Unwind_SjLj_GetContext ();
     299  }
     300  
     301  static void __attribute__((noreturn))
     302  uw_install_context (struct _Unwind_Context *current __attribute__((unused)),
     303                      struct _Unwind_Context *target,
     304  		    unsigned long frames __attribute__((unused)))
     305  {
     306    _Unwind_SjLj_SetContext (target->fc);
     307    longjmp (target->fc->jbuf, 1);
     308  }
     309  
     310  static inline _Unwind_Ptr
     311  uw_identify_context (struct _Unwind_Context *context)
     312  {
     313    return (_Unwind_Ptr) context->fc;
     314  }
     315  
     316  
     317  /* Play games with unwind symbols so that we can have call frame
     318     and sjlj symbols in the same shared library.  Not that you can
     319     use them simultaneously...  */
     320  #define _Unwind_RaiseException		_Unwind_SjLj_RaiseException
     321  #define _Unwind_ForcedUnwind		_Unwind_SjLj_ForcedUnwind
     322  #define _Unwind_Resume			_Unwind_SjLj_Resume
     323  #define _Unwind_Resume_or_Rethrow	_Unwind_SjLj_Resume_or_Rethrow
     324  
     325  #include "unwind.inc"
     326  
     327  #endif /* USING_SJLJ_EXCEPTIONS */