Home | History | Annotate | Line # | Download | only in sparc
linux-unwind.h revision 1.1.1.3
      1      1.1  mrg /* DWARF2 EH unwinding support for SPARC Linux.
      2  1.1.1.3  mrg    Copyright (C) 2004-2016 Free Software Foundation, Inc.
      3      1.1  mrg 
      4      1.1  mrg This file is part of GCC.
      5      1.1  mrg 
      6      1.1  mrg GCC is free software; you can redistribute it and/or modify
      7      1.1  mrg it under the terms of the GNU General Public License as published by
      8      1.1  mrg the Free Software Foundation; either version 3, or (at your option)
      9      1.1  mrg any later version.
     10      1.1  mrg 
     11      1.1  mrg GCC is distributed in the hope that it will be useful,
     12      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  mrg GNU General Public License for more details.
     15      1.1  mrg 
     16      1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     17      1.1  mrg permissions described in the GCC Runtime Library Exception, version
     18      1.1  mrg 3.1, as published by the Free Software Foundation.
     19      1.1  mrg 
     20      1.1  mrg You should have received a copy of the GNU General Public License and
     21      1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     22      1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23      1.1  mrg <http://www.gnu.org/licenses/>.  */
     24      1.1  mrg 
     25      1.1  mrg /* Do code reading to identify a signal frame, and set the frame
     26      1.1  mrg    state data appropriately.  See unwind-dw2.c for the structs.  */
     27      1.1  mrg 
     28      1.1  mrg #if defined(__arch64__)
     29      1.1  mrg 
     30      1.1  mrg #undef STACK_BIAS
     31      1.1  mrg #define STACK_BIAS 2047
     32      1.1  mrg 
     33      1.1  mrg /* 64-bit SPARC version */
     34      1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
     35      1.1  mrg 
     36      1.1  mrg static _Unwind_Reason_Code
     37      1.1  mrg sparc64_fallback_frame_state (struct _Unwind_Context *context,
     38      1.1  mrg 			      _Unwind_FrameState *fs)
     39      1.1  mrg {
     40      1.1  mrg   unsigned int *pc = context->ra;
     41      1.1  mrg   long this_cfa = (long) context->cfa;
     42      1.1  mrg   long new_cfa, ra_location, shifted_ra_location;
     43      1.1  mrg   long regs_off, fpu_save_off;
     44      1.1  mrg   long fpu_save;
     45      1.1  mrg   int i;
     46      1.1  mrg 
     47      1.1  mrg   if (pc[0] != 0x82102065	/* mov NR_rt_sigreturn, %g1 */
     48      1.1  mrg       || pc[1] != 0x91d0206d)	/* ta 0x6d */
     49      1.1  mrg     return _URC_END_OF_STACK;
     50      1.1  mrg 
     51      1.1  mrg   regs_off = 192 + 128;
     52      1.1  mrg   fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
     53      1.1  mrg 
     54      1.1  mrg   new_cfa = *(long *)(this_cfa + regs_off + (14 * 8));
     55      1.1  mrg   /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
     56      1.1  mrg   new_cfa += STACK_BIAS;
     57      1.1  mrg   fpu_save = *(long *)(this_cfa + fpu_save_off);
     58      1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
     59      1.1  mrg   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
     60      1.1  mrg   fs->regs.cfa_offset = new_cfa - this_cfa;
     61      1.1  mrg 
     62      1.1  mrg   for (i = 1; i < 16; i++)
     63      1.1  mrg     {
     64      1.1  mrg       /* We never restore %sp as everything is purely CFA-based.  */
     65      1.1  mrg       if ((unsigned int) i == __builtin_dwarf_sp_column ())
     66      1.1  mrg 	continue;
     67      1.1  mrg 
     68      1.1  mrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
     69      1.1  mrg       fs->regs.reg[i].loc.offset
     70      1.1  mrg 	= this_cfa + regs_off + (i * 8) - new_cfa;
     71      1.1  mrg     }
     72      1.1  mrg   for (i = 0; i < 16; i++)
     73      1.1  mrg     {
     74      1.1  mrg       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
     75      1.1  mrg       fs->regs.reg[i + 16].loc.offset
     76      1.1  mrg 	= this_cfa + (i * 8) - new_cfa;
     77      1.1  mrg     }
     78      1.1  mrg   if (fpu_save)
     79      1.1  mrg     {
     80      1.1  mrg       for (i = 0; i < 64; i++)
     81      1.1  mrg 	{
     82      1.1  mrg 	  if (i > 32 && (i & 0x1))
     83      1.1  mrg 	    continue;
     84      1.1  mrg 	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
     85      1.1  mrg 	  fs->regs.reg[i + 32].loc.offset
     86      1.1  mrg 	    = fpu_save + (i * 4) - new_cfa;
     87      1.1  mrg 	}
     88      1.1  mrg     }
     89      1.1  mrg 
     90      1.1  mrg   /* State the rules to find the kernel's code "return address", which is
     91      1.1  mrg      the address of the active instruction when the signal was caught.
     92      1.1  mrg      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
     93      1.1  mrg      need to preventively subtract it from the purported return address.  */
     94      1.1  mrg   ra_location = this_cfa + regs_off + 17 * 8;
     95      1.1  mrg   shifted_ra_location = this_cfa + regs_off + 19 * 8; /* Y register */
     96      1.1  mrg   *(long *)shifted_ra_location = *(long *)ra_location - 8;
     97      1.1  mrg   fs->retaddr_column = 0;
     98      1.1  mrg   fs->regs.reg[0].how = REG_SAVED_OFFSET;
     99      1.1  mrg   fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
    100      1.1  mrg   fs->signal_frame = 1;
    101      1.1  mrg 
    102      1.1  mrg   return _URC_NO_REASON;
    103      1.1  mrg }
    104      1.1  mrg 
    105      1.1  mrg #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
    106      1.1  mrg 
    107      1.1  mrg static void
    108      1.1  mrg sparc64_frob_update_context (struct _Unwind_Context *context,
    109      1.1  mrg 			     _Unwind_FrameState *fs)
    110      1.1  mrg {
    111      1.1  mrg   /* The column of %sp contains the old CFA, not the old value of %sp.
    112      1.1  mrg      The CFA offset already comprises the stack bias so, when %sp is the
    113      1.1  mrg      CFA register, we must avoid counting the stack bias twice.  Do not
    114      1.1  mrg      do that for signal frames as the offset is artificial for them.  */
    115      1.1  mrg   if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
    116      1.1  mrg       && fs->regs.cfa_how == CFA_REG_OFFSET
    117      1.1  mrg       && fs->regs.cfa_offset != 0
    118      1.1  mrg       && !fs->signal_frame)
    119      1.1  mrg     {
    120      1.1  mrg       long i;
    121      1.1  mrg 
    122      1.1  mrg       context->cfa -= STACK_BIAS;
    123      1.1  mrg 
    124  1.1.1.2  mrg       for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i)
    125      1.1  mrg 	if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
    126      1.1  mrg 	  _Unwind_SetGRPtr (context, i,
    127      1.1  mrg 			    _Unwind_GetGRPtr (context, i) - STACK_BIAS);
    128      1.1  mrg     }
    129      1.1  mrg }
    130      1.1  mrg 
    131      1.1  mrg #else
    132      1.1  mrg 
    133      1.1  mrg /* 32-bit SPARC version */
    134      1.1  mrg #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
    135      1.1  mrg 
    136      1.1  mrg static _Unwind_Reason_Code
    137      1.1  mrg sparc_fallback_frame_state (struct _Unwind_Context *context,
    138      1.1  mrg 			    _Unwind_FrameState *fs)
    139      1.1  mrg {
    140      1.1  mrg   unsigned int *pc = context->ra;
    141      1.1  mrg   int this_cfa = (int) context->cfa;
    142      1.1  mrg   int new_cfa, ra_location, shifted_ra_location;
    143      1.1  mrg   int regs_off, fpu_save_off;
    144      1.1  mrg   int fpu_save;
    145      1.1  mrg   int old_style, i;
    146      1.1  mrg 
    147      1.1  mrg   if (pc[1] != 0x91d02010)	/* ta 0x10 */
    148      1.1  mrg     return _URC_END_OF_STACK;
    149      1.1  mrg 
    150      1.1  mrg   if (pc[0] == 0x821020d8)	/* mov NR_sigreturn, %g1 */
    151      1.1  mrg     old_style = 1;
    152      1.1  mrg   else if (pc[0] == 0x82102065)	/* mov NR_rt_sigreturn, %g1 */
    153      1.1  mrg     old_style = 0;
    154      1.1  mrg   else
    155      1.1  mrg     return _URC_END_OF_STACK;
    156      1.1  mrg 
    157      1.1  mrg   if (old_style)
    158      1.1  mrg     {
    159      1.1  mrg       regs_off = 96;
    160      1.1  mrg       fpu_save_off = regs_off + (4 * 4) + (16 * 4);
    161      1.1  mrg     }
    162      1.1  mrg   else
    163      1.1  mrg     {
    164      1.1  mrg       regs_off = 96 + 128;
    165      1.1  mrg       fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
    166      1.1  mrg     }
    167      1.1  mrg 
    168      1.1  mrg   new_cfa = *(int *)(this_cfa + regs_off + (4 * 4) + (14 * 4));
    169      1.1  mrg   fpu_save = *(int *)(this_cfa + fpu_save_off);
    170      1.1  mrg   fs->regs.cfa_how = CFA_REG_OFFSET;
    171      1.1  mrg   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
    172      1.1  mrg   fs->regs.cfa_offset = new_cfa - this_cfa;
    173      1.1  mrg 
    174      1.1  mrg   for (i = 1; i < 16; i++)
    175      1.1  mrg     {
    176      1.1  mrg       /* We never restore %sp as everything is purely CFA-based.  */
    177      1.1  mrg       if ((unsigned int) i == __builtin_dwarf_sp_column ())
    178      1.1  mrg 	continue;
    179      1.1  mrg 
    180      1.1  mrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
    181      1.1  mrg       fs->regs.reg[i].loc.offset
    182      1.1  mrg 	= this_cfa + regs_off + (4 * 4) + (i * 4) - new_cfa;
    183      1.1  mrg     }
    184      1.1  mrg   for (i = 0; i < 16; i++)
    185      1.1  mrg     {
    186      1.1  mrg       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
    187      1.1  mrg       fs->regs.reg[i + 16].loc.offset
    188      1.1  mrg 	= this_cfa + (i * 4) - new_cfa;
    189      1.1  mrg     }
    190      1.1  mrg   if (fpu_save)
    191      1.1  mrg     {
    192      1.1  mrg       for (i = 0; i < 32; i++)
    193      1.1  mrg 	{
    194      1.1  mrg 	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
    195      1.1  mrg 	  fs->regs.reg[i + 32].loc.offset
    196      1.1  mrg 	    = fpu_save + (i * 4) - new_cfa;
    197      1.1  mrg 	}
    198      1.1  mrg     }
    199      1.1  mrg 
    200      1.1  mrg   /* State the rules to find the kernel's code "return address", which is
    201      1.1  mrg      the address of the active instruction when the signal was caught.
    202      1.1  mrg      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
    203      1.1  mrg      need to preventively subtract it from the purported return address.  */
    204      1.1  mrg   ra_location = this_cfa + regs_off + 4;
    205      1.1  mrg   shifted_ra_location = this_cfa + regs_off + 3 * 4; /* Y register */
    206      1.1  mrg   *(int *)shifted_ra_location = *(int *)ra_location - 8;
    207      1.1  mrg   fs->retaddr_column = 0;
    208      1.1  mrg   fs->regs.reg[0].how = REG_SAVED_OFFSET;
    209      1.1  mrg   fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
    210      1.1  mrg   fs->signal_frame = 1;
    211      1.1  mrg 
    212      1.1  mrg   return _URC_NO_REASON;
    213      1.1  mrg }
    214      1.1  mrg 
    215      1.1  mrg #endif
    216