1169689Skan/* DWARF2 EH unwinding support for S/390 Linux.
2169689Skan   Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify it under
7169689Skanthe terms of the GNU General Public License as published by the Free
8169689SkanSoftware Foundation; either version 2, or (at your option) any later
9169689Skanversion.
10169689Skan
11169689SkanIn addition to the permissions in the GNU General Public License, the
12169689SkanFree Software Foundation gives you unlimited permission to link the
13169689Skancompiled version of this file with other programs, and to distribute
14169689Skanthose programs without any restriction coming from the use of this
15169689Skanfile.  (The General Public License restrictions do apply in other
16169689Skanrespects; for example, they cover modification of the file, and
17169689Skandistribution when not linked into another program.)
18169689Skan
19169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
20169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
21169689SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22169689Skanfor more details.
23169689Skan
24169689SkanYou should have received a copy of the GNU General Public License
25169689Skanalong with GCC; see the file COPYING.  If not, write to the Free
26169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
27169689Skan02110-1301, USA.  */
28169689Skan
29169689Skan/* Do code reading to identify a signal frame, and set the frame
30169689Skan   state data appropriately.  See unwind-dw2.c for the structs.  */
31169689Skan
32169689Skan#define MD_FALLBACK_FRAME_STATE_FOR s390_fallback_frame_state
33169689Skan
34169689Skanstatic _Unwind_Reason_Code
35169689Skans390_fallback_frame_state (struct _Unwind_Context *context,
36169689Skan			   _Unwind_FrameState *fs)
37169689Skan{
38169689Skan  unsigned char *pc = context->ra;
39169689Skan  long new_cfa;
40169689Skan  int i;
41169689Skan
42169689Skan  typedef struct
43169689Skan  {
44169689Skan    unsigned long psw_mask;
45169689Skan    unsigned long psw_addr;
46169689Skan    unsigned long gprs[16];
47169689Skan    unsigned int  acrs[16];
48169689Skan    unsigned int  fpc;
49169689Skan    unsigned int  __pad;
50169689Skan    double        fprs[16];
51169689Skan  } __attribute__ ((__aligned__ (8))) sigregs_;
52169689Skan
53169689Skan  sigregs_ *regs;
54169689Skan  int *signo;
55169689Skan
56169689Skan  /* svc $__NR_sigreturn or svc $__NR_rt_sigreturn  */
57169689Skan  if (pc[0] != 0x0a || (pc[1] != 119 && pc[1] != 173))
58169689Skan    return _URC_END_OF_STACK;
59169689Skan
60169689Skan  /* Legacy frames:
61169689Skan       old signal mask (8 bytes)
62169689Skan       pointer to sigregs (8 bytes) - points always to next location
63169689Skan       sigregs
64169689Skan       retcode
65169689Skan     This frame layout was used on kernels < 2.6.9 for non-RT frames,
66169689Skan     and on kernels < 2.4.13 for RT frames as well.  Note that we need
67169689Skan     to look at RA to detect this layout -- this means that if you use
68169689Skan     sa_restorer to install a different signal restorer on a legacy
69169689Skan     kernel, unwinding from signal frames will not work.  */
70169689Skan  if (context->ra == context->cfa + 16 + sizeof (sigregs_))
71169689Skan    {
72169689Skan      regs = (sigregs_ *)(context->cfa + 16);
73169689Skan      signo = NULL;
74169689Skan    }
75169689Skan
76169689Skan  /* New-style RT frame:
77169689Skan     retcode + alignment (8 bytes)
78169689Skan     siginfo (128 bytes)
79169689Skan     ucontext (contains sigregs)  */
80169689Skan  else if (pc[1] == 173 /* __NR_rt_sigreturn */)
81169689Skan    {
82169689Skan      struct ucontext_
83169689Skan      {
84169689Skan	unsigned long     uc_flags;
85169689Skan	struct ucontext_ *uc_link;
86169689Skan	unsigned long     uc_stack[3];
87169689Skan	sigregs_          uc_mcontext;
88169689Skan      } *uc = context->cfa + 8 + 128;
89169689Skan
90169689Skan      regs = &uc->uc_mcontext;
91169689Skan      signo = context->cfa + sizeof(long);
92169689Skan    }
93169689Skan
94169689Skan  /* New-style non-RT frame:
95169689Skan     old signal mask (8 bytes)
96169689Skan     pointer to sigregs (followed by signal number)  */
97169689Skan  else
98169689Skan    {
99169689Skan      regs = *(sigregs_ **)(context->cfa + 8);
100169689Skan      signo = (int *)(regs + 1);
101169689Skan    }
102169689Skan
103169689Skan  new_cfa = regs->gprs[15] + 16*sizeof(long) + 32;
104169689Skan  fs->cfa_how = CFA_REG_OFFSET;
105169689Skan  fs->cfa_reg = 15;
106169689Skan  fs->cfa_offset =
107169689Skan    new_cfa - (long) context->cfa + 16*sizeof(long) + 32;
108169689Skan
109169689Skan  for (i = 0; i < 16; i++)
110169689Skan    {
111169689Skan      fs->regs.reg[i].how = REG_SAVED_OFFSET;
112169689Skan      fs->regs.reg[i].loc.offset =
113169689Skan	(long)&regs->gprs[i] - new_cfa;
114169689Skan    }
115169689Skan  for (i = 0; i < 16; i++)
116169689Skan    {
117169689Skan      fs->regs.reg[16+i].how = REG_SAVED_OFFSET;
118169689Skan      fs->regs.reg[16+i].loc.offset =
119169689Skan	(long)&regs->fprs[i] - new_cfa;
120169689Skan    }
121169689Skan
122169689Skan  /* Load return addr from PSW into dummy register 32.  */
123169689Skan
124169689Skan  fs->regs.reg[32].how = REG_SAVED_OFFSET;
125169689Skan  fs->regs.reg[32].loc.offset = (long)&regs->psw_addr - new_cfa;
126169689Skan  fs->retaddr_column = 32;
127169689Skan  /* SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr
128169689Skan     after the faulting instruction rather than before it.
129169689Skan     Don't set FS->signal_frame in that case.  */
130169689Skan  if (!signo || (*signo != 4 && *signo != 5 && *signo != 8))
131169689Skan    fs->signal_frame = 1;
132169689Skan
133169689Skan  return _URC_NO_REASON;
134169689Skan}
135