OpenMP/Fortran: Fix gfortran.dg/gomp/is_device_ptr-2.f90
[gcc.git] / libgcc / unwind-dw2.c
index 101a828b556df5bbb02d34a3e84f59042c2d1659..41af7e23f47602ec9a62673ad2c0f5d9e0a5e943 100644 (file)
@@ -1,5 +1,5 @@
 /* DWARF2 exception handling and frame unwind runtime interface routines.
-   Copyright (C) 1997-2013 Free Software Foundation, Inc.
+   Copyright (C) 1997-2021 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 
 #ifndef __USING_SJLJ_EXCEPTIONS__
 
-#ifndef STACK_GROWS_DOWNWARD
-#define STACK_GROWS_DOWNWARD 0
+#ifndef __LIBGCC_STACK_GROWS_DOWNWARD__
+#define __LIBGCC_STACK_GROWS_DOWNWARD__ 0
 #else
-#undef STACK_GROWS_DOWNWARD
-#define STACK_GROWS_DOWNWARD 1
+#undef __LIBGCC_STACK_GROWS_DOWNWARD__
+#define __LIBGCC_STACK_GROWS_DOWNWARD__ 1
 #endif
 
 /* Dwarf frame registers used for pre gcc 3.0 compiled glibc.  */
 #ifndef PRE_GCC3_DWARF_FRAME_REGISTERS
-#define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS
+#define PRE_GCC3_DWARF_FRAME_REGISTERS __LIBGCC_DWARF_FRAME_REGISTERS__
 #endif
 
-#ifndef DWARF_REG_TO_UNWIND_COLUMN
-#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO)
-#endif
+/* ??? For the public function interfaces, we tend to gcc_assert that the
+   column numbers are in range.  For the dwarf2 unwind info this does happen,
+   although so far in a case that doesn't actually matter.
+
+   See PR49146, in which a call from x86_64 ms abi to x86_64 unix abi stores
+   the call-saved xmm registers and annotates them.  We havn't bothered
+   providing support for the xmm registers for the x86_64 port primarily
+   because the 64-bit windows targets don't use dwarf2 unwind, using sjlj or
+   SEH instead.  Adding the support for unix targets would generally be a
+   waste.  However, some runtime libraries supplied with ICC do contain such
+   an unorthodox transition, as well as the unwind info to match.  This loss
+   of register restoration doesn't matter in practice, because the exception
+   is caught in the native unix abi, where all of the xmm registers are 
+   call clobbered.
+
+   Ideally, we'd record some bit to notice when we're failing to restore some
+   register recorded in the unwind info, but to do that we need annotation on
+   the unix->ms abi edge, so that we know when the register data may be
+   discarded.  And since this edge is also within the ICC library, we're
+   unlikely to be able to get the new annotation.
+
+   Barring a magic solution to restore the ms abi defined 128-bit xmm registers
+   (as distictly opposed to the full runtime width) without causing extra
+   overhead for normal unix abis, the best solution seems to be to simply
+   ignore unwind data for unknown columns.  */
+
+#define UNWIND_COLUMN_IN_RANGE(x) \
+    __builtin_expect((x) <= __LIBGCC_DWARF_FRAME_REGISTERS__, 1)
 
 #ifdef REG_VALUE_IN_UNWIND_CONTEXT
 typedef _Unwind_Word _Unwind_Context_Reg_Val;
