summaryrefslogtreecommitdiff
path: root/gcc/config/s390/linux-unwind.h
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2004-09-08 00:17:19 +0000
committerAlan Modra <amodra@gcc.gnu.org>2004-09-08 09:47:19 +0930
commit8662eb14c0ef6531d7086ec08f5e52b87c472ede (patch)
treef6927bd90fe84c682dd04619d255d6355aac36d5 /gcc/config/s390/linux-unwind.h
parenta9e10feb68d5cbc371f581ebca229043b7854fe5 (diff)
downloadgcc-8662eb14c0ef6531d7086ec08f5e52b87c472ede.tar.gz
tm.texi (MD_UNWIND_SUPPORT): Document.
* doc/tm.texi (MD_UNWIND_SUPPORT): Document. (MD_FALLBACK_FRAME_STATE_FOR): Update. * unwind-dw2.c (MD_UNWIND_SUPPORT): #include if defined. (uw_frame_state_for): Adjust MD_FALLBACK_FRAME_STATE_FOR invocation. (MD_FROB_UPDATE_CONTEXT): Remove default. (uw_update_context_1): Instead #ifdef invocation. * config/ia64/unwind-ia64.c (MD_UNWIND_SUPPORT): #include if defined. (uw_frame_state_for): Adjust MD_FALLBACK_FRAME_STATE_FOR invocation. * config/alpha/gnu.h (MD_FALLBACK_FRAME_STATE_FOR): Don't undef. (MD_UNWIND_SUPPORT): Undefine this instead. * config/i386/gnu.h: Likewise. * config/alpha/linux-unwind.h: New file, macro converted to function, extracted from.. * config/alpha/linux.h (MD_FALLBACK_FRAME_STATE_FOR): ..this. (MD_UNWIND_SUPPORT): Define. * config/alpha/vms-unwind.h, config/alpha/vms.h: Likewise. * config/i386/linux-unwind.h, config/i386/linux.h, config/i386/linux64.h: Likewise. * config/ia64/linux-unwind.h, config/ia64/linux.h: Likewise. MD_HANDLE_UNWABI too. * config/mips/linux-unwind.h, config/mips/linux.h: Likewise. * config/pa/linux-unwind.h, config/pa/pa32-linux.h: Likewise. * config/rs6000/darwin-unwind.h, config/rs6000/darwin.h: Likewise. * config/s390/linux-unwind.h, config/s390/linux.h: Likewise. * config/sparc/linux-unwind.h, config/sparc/linux.h, config/sparc/linux64.h: Likewise. * config/sh/linux-unwind.h, config/sh/linux.h: Likewise, but merge SH_FALLBACK_FRAME_FLOAT_STATE into sh_fallback_frame_state. * config/rs6000/linux-unwind.h, config/rs6000/linux.h, config/rs6000/linux64.h: Likewise. Split out get_sigcontext function. Use ARG_POINTER_REGNUM for 32-bit temp reg too. From-SVN: r87167
Diffstat (limited to 'gcc/config/s390/linux-unwind.h')
-rw-r--r--gcc/config/s390/linux-unwind.h131
1 files changed, 131 insertions, 0 deletions
diff --git a/gcc/config/s390/linux-unwind.h b/gcc/config/s390/linux-unwind.h
new file mode 100644
index 00000000000..3713f1821a9
--- /dev/null
+++ b/gcc/config/s390/linux-unwind.h
@@ -0,0 +1,131 @@
+/* DWARF2 EH unwinding support for S/390 Linux.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+#define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
+
+static _Unwind_Reason_Code
+s390_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ unsigned char *pc = context->ra;
+ long new_cfa;
+ int i;
+
+ typedef struct
+ {
+ unsigned long psw_mask;
+ unsigned long psw_addr;
+ unsigned long gprs[16];
+ unsigned int acrs[16];
+ unsigned int fpc;
+ unsigned int __pad;
+ double fprs[16];
+ } __attribute__ ((__aligned__ (8))) sigregs_;
+
+ sigregs_ *regs;
+ int *signo = NULL;
+
+ /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn */
+ if (pc[0] != 0x0a || (pc[1] != 119 && pc[1] != 173))
+ return _URC_END_OF_STACK;
+
+ /* New-style RT frame:
+ retcode + alignment (8 bytes)
+ siginfo (128 bytes)
+ ucontext (contains sigregs) */
+ if (context->ra == context->cfa)
+ {
+ struct ucontext_
+ {
+ unsigned long uc_flags;
+ struct ucontext_ *uc_link;
+ unsigned long uc_stack[3];
+ sigregs_ uc_mcontext;
+ } *uc = context->cfa + 8 + 128;
+
+ regs = &uc->uc_mcontext;
+ signo = context->cfa + sizeof(long);
+ }
+
+ /* Old-style RT frame and all non-RT frames:
+ old signal mask (8 bytes)
+ pointer to sigregs */
+ else
+ {
+ regs = *(sigregs_ **)(context->cfa + 8);
+
+ /* Recent kernels store the signal number immediately after
+ the sigregs; old kernels have the return trampoline at
+ this location. */
+ if ((void *)(regs + 1) != context->ra)
+ signo = (int *)(regs + 1);
+ }
+
+ new_cfa = regs->gprs[15] + 16*sizeof(long) + 32;
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = 15;
+ fs->cfa_offset =
+ new_cfa - (long) context->cfa + 16*sizeof(long) + 32;
+
+ for (i = 0; i < 16; i++)
+ {
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset =
+ (long)&regs->gprs[i] - new_cfa;
+ }
+ for (i = 0; i < 16; i++)
+ {
+ fs->regs.reg[16+i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[16+i].loc.offset =
+ (long)&regs->fprs[i] - new_cfa;
+ }
+
+ /* Load return addr from PSW into dummy register 32. */
+
+ fs->regs.reg[32].how = REG_SAVED_OFFSET;
+ fs->regs.reg[32].loc.offset = (long)&regs->psw_addr - new_cfa;
+ fs->retaddr_column = 32;
+
+ /* If we got a SIGSEGV or a SIGBUS, the PSW address points *to*
+ the faulting instruction, not after it. This causes the logic
+ in unwind-dw2.c that decrements the RA to determine the correct
+ CFI region to get confused. To fix that, we *increment* the RA
+ here in that case. Note that we cannot modify the RA in place,
+ and the frame state wants a *pointer*, not a value; thus we put
+ the modified RA value into the unused register 33 slot of FS and
+ have the register 32 save address point to that slot.
+
+ Unfortunately, for regular signals on old kernels, we don't know
+ the signal number. We default to not fiddling with the RA;
+ that can fail in rare cases. Upgrade your kernel. */
+
+ if (signo && (*signo == 11 || *signo == 7))
+ {
+ fs->regs.reg[33].loc.exp =
+ (unsigned char *)regs->psw_addr + 1;
+ fs->regs.reg[32].loc.offset =
+ (long)&fs->regs.reg[33].loc.exp - new_cfa;
+ }
+
+ return _URC_NO_REASON;
+}