OSDN Git Service

* config/s390/2064.md ("z_int", "z_agen"): Ensure the condition
[pf3gnuchains/gcc-fork.git] / gcc / config / s390 / linux-unwind.h
1 /* DWARF2 EH unwinding support for S/390 Linux.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING.  If not, write to the Free
18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.  */
20
21 /* Do code reading to identify a signal frame, and set the frame
22    state data appropriately.  See unwind-dw2.c for the structs.  */
23
24 #define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
25
26 static _Unwind_Reason_Code
27 s390_fallback_frame_state (struct _Unwind_Context *context,
28                            _Unwind_FrameState *fs)
29 {
30   unsigned char *pc = context->ra;
31   long new_cfa;
32   int i;
33
34   typedef struct
35   {
36     unsigned long psw_mask;
37     unsigned long psw_addr;
38     unsigned long gprs[16];
39     unsigned int  acrs[16];
40     unsigned int  fpc;
41     unsigned int  __pad;
42     double        fprs[16];
43   } __attribute__ ((__aligned__ (8))) sigregs_;
44
45   sigregs_ *regs;
46   int *signo = NULL;
47
48   /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn  */
49   if (pc[0] != 0x0a || (pc[1] != 119 && pc[1] != 173))
50     return _URC_END_OF_STACK;
51
52   /* New-style RT frame:
53      retcode + alignment (8 bytes)
54      siginfo (128 bytes)
55      ucontext (contains sigregs)  */
56   if (context->ra == context->cfa)
57     {
58       struct ucontext_
59       {
60         unsigned long     uc_flags;
61         struct ucontext_ *uc_link;
62         unsigned long     uc_stack[3];
63         sigregs_          uc_mcontext;
64       } *uc = context->cfa + 8 + 128;
65
66       regs = &uc->uc_mcontext;
67       signo = context->cfa + sizeof(long);
68     }
69
70   /* Old-style RT frame and all non-RT frames:
71      old signal mask (8 bytes)
72      pointer to sigregs  */
73   else
74     {
75       regs = *(sigregs_ **)(context->cfa + 8);
76
77       /* Recent kernels store the signal number immediately after
78          the sigregs; old kernels have the return trampoline at
79          this location.  */
80       if ((void *)(regs + 1) != context->ra)
81         signo = (int *)(regs + 1);
82     }
83
84   new_cfa = regs->gprs[15] + 16*sizeof(long) + 32;
85   fs->cfa_how = CFA_REG_OFFSET;
86   fs->cfa_reg = 15;
87   fs->cfa_offset =
88     new_cfa - (long) context->cfa + 16*sizeof(long) + 32;
89
90   for (i = 0; i < 16; i++)
91     {
92       fs->regs.reg[i].how = REG_SAVED_OFFSET;
93       fs->regs.reg[i].loc.offset =
94         (long)&regs->gprs[i] - new_cfa;
95     }
96   for (i = 0; i < 16; i++)
97     {
98       fs->regs.reg[16+i].how = REG_SAVED_OFFSET;
99       fs->regs.reg[16+i].loc.offset =
100         (long)&regs->fprs[i] - new_cfa;
101     }
102
103   /* Load return addr from PSW into dummy register 32.  */
104
105   fs->regs.reg[32].how = REG_SAVED_OFFSET;
106   fs->regs.reg[32].loc.offset = (long)&regs->psw_addr - new_cfa;
107   fs->retaddr_column = 32;
108
109   /* If we got a SIGSEGV or a SIGBUS, the PSW address points *to*
110      the faulting instruction, not after it.  This causes the logic
111      in unwind-dw2.c that decrements the RA to determine the correct
112      CFI region to get confused.  To fix that, we *increment* the RA
113      here in that case.  Note that we cannot modify the RA in place,
114      and the frame state wants a *pointer*, not a value; thus we put
115      the modified RA value into the unused register 33 slot of FS and
116      have the register 32 save address point to that slot.
117
118      Unfortunately, for regular signals on old kernels, we don't know
119      the signal number.  We default to not fiddling with the RA;
120      that can fail in rare cases.  Upgrade your kernel.  */
121
122   if (signo && (*signo == 11 || *signo == 7))
123     {
124       fs->regs.reg[33].loc.exp =
125         (unsigned char *)regs->psw_addr + 1;
126       fs->regs.reg[32].loc.offset =
127         (long)&fs->regs.reg[33].loc.exp - new_cfa;
128     }
129
130   return _URC_NO_REASON;
131 }