xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/sparc/linux-unwind.h (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg /* DWARF2 EH unwinding support for SPARC Linux.
2*8feb0f0bSmrg    Copyright (C) 2004-2020 Free Software Foundation, Inc.
336ac495dSmrg 
436ac495dSmrg This file is part of GCC.
536ac495dSmrg 
636ac495dSmrg GCC is free software; you can redistribute it and/or modify
736ac495dSmrg it under the terms of the GNU General Public License as published by
836ac495dSmrg the Free Software Foundation; either version 3, or (at your option)
936ac495dSmrg any later version.
1036ac495dSmrg 
1136ac495dSmrg GCC is distributed in the hope that it will be useful,
1236ac495dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
1336ac495dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1436ac495dSmrg GNU General Public License for more details.
1536ac495dSmrg 
1636ac495dSmrg Under Section 7 of GPL version 3, you are granted additional
1736ac495dSmrg permissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg 3.1, as published by the Free Software Foundation.
1936ac495dSmrg 
2036ac495dSmrg You should have received a copy of the GNU General Public License and
2136ac495dSmrg a copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2336ac495dSmrg <http://www.gnu.org/licenses/>.  */
2436ac495dSmrg 
2536ac495dSmrg /* Do code reading to identify a signal frame, and set the frame
2636ac495dSmrg    state data appropriately.  See unwind-dw2.c for the structs.  */
2736ac495dSmrg 
2836ac495dSmrg #if defined(__arch64__)
2936ac495dSmrg 
3036ac495dSmrg #undef STACK_BIAS
3136ac495dSmrg #define STACK_BIAS 2047
3236ac495dSmrg 
3336ac495dSmrg /* 64-bit SPARC version */
3436ac495dSmrg #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
3536ac495dSmrg 
3636ac495dSmrg static _Unwind_Reason_Code
sparc64_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)3736ac495dSmrg sparc64_fallback_frame_state (struct _Unwind_Context *context,
3836ac495dSmrg 			      _Unwind_FrameState *fs)
3936ac495dSmrg {
4036ac495dSmrg   unsigned int *pc = context->ra;
4136ac495dSmrg   long this_cfa = (long) context->cfa;
4236ac495dSmrg   long new_cfa, ra_location, shifted_ra_location;
4336ac495dSmrg   long regs_off, fpu_save_off;
4436ac495dSmrg   long fpu_save;
4536ac495dSmrg   int i;
4636ac495dSmrg 
4736ac495dSmrg   if (pc[0] != 0x82102065	/* mov NR_rt_sigreturn, %g1 */
4836ac495dSmrg       || pc[1] != 0x91d0206d)	/* ta 0x6d */
4936ac495dSmrg     return _URC_END_OF_STACK;
5036ac495dSmrg 
5136ac495dSmrg   regs_off = 192 + 128;
5236ac495dSmrg   fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
5336ac495dSmrg 
5436ac495dSmrg   new_cfa = *(long *)(this_cfa + regs_off + (14 * 8));
5536ac495dSmrg   /* The frame address is %sp + STACK_BIAS in 64-bit mode.  */
5636ac495dSmrg   new_cfa += STACK_BIAS;
5736ac495dSmrg   fpu_save = *(long *)(this_cfa + fpu_save_off);
5836ac495dSmrg   fs->regs.cfa_how = CFA_REG_OFFSET;
5936ac495dSmrg   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
6036ac495dSmrg   fs->regs.cfa_offset = new_cfa - this_cfa;
6136ac495dSmrg 
6236ac495dSmrg   for (i = 1; i < 16; i++)
6336ac495dSmrg     {
6436ac495dSmrg       /* We never restore %sp as everything is purely CFA-based.  */
6536ac495dSmrg       if ((unsigned int) i == __builtin_dwarf_sp_column ())
6636ac495dSmrg 	continue;
6736ac495dSmrg 
6836ac495dSmrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
6936ac495dSmrg       fs->regs.reg[i].loc.offset
7036ac495dSmrg 	= this_cfa + regs_off + (i * 8) - new_cfa;
7136ac495dSmrg     }
7236ac495dSmrg   for (i = 0; i < 16; i++)
7336ac495dSmrg     {
7436ac495dSmrg       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
7536ac495dSmrg       fs->regs.reg[i + 16].loc.offset
7636ac495dSmrg 	= this_cfa + (i * 8) - new_cfa;
7736ac495dSmrg     }
7836ac495dSmrg   if (fpu_save)
7936ac495dSmrg     {
8036ac495dSmrg       for (i = 0; i < 64; i++)
8136ac495dSmrg 	{
8236ac495dSmrg 	  if (i > 32 && (i & 0x1))
8336ac495dSmrg 	    continue;
8436ac495dSmrg 	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
8536ac495dSmrg 	  fs->regs.reg[i + 32].loc.offset
8636ac495dSmrg 	    = fpu_save + (i * 4) - new_cfa;
8736ac495dSmrg 	}
8836ac495dSmrg     }
8936ac495dSmrg 
9036ac495dSmrg   /* State the rules to find the kernel's code "return address", which is
9136ac495dSmrg      the address of the active instruction when the signal was caught.
9236ac495dSmrg      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
9336ac495dSmrg      need to preventively subtract it from the purported return address.  */
9436ac495dSmrg   ra_location = this_cfa + regs_off + 17 * 8;
9536ac495dSmrg   shifted_ra_location = this_cfa + regs_off + 19 * 8; /* Y register */
9636ac495dSmrg   *(long *)shifted_ra_location = *(long *)ra_location - 8;
9736ac495dSmrg   fs->retaddr_column = 0;
9836ac495dSmrg   fs->regs.reg[0].how = REG_SAVED_OFFSET;
9936ac495dSmrg   fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
10036ac495dSmrg   fs->signal_frame = 1;
10136ac495dSmrg 
10236ac495dSmrg   return _URC_NO_REASON;
10336ac495dSmrg }
10436ac495dSmrg 
10536ac495dSmrg #define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context
10636ac495dSmrg 
10736ac495dSmrg static void
sparc64_frob_update_context(struct _Unwind_Context * context,_Unwind_FrameState * fs)10836ac495dSmrg sparc64_frob_update_context (struct _Unwind_Context *context,
10936ac495dSmrg 			     _Unwind_FrameState *fs)
11036ac495dSmrg {
11136ac495dSmrg   /* The column of %sp contains the old CFA, not the old value of %sp.
11236ac495dSmrg      The CFA offset already comprises the stack bias so, when %sp is the
11336ac495dSmrg      CFA register, we must avoid counting the stack bias twice.  Do not
11436ac495dSmrg      do that for signal frames as the offset is artificial for them.  */
11536ac495dSmrg   if (fs->regs.cfa_reg == __builtin_dwarf_sp_column ()
11636ac495dSmrg       && fs->regs.cfa_how == CFA_REG_OFFSET
11736ac495dSmrg       && fs->regs.cfa_offset != 0
11836ac495dSmrg       && !fs->signal_frame)
11936ac495dSmrg     {
12036ac495dSmrg       long i;
12136ac495dSmrg 
12236ac495dSmrg       context->cfa -= STACK_BIAS;
12336ac495dSmrg 
12436ac495dSmrg       for (i = 0; i < __LIBGCC_DWARF_FRAME_REGISTERS__ + 1; ++i)
12536ac495dSmrg 	if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
12636ac495dSmrg 	  _Unwind_SetGRPtr (context, i,
12736ac495dSmrg 			    _Unwind_GetGRPtr (context, i) - STACK_BIAS);
12836ac495dSmrg     }
12936ac495dSmrg }
13036ac495dSmrg 
13136ac495dSmrg #else
13236ac495dSmrg 
13336ac495dSmrg /* 32-bit SPARC version */
13436ac495dSmrg #define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
13536ac495dSmrg 
13636ac495dSmrg static _Unwind_Reason_Code
sparc_fallback_frame_state(struct _Unwind_Context * context,_Unwind_FrameState * fs)13736ac495dSmrg sparc_fallback_frame_state (struct _Unwind_Context *context,
13836ac495dSmrg 			    _Unwind_FrameState *fs)
13936ac495dSmrg {
14036ac495dSmrg   unsigned int *pc = context->ra;
14136ac495dSmrg   int this_cfa = (int) context->cfa;
14236ac495dSmrg   int new_cfa, ra_location, shifted_ra_location;
14336ac495dSmrg   int regs_off, fpu_save_off;
14436ac495dSmrg   int fpu_save;
14536ac495dSmrg   int old_style, i;
14636ac495dSmrg 
14736ac495dSmrg   if (pc[1] != 0x91d02010)	/* ta 0x10 */
14836ac495dSmrg     return _URC_END_OF_STACK;
14936ac495dSmrg 
15036ac495dSmrg   if (pc[0] == 0x821020d8)	/* mov NR_sigreturn, %g1 */
15136ac495dSmrg     old_style = 1;
15236ac495dSmrg   else if (pc[0] == 0x82102065)	/* mov NR_rt_sigreturn, %g1 */
15336ac495dSmrg     old_style = 0;
15436ac495dSmrg   else
15536ac495dSmrg     return _URC_END_OF_STACK;
15636ac495dSmrg 
15736ac495dSmrg   if (old_style)
15836ac495dSmrg     {
15936ac495dSmrg       regs_off = 96;
16036ac495dSmrg       fpu_save_off = regs_off + (4 * 4) + (16 * 4);
16136ac495dSmrg     }
16236ac495dSmrg   else
16336ac495dSmrg     {
16436ac495dSmrg       regs_off = 96 + 128;
16536ac495dSmrg       fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
16636ac495dSmrg     }
16736ac495dSmrg 
16836ac495dSmrg   new_cfa = *(int *)(this_cfa + regs_off + (4 * 4) + (14 * 4));
16936ac495dSmrg   fpu_save = *(int *)(this_cfa + fpu_save_off);
17036ac495dSmrg   fs->regs.cfa_how = CFA_REG_OFFSET;
17136ac495dSmrg   fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
17236ac495dSmrg   fs->regs.cfa_offset = new_cfa - this_cfa;
17336ac495dSmrg 
17436ac495dSmrg   for (i = 1; i < 16; i++)
17536ac495dSmrg     {
17636ac495dSmrg       /* We never restore %sp as everything is purely CFA-based.  */
17736ac495dSmrg       if ((unsigned int) i == __builtin_dwarf_sp_column ())
17836ac495dSmrg 	continue;
17936ac495dSmrg 
18036ac495dSmrg       fs->regs.reg[i].how = REG_SAVED_OFFSET;
18136ac495dSmrg       fs->regs.reg[i].loc.offset
18236ac495dSmrg 	= this_cfa + regs_off + (4 * 4) + (i * 4) - new_cfa;
18336ac495dSmrg     }
18436ac495dSmrg   for (i = 0; i < 16; i++)
18536ac495dSmrg     {
18636ac495dSmrg       fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
18736ac495dSmrg       fs->regs.reg[i + 16].loc.offset
18836ac495dSmrg 	= this_cfa + (i * 4) - new_cfa;
18936ac495dSmrg     }
19036ac495dSmrg   if (fpu_save)
19136ac495dSmrg     {
19236ac495dSmrg       for (i = 0; i < 32; i++)
19336ac495dSmrg 	{
19436ac495dSmrg 	  fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
19536ac495dSmrg 	  fs->regs.reg[i + 32].loc.offset
19636ac495dSmrg 	    = fpu_save + (i * 4) - new_cfa;
19736ac495dSmrg 	}
19836ac495dSmrg     }
19936ac495dSmrg 
20036ac495dSmrg   /* State the rules to find the kernel's code "return address", which is
20136ac495dSmrg      the address of the active instruction when the signal was caught.
20236ac495dSmrg      On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we
20336ac495dSmrg      need to preventively subtract it from the purported return address.  */
20436ac495dSmrg   ra_location = this_cfa + regs_off + 4;
20536ac495dSmrg   shifted_ra_location = this_cfa + regs_off + 3 * 4; /* Y register */
20636ac495dSmrg   *(int *)shifted_ra_location = *(int *)ra_location - 8;
20736ac495dSmrg   fs->retaddr_column = 0;
20836ac495dSmrg   fs->regs.reg[0].how = REG_SAVED_OFFSET;
20936ac495dSmrg   fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa;
21036ac495dSmrg   fs->signal_frame = 1;
21136ac495dSmrg 
21236ac495dSmrg   return _URC_NO_REASON;
21336ac495dSmrg }
21436ac495dSmrg 
21536ac495dSmrg #endif
216