@@ -102,7 +127,7 @@ _Unwind_Get_Unwind_Context_Reg_Val (_Unwind_Word val)
    to its caller.  */
 struct _Unwind_Context
 {
-  _Unwind_Context_Reg_Val reg[DWARF_FRAME_REGISTERS+1];
+  _Unwind_Context_Reg_Val reg[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
   void *cfa;
   void *ra;
   void *lsda;
@@ -111,16 +136,19 @@ struct _Unwind_Context
 #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
   /* Context which has version/args_size/by_value fields.  */
 #define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
+  /* Bit reserved on AArch64, return address has been signed with A or B
+     key.  */
+#define RA_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1)
   _Unwind_Word flags;
   /* 0 for now, can be increased when further fields are added to
      struct _Unwind_Context.  */
   _Unwind_Word version;
   _Unwind_Word args_size;
-  char by_value[DWARF_FRAME_REGISTERS+1];
+  char by_value[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
 };
 
 /* Byte size of every register managed by these routines.  */
-static unsigned char dwarf_reg_size_table[DWARF_FRAME_REGISTERS+1];
+static unsigned char dwarf_reg_size_table[__LIBGCC_DWARF_FRAME_REGISTERS__+1];
 
 \f
 /* Read unaligned data from the instruction buffer.  */
@@ -189,20 +217,20 @@ _Unwind_IsExtendedContext (struct _Unwind_Context *context)
          || (context->flags & EXTENDED_CONTEXT_BIT));
 }
 \f
-/* Get the value of register INDEX as saved in CONTEXT.  */
+/* Get the value of register REGNO as saved in CONTEXT.  */
 
 inline _Unwind_Word
-_Unwind_GetGR (struct _Unwind_Context *context, int index)
+_Unwind_GetGR (struct _Unwind_Context *context, int regno)
 {
-  int size;
+  int size, index;
   _Unwind_Context_Reg_Val val;
 
 #ifdef DWARF_ZERO_REG
-  if (index == DWARF_ZERO_REG)
+  if (regno == DWARF_ZERO_REG)
     return 0;
 #endif
 
-  index = DWARF_REG_TO_UNWIND_COLUMN (index);
+  index = DWARF_REG_TO_UNWIND_COLUMN (regno);
   gcc_assert (index < (int) sizeof(dwarf_reg_size_table));
   size = dwarf_reg_size_table[index];
   val = context->reg[index];
@@ -210,6 +238,14 @@ _Unwind_GetGR (struct _Unwind_Context *context, int index)
   if (_Unwind_IsExtendedContext (context) && context->by_value[index])
     return _Unwind_Get_Unwind_Word (val);
 
+#ifdef DWARF_LAZY_REGISTER_VALUE
+  {
+    _Unwind_Word value;
+    if (DWARF_LAZY_REGISTER_VALUE (regno, &value))
+      return value;
+  }
+#endif
+
   /* This will segfault if the register hasn't been saved.  */
   if (size == sizeof(_Unwind_Ptr))
     return * (_Unwind_Ptr *) (_Unwind_Internal_Ptr) val;
@@ -467,6 +503,11 @@ extract_cie_info (const struct dwarf_cie *cie, struct _Unwind_Context *context,
          fs->signal_frame = 1;
          aug += 1;
        }
+      /* aarch64 B-key pointer authentication.  */
+      else if (aug[0] == 'B')
+       {
+         aug += 1;
+      }
 
       /* Otherwise we have an unknown augmentation string.
         Bail unless we saw a 'z' prefix.  */
@@ -939,14 +980,19 @@ execute_cfa_program (const unsigned char *insn_ptr,
          reg = insn & 0x3f;
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Sword) utmp * fs->data_align;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_OFFSET;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+             fs->regs.reg[reg].loc.offset = offset;
+           }
        }
       else if ((insn & 0xc0) == DW_CFA_restore)
        {
          reg = insn & 0x3f;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_UNSAVED;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           fs->regs.reg[reg].how = REG_UNSAVED;
        }
       else switch (insn)
        {
@@ -977,26 +1023,35 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Sword) utmp * fs->data_align;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_OFFSET;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+             fs->regs.reg[reg].loc.offset = offset;
+           }
          break;
 
        case DW_CFA_restore_extended:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          /* FIXME, this is wrong; the CIE might have said that the
             register was saved somewhere.  */
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           fs->regs.reg[reg].how = REG_UNSAVED;
          break;
 
        case DW_CFA_same_value:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNSAVED;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           fs->regs.reg[reg].how = REG_UNSAVED;
          break;
 
        case DW_CFA_undefined:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN(reg)].how = REG_UNDEFINED;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           fs->regs.reg[reg].how = REG_UNDEFINED;
          break;
 
        case DW_CFA_nop:
