1169689Skan/* DWARF2 EH unwinding support for MIPS Linux.
2169689Skan   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3169689Skan
4169689SkanThis file is part of GCC.
5169689Skan
6169689SkanGCC is free software; you can redistribute it and/or modify
7169689Skanit under the terms of the GNU General Public License as published by
8169689Skanthe Free Software Foundation; either version 2, or (at your option)
9169689Skanany later version.
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,
20169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
21169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22169689SkanGNU General Public License for 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
26169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor,
27169689SkanBoston, MA 02110-1301, USA.  */
28169689Skan
29169689Skan#ifndef inhibit_libc
30169689Skan/* Do code reading to identify a signal frame, and set the frame
31169689Skan   state data appropriately.  See unwind-dw2.c for the structs.  */
32169689Skan
33169689Skan#include <signal.h>
34169689Skan#include <asm/unistd.h>
35169689Skan
36169689Skan/* The third parameter to the signal handler points to something with
37169689Skan * this structure defined in asm/ucontext.h, but the name clashes with
38169689Skan * struct ucontext from sys/ucontext.h so this private copy is used.  */
39169689Skantypedef struct _sig_ucontext {
40169689Skan    unsigned long         uc_flags;
41169689Skan    struct _sig_ucontext  *uc_link;
42169689Skan    stack_t               uc_stack;
43169689Skan    struct sigcontext uc_mcontext;
44169689Skan    sigset_t      uc_sigmask;
45169689Skan} _sig_ucontext_t;
46169689Skan
47169689Skan#define MD_FALLBACK_FRAME_STATE_FOR mips_fallback_frame_state
48169689Skan
49169689Skanstatic _Unwind_Reason_Code
50169689Skanmips_fallback_frame_state (struct _Unwind_Context *context,
51169689Skan			   _Unwind_FrameState *fs)
52169689Skan{
53169689Skan  u_int32_t *pc = (u_int32_t *) context->ra;
54169689Skan  struct sigcontext *sc;
55169689Skan  _Unwind_Ptr new_cfa;
56169689Skan  int i;
57169689Skan
58169689Skan  /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
59169689Skan  /* 0000000c syscall    */
60169689Skan  /*    or */
61169689Skan  /* 24021017 li v0, 0x1017 (sigreturn) */
62169689Skan  /* 0000000c syscall  */
63169689Skan  if (pc[1] != 0x0000000c)
64169689Skan    return _URC_END_OF_STACK;
65169689Skan#if _MIPS_SIM == _ABIO32
66169689Skan  if (pc[0] == (0x24020000 | __NR_sigreturn))
67169689Skan    {
68169689Skan      struct sigframe {
69169689Skan	u_int32_t trampoline[2];
70169689Skan	struct sigcontext sigctx;
71169689Skan      } *rt_ = context->ra;
72169689Skan      sc = &rt_->sigctx;
73169689Skan    }
74169689Skan  else
75169689Skan#endif
76169689Skan  if (pc[0] == (0x24020000 | __NR_rt_sigreturn))
77169689Skan    {
78169689Skan      struct rt_sigframe {
79169689Skan	u_int32_t trampoline[2];
80169689Skan	struct siginfo info;
81169689Skan	_sig_ucontext_t uc;
82169689Skan      } *rt_ = context->ra;
83169689Skan      sc = &rt_->uc.uc_mcontext;
84169689Skan    }
85169689Skan  else
86169689Skan    return _URC_END_OF_STACK;
87169689Skan
88169689Skan  new_cfa = (_Unwind_Ptr)sc;
89169689Skan  fs->cfa_how = CFA_REG_OFFSET;
90169689Skan  fs->cfa_reg = STACK_POINTER_REGNUM;
91169689Skan  fs->cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa;
92169689Skan
93169689Skan#if _MIPS_SIM == _ABIO32 && defined __MIPSEB__
94169689Skan  /* On o32 Linux, the register save slots in the sigcontext are
95169689Skan     eight bytes.  We need the lower half of each register slot,
96169689Skan     so slide our view of the structure back four bytes.  */
97169689Skan  new_cfa -= 4;
98169689Skan#endif
99169689Skan
100169689Skan  for (i = 0; i < 32; i++) {
101169689Skan    fs->regs.reg[i].how = REG_SAVED_OFFSET;
102169689Skan    fs->regs.reg[i].loc.offset
103169689Skan      = (_Unwind_Ptr)&(sc->sc_regs[i]) - new_cfa;
104169689Skan  }
105169689Skan  fs->regs.reg[SIGNAL_UNWIND_RETURN_COLUMN].how = REG_SAVED_OFFSET;
106169689Skan  fs->regs.reg[SIGNAL_UNWIND_RETURN_COLUMN].loc.offset
107169689Skan    = (_Unwind_Ptr)&(sc->sc_pc) - new_cfa;
108169689Skan  fs->retaddr_column = SIGNAL_UNWIND_RETURN_COLUMN;
109169689Skan
110169689Skan  return _URC_NO_REASON;
111169689Skan}
112169689Skan#endif
113