1/* DWARF2 EH unwinding support for S/390 Linux. 2 Copyright (C) 2004-2020 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16Under Section 7 of GPL version 3, you are granted additional 17permissions described in the GCC Runtime Library Exception, version 183.1, as published by the Free Software Foundation. 19 20You should have received a copy of the GNU General Public License and 21a copy of the GCC Runtime Library Exception along with this program; 22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23<http://www.gnu.org/licenses/>. */ 24 25/* Do code reading to identify a signal frame, and set the frame 26 state data appropriately. See unwind-dw2.c for the structs. */ 27 28#define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state 29 30static _Unwind_Reason_Code 31s390_fallback_frame_state (struct _Unwind_Context *context, 32 _Unwind_FrameState *fs) 33{ 34 static const unsigned char dwarf_to_fpr_map[16] = 35 { 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15 }; 36 unsigned char *pc = context->ra; 37 long new_cfa; 38 int i; 39 40 typedef struct 41 { 42 unsigned long psw_mask; 43 unsigned long psw_addr; 44 unsigned long gprs[16]; 45 unsigned int acrs[16]; 46 unsigned int fpc; 47 unsigned int __pad; 48 double fprs[16]; 49 } __attribute__ ((__aligned__ (8))) sigregs_; 50 51 sigregs_ *regs; 52 int *signo; 53 54 /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn */ 55 if (pc[0] != 0x0a || (pc[1] != 119 && pc[1] != 173)) 56 return _URC_END_OF_STACK; 57 58 /* Legacy frames: 59 old signal mask (8 bytes) 60 pointer to sigregs (8 bytes) - points always to next location 61 sigregs 62 retcode 63 This frame layout was used on kernels < 2.6.9 for non-RT frames, 64 and on kernels < 2.4.13 for RT frames as well. Note that we need 65 to look at RA to detect this layout -- this means that if you use 66 sa_restorer to install a different signal restorer on a legacy 67 kernel, unwinding from signal frames will not work. */ 68 if (context->ra == context->cfa + 16 + sizeof (sigregs_)) 69 { 70 regs = (sigregs_ *)(context->cfa + 16); 71 signo = NULL; 72 } 73 74 /* New-style RT frame: 75 retcode + alignment (8 bytes) 76 siginfo (128 bytes) 77 ucontext (contains sigregs) */ 78 else if (pc[1] == 173 /* __NR_rt_sigreturn */) 79 { 80 struct ucontext_ 81 { 82 unsigned long uc_flags; 83 struct ucontext_ *uc_link; 84 unsigned long uc_stack[3]; 85 sigregs_ uc_mcontext; 86 } *uc = context->cfa + 8 + 128; 87 88 regs = &uc->uc_mcontext; 89 signo = context->cfa + sizeof(long); 90 } 91 92 /* New-style non-RT frame: 93 old signal mask (8 bytes) 94 pointer to sigregs (followed by signal number) */ 95 else 96 { 97 regs = *(sigregs_ **)(context->cfa + 8); 98 signo = (int *)(regs + 1); 99 } 100 101 new_cfa = regs->gprs[15] + 16*sizeof(long) + 32; 102 fs->regs.cfa_how = CFA_REG_OFFSET; 103 fs->regs.cfa_reg = 15; 104 fs->regs.cfa_offset = 105 new_cfa - (long) context->cfa + 16*sizeof(long) + 32; 106 107 for (i = 0; i < 16; i++) 108 { 109 fs->regs.reg[i].how = REG_SAVED_OFFSET; 110 fs->regs.reg[i].loc.offset = 111 (long)®s->gprs[i] - new_cfa; 112 } 113 for (i = 0; i < 16; i++) 114 { 115 fs->regs.reg[16+i].how = REG_SAVED_OFFSET; 116 fs->regs.reg[16+i].loc.offset = 117 (long)®s->fprs[dwarf_to_fpr_map[i]] - new_cfa; 118 } 119 120 /* Load return addr from PSW into dummy register 32. */ 121 122 fs->regs.reg[32].how = REG_SAVED_OFFSET; 123 fs->regs.reg[32].loc.offset = (long)®s->psw_addr - new_cfa; 124 fs->retaddr_column = 32; 125 /* SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr 126 after the faulting instruction rather than before it. 127 Don't set FS->signal_frame in that case. */ 128 if (!signo || (*signo != 4 && *signo != 5 && *signo != 8)) 129 fs->signal_frame = 1; 130 131 return _URC_NO_REASON; 132} 133