1/* Target-dependent code for GNU/Linux UltraSPARC.
2
3   Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "frame.h"
22#include "frame-unwind.h"
23#include "dwarf2-frame.h"
24#include "regset.h"
25#include "regcache.h"
26#include "gdbarch.h"
27#include "gdbcore.h"
28#include "osabi.h"
29#include "solib-svr4.h"
30#include "symtab.h"
31#include "trad-frame.h"
32#include "tramp-frame.h"
33
34#include "sparc64-tdep.h"
35
36/* Signal trampoline support.  */
37
38static void sparc64_linux_sigframe_init (const struct tramp_frame *self,
39					 struct frame_info *next_frame,
40					 struct trad_frame_cache *this_cache,
41					 CORE_ADDR func);
42
43/* See sparc-linux-tdep.c for details.  Note that 64-bit binaries only
44   use RT signals.  */
45
46static const struct tramp_frame sparc64_linux_rt_sigframe =
47{
48  SIGTRAMP_FRAME,
49  4,
50  {
51    { 0x82102065, -1 },		/* mov __NR_rt_sigreturn, %g1 */
52    { 0x91d0206d, -1 },		/* ta  0x6d */
53    { TRAMP_SENTINEL_INSN, -1 }
54  },
55  sparc64_linux_sigframe_init
56};
57
58static void
59sparc64_linux_sigframe_init (const struct tramp_frame *self,
60			     struct frame_info *next_frame,
61			     struct trad_frame_cache *this_cache,
62			     CORE_ADDR func)
63{
64  CORE_ADDR base, addr, sp_addr;
65  int regnum;
66
67  base = frame_unwind_register_unsigned (next_frame, SPARC_O1_REGNUM);
68  base += 128;
69
70  /* Offsets from <bits/sigcontext.h>.  */
71
72  /* Since %g0 is always zero, keep the identity encoding.  */
73  addr = base + 8;
74  sp_addr = base + ((SPARC_SP_REGNUM - SPARC_G0_REGNUM) * 8);
75  for (regnum = SPARC_G1_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++)
76    {
77      trad_frame_set_reg_addr (this_cache, regnum, addr);
78      addr += 8;
79    }
80
81  trad_frame_set_reg_addr (this_cache, SPARC64_STATE_REGNUM, addr + 0);
82  trad_frame_set_reg_addr (this_cache, SPARC64_PC_REGNUM, addr + 8);
83  trad_frame_set_reg_addr (this_cache, SPARC64_NPC_REGNUM, addr + 16);
84  trad_frame_set_reg_addr (this_cache, SPARC64_Y_REGNUM, addr + 24);
85  trad_frame_set_reg_addr (this_cache, SPARC64_FPRS_REGNUM, addr + 28);
86
87  base = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
88  if (base & 1)
89    base += BIAS;
90
91  addr = get_frame_memory_unsigned (next_frame, sp_addr, 8);
92  if (addr & 1)
93    addr += BIAS;
94
95  for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
96    {
97      trad_frame_set_reg_addr (this_cache, regnum, addr);
98      addr += 8;
99    }
100  trad_frame_set_id (this_cache, frame_id_build (base, func));
101}
102
103/* Return the address of a system call's alternative return
104   address.  */
105
106static CORE_ADDR
107sparc64_linux_step_trap (struct frame_info *frame, unsigned long insn)
108{
109  if (insn == 0x91d0206d)
110    {
111      ULONGEST sp = get_frame_register_unsigned (frame, SPARC_SP_REGNUM);
112      if (sp & 1)
113	sp += BIAS;
114
115      /* The kernel puts the sigreturn registers on the stack,
116	 and this is where the signal unwinding state is take from
117	 when returning from a signal.
118
119	 A siginfo_t sits 192 bytes from the base of the stack.  This
120	 siginfo_t is 128 bytes, and is followed by the sigreturn
121	 register save area.  The saved PC sits at a 136 byte offset
122	 into there.  */
123
124      return read_memory_unsigned_integer (sp + 192 + 128 + 136, 8);
125    }
126
127  return 0;
128}
129
130
131const struct sparc_gregset sparc64_linux_core_gregset =
132{
133  32 * 8,			/* %tstate */
134  33 * 8,			/* %tpc */
135  34 * 8,			/* %tnpc */
136  35 * 8,			/* %y */
137  -1,				/* %wim */
138  -1,				/* %tbr */
139  1 * 8,			/* %g1 */
140  16 * 8,			/* %l0 */
141  8,				/* y size */
142};
143
144
145static void
146sparc64_linux_supply_core_gregset (const struct regset *regset,
147				   struct regcache *regcache,
148				   int regnum, const void *gregs, size_t len)
149{
150  sparc64_supply_gregset (&sparc64_linux_core_gregset, regcache, regnum, gregs);
151}
152
153static void
154sparc64_linux_collect_core_gregset (const struct regset *regset,
155				    const struct regcache *regcache,
156				    int regnum, void *gregs, size_t len)
157{
158  sparc64_collect_gregset (&sparc64_linux_core_gregset, regcache, regnum, gregs);
159}
160
161static void
162sparc64_linux_supply_core_fpregset (const struct regset *regset,
163				    struct regcache *regcache,
164				    int regnum, const void *fpregs, size_t len)
165{
166  sparc64_supply_fpregset (regcache, regnum, fpregs);
167}
168
169static void
170sparc64_linux_collect_core_fpregset (const struct regset *regset,
171				     const struct regcache *regcache,
172				     int regnum, void *fpregs, size_t len)
173{
174  sparc64_collect_fpregset (regcache, regnum, fpregs);
175}
176
177
178
179static void
180sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
181{
182  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
183
184  tdep->gregset = regset_alloc (gdbarch, sparc64_linux_supply_core_gregset,
185				sparc64_linux_collect_core_gregset);
186  tdep->sizeof_gregset = 288;
187
188  tdep->fpregset = regset_alloc (gdbarch, sparc64_linux_supply_core_fpregset,
189				 sparc64_linux_collect_core_fpregset);
190  tdep->sizeof_fpregset = 280;
191
192  tramp_frame_prepend_unwinder (gdbarch, &sparc64_linux_rt_sigframe);
193
194  /* Hook in the DWARF CFI frame unwinder.  */
195  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
196
197  sparc64_init_abi (info, gdbarch);
198
199  /* GNU/Linux has SVR4-style shared libraries...  */
200  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
201  set_solib_svr4_fetch_link_map_offsets
202    (gdbarch, svr4_lp64_fetch_link_map_offsets);
203
204  /* ...which means that we need some special handling when doing
205     prologue analysis.  */
206  tdep->plt_entry_size = 16;
207
208  /* Enable TLS support.  */
209  set_gdbarch_fetch_tls_load_module_address (gdbarch,
210                                             svr4_fetch_objfile_link_map);
211
212  /* Make sure we can single-step over signal return system calls.  */
213  tdep->step_trap = sparc64_linux_step_trap;
214}
215
216
217/* Provide a prototype to silence -Wmissing-prototypes.  */
218extern void _initialize_sparc64_linux_tdep (void);
219
220void
221_initialize_sparc64_linux_tdep (void)
222{
223  gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
224			  GDB_OSABI_LINUX, sparc64_linux_init_abi);
225}
226