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