@@ -1007,9 +1062,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
            _uleb128_t reg2;
            insn_ptr = read_uleb128 (insn_ptr, &reg);
            insn_ptr = read_uleb128 (insn_ptr, &reg2);
-           fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_REG;
-           fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.reg =
-             (_Unwind_Word)reg2;
+           reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+           if (UNWIND_COLUMN_IN_RANGE (reg))
+             {
+               fs->regs.reg[reg].how = REG_SAVED_REG;
+               fs->regs.reg[reg].loc.reg = (_Unwind_Word)reg2;
+             }
          }
          break;
 
@@ -1067,8 +1125,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
 
        case DW_CFA_expression:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how = REG_SAVED_EXP;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_EXP;
+             fs->regs.reg[reg].loc.exp = insn_ptr;
+           }
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          insn_ptr += utmp;
          break;
@@ -1078,9 +1140,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_sleb128 (insn_ptr, &stmp);
          offset = stmp * fs->data_align;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_OFFSET;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+             fs->regs.reg[reg].loc.offset = offset;
+           }
          break;
 
        case DW_CFA_def_cfa_sf:
@@ -1103,36 +1168,52 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Sword) utmp * fs->data_align;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_VAL_OFFSET;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_VAL_OFFSET;
+             fs->regs.reg[reg].loc.offset = offset;
+           }
          break;
 
        case DW_CFA_val_offset_sf:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_sleb128 (insn_ptr, &stmp);
          offset = stmp * fs->data_align;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_VAL_OFFSET;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = offset;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_VAL_OFFSET;
+             fs->regs.reg[reg].loc.offset = offset;
+           }
          break;
 
        case DW_CFA_val_expression:
          insn_ptr = read_uleb128 (insn_ptr, &reg);
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_VAL_EXP;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.exp = insn_ptr;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_VAL_EXP;
+             fs->regs.reg[reg].loc.exp = insn_ptr;
+           }
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          insn_ptr += utmp;
          break;
 
        case DW_CFA_GNU_window_save:
+#if defined (__aarch64__) && !defined (__ILP32__)
+         /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
+            return address signing status.  */
+         fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1;
+#else
          /* ??? Hardcoded for SPARC register window configuration.  */
-         for (reg = 16; reg < 32; ++reg)
-           {
-             fs->regs.reg[reg].how = REG_SAVED_OFFSET;
-             fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
-           }
+         if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
+           for (reg = 16; reg < 32; ++reg)
+             {
+               fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+               fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
+             }
+#endif
          break;
 
        case DW_CFA_GNU_args_size:
@@ -1146,9 +1227,12 @@ execute_cfa_program (const unsigned char *insn_ptr,
          insn_ptr = read_uleb128 (insn_ptr, &reg);
          insn_ptr = read_uleb128 (insn_ptr, &utmp);
          offset = (_Unwind_Word) utmp * fs->data_align;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].how
-           = REG_SAVED_OFFSET;
-         fs->regs.reg[DWARF_REG_TO_UNWIND_COLUMN (reg)].loc.offset = -offset;
+         reg = DWARF_REG_TO_UNWIND_COLUMN (reg);
+         if (UNWIND_COLUMN_IN_RANGE (reg))
+           {
+             fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+             fs->regs.reg[reg].loc.offset = -offset;
+           }
          break;
 
        default:
@@ -1318,7 +1402,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
   void *cfa;
   long i;
 
-#ifdef EH_RETURN_STACKADJ_RTX
+#ifdef __LIBGCC_EH_RETURN_STACKADJ_RTX__
   /* Special handling here: Many machines do not use a frame pointer,
      and track the CFA only through offsets from the stack pointer from
      one frame to the next.  In this case, the stack pointer is never
@@ -1366,7 +1450,7 @@ uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
   context->cfa = cfa;
 
   /* Compute the addresses of all registers saved in this frame.  */
-  for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
+  for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i)
     switch (fs->regs.reg[i].how)
       {
       case REG_UNSAVED:
@@ -1451,10 +1535,18 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
        stack frame.  */
     context->ra = 0;
   else
-    /* Compute the return address now, since the return address column
-       can change from frame to frame.  */
-    context->ra = __builtin_extract_return_addr
-      (_Unwind_GetPtr (context, fs->retaddr_column));
+    {
+      /* Compute the return address now, since the return address column
+        can change from frame to frame.  */
+      void *ret_addr;
+#ifdef MD_DEMANGLE_RETURN_ADDR
+      _Unwind_Word ra = _Unwind_GetGR (context, fs->retaddr_column);
+      ret_addr = MD_DEMANGLE_RETURN_ADDR (context, fs, ra);
+#else
+      ret_addr = _Unwind_GetPtr (context, fs->retaddr_column);
+#endif
+      context->ra = __builtin_extract_return_addr (ret_addr);
+    }
 }
 
 static void
@@ -1548,14 +1640,18 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
 
 /* Install TARGET into CURRENT so that we can return to it.  This is a
    macro because __builtin_eh_return must be invoked in the context of
-   our caller.  */
+   our caller.  FRAMES is a number of frames to be unwind.
+   _Unwind_Frames_Extra is a macro to do additional work during unwinding
+   if needed, for example shadow stack pointer adjustment for Intel CET
+   technology.  */
 
-#define uw_install_context(CURRENT, TARGET)                            \
+#define uw_install_context(CURRENT, TARGET, FRAMES)                    \
   do                                                                   \
     {                                                                  \
       long offset = uw_install_context_1 ((CURRENT), (TARGET));                \
       void *handler = __builtin_frob_return_addr ((TARGET)->ra);       \
       _Unwind_DebugHook ((TARGET)->cfa, handler);                      \
+      _Unwind_Frames_Extra (FRAMES);                                   \
       __builtin_eh_return (offset, handler);                           \
     }                                                                  \
   while (0)
@@ -1572,7 +1668,7 @@ uw_install_context_1 (struct _Unwind_Context *current,
   if (!_Unwind_GetGRPtr (target, __builtin_dwarf_sp_column ()))
     _Unwind_SetSpColumn (target, target->cfa, &sp_slot);
 
-  for (i = 0; i < DWARF_FRAME_REGISTERS; ++i)
+  for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__; ++i)
     {
       void *c = (void *) (_Unwind_Internal_Ptr) current->reg[i];
       void *t = (void *) (_Unwind_Internal_Ptr)target->reg[i];
@@ -1608,7 +1704,7 @@ uw_install_context_1 (struct _Unwind_Context *current,
       target_cfa = _Unwind_GetPtr (target, __builtin_dwarf_sp_column ());
 
       /* We adjust SP by the difference between CURRENT and TARGET's CFA.  */
-      if (STACK_GROWS_DOWNWARD)
+      if (__LIBGCC_STACK_GROWS_DOWNWARD__)
        return target_cfa - current->cfa + target->args_size;
       else
        return current->cfa - target_cfa - target->args_size;
@@ -1622,7 +1718,7 @@ uw_identify_context (struct _Unwind_Context *context)
   /* The CFA is not sufficient to disambiguate the context of a function
      interrupted by a signal before establishing its frame and the context
      of the signal itself.  */
-  if (STACK_GROWS_DOWNWARD)
+  if (__LIBGCC_STACK_GROWS_DOWNWARD__)
     return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context);
   else
     return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context);