1130803Smarcel/* Target-dependent code for NetBSD/sparc64.
2130803Smarcel
3130803Smarcel   Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
4130803Smarcel   Based on code contributed by Wasabi Systems, Inc.
5130803Smarcel
6130803Smarcel   This file is part of GDB.
7130803Smarcel
8130803Smarcel   This program is free software; you can redistribute it and/or modify
9130803Smarcel   it under the terms of the GNU General Public License as published by
10130803Smarcel   the Free Software Foundation; either version 2 of the License, or
11130803Smarcel   (at your option) any later version.
12130803Smarcel
13130803Smarcel   This program is distributed in the hope that it will be useful,
14130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
15130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130803Smarcel   GNU General Public License for more details.
17130803Smarcel
18130803Smarcel   You should have received a copy of the GNU General Public License
19130803Smarcel   along with this program; if not, write to the Free Software
20130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
21130803Smarcel   Boston, MA 02111-1307, USA.  */
22130803Smarcel
23130803Smarcel#include "defs.h"
24130803Smarcel#include "frame.h"
25130803Smarcel#include "frame-unwind.h"
26130803Smarcel#include "gdbcore.h"
27130803Smarcel#include "osabi.h"
28130803Smarcel#include "regcache.h"
29130803Smarcel#include "regset.h"
30130803Smarcel#include "symtab.h"
31130803Smarcel#include "solib-svr4.h"
32130803Smarcel#include "trad-frame.h"
33130803Smarcel
34130803Smarcel#include "gdb_assert.h"
35130803Smarcel#include "gdb_string.h"
36130803Smarcel
37130803Smarcel#include "sparc64-tdep.h"
38130803Smarcel#include "nbsd-tdep.h"
39130803Smarcel
40130803Smarcel/* From <machine/reg.h>.  */
41130803Smarcelconst struct sparc_gregset sparc64nbsd_gregset =
42130803Smarcel{
43130803Smarcel  0 * 8,			/* "tstate" */
44130803Smarcel  1 * 8,			/* %pc */
45130803Smarcel  2 * 8,			/* %npc */
46130803Smarcel  3 * 8,			/* %y */
47130803Smarcel  -1,				/* %fprs */
48130803Smarcel  -1,
49130803Smarcel  5 * 8,			/* %g1 */
50130803Smarcel  -1,				/* %l0 */
51130803Smarcel  4				/* sizeof (%y) */
52130803Smarcel};
53130803Smarcel
54130803Smarcel
55130803Smarcelstatic void
56130803Smarcelsparc64nbsd_supply_gregset (const struct regset *regset,
57130803Smarcel			    struct regcache *regcache,
58130803Smarcel			    int regnum, const void *gregs, size_t len)
59130803Smarcel{
60130803Smarcel  sparc64_supply_gregset (regset->descr, regcache, regnum, gregs);
61130803Smarcel}
62130803Smarcel
63130803Smarcelstatic void
64130803Smarcelsparc64nbsd_supply_fpregset (const struct regset *regset,
65130803Smarcel			     struct regcache *regcache,
66130803Smarcel			     int regnum, const void *fpregs, size_t len)
67130803Smarcel{
68130803Smarcel  sparc64_supply_fpregset (regcache, regnum, fpregs);
69130803Smarcel}
70130803Smarcel
71130803Smarcel
72130803Smarcel/* Signal trampolines.  */
73130803Smarcel
74130803Smarcel/* The following variables describe the location of an on-stack signal
75130803Smarcel   trampoline.  The current values correspond to the memory layout for
76130803Smarcel   NetBSD 1.3 and up.  These shouldn't be necessary for NetBSD 2.0 and
77130803Smarcel   up, since NetBSD uses signal trampolines provided by libc now.  */
78130803Smarcel
79130803Smarcelstatic const CORE_ADDR sparc64nbsd_sigtramp_start = 0xffffffffffffdee4ULL;
80130803Smarcelstatic const CORE_ADDR sparc64nbsd_sigtramp_end = 0xffffffffffffe000ULL;
81130803Smarcel
82130803Smarcelstatic int
83130803Smarcelsparc64nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
84130803Smarcel{
85130803Smarcel  if (pc >= sparc64nbsd_sigtramp_start && pc < sparc64nbsd_sigtramp_end)
86130803Smarcel    return 1;
87130803Smarcel
88130803Smarcel  return nbsd_pc_in_sigtramp (pc, name);
89130803Smarcel}
90130803Smarcel
91130803Smarcelstruct trad_frame_saved_reg *
92130803Smarcelsparc64nbsd_sigcontext_saved_regs (CORE_ADDR sigcontext_addr,
93130803Smarcel				   struct frame_info *next_frame)
94130803Smarcel{
95130803Smarcel  struct trad_frame_saved_reg *saved_regs;
96130803Smarcel  CORE_ADDR addr, sp;
97130803Smarcel  int regnum, delta;
98130803Smarcel
99130803Smarcel  saved_regs = trad_frame_alloc_saved_regs (next_frame);
100130803Smarcel
101130803Smarcel  /* The registers are saved in bits and pieces scattered all over the
102130803Smarcel     place.  The code below records their location on the assumption
103130803Smarcel     that the part of the signal trampoline that saves the state has
104130803Smarcel     been executed.  */
105130803Smarcel
106130803Smarcel  saved_regs[SPARC_SP_REGNUM].addr = sigcontext_addr + 8;
107130803Smarcel  saved_regs[SPARC64_PC_REGNUM].addr = sigcontext_addr + 16;
108130803Smarcel  saved_regs[SPARC64_NPC_REGNUM].addr = sigcontext_addr + 24;
109130803Smarcel  saved_regs[SPARC64_STATE_REGNUM].addr = sigcontext_addr + 32;
110130803Smarcel  saved_regs[SPARC_G1_REGNUM].addr = sigcontext_addr + 40;
111130803Smarcel  saved_regs[SPARC_O0_REGNUM].addr = sigcontext_addr + 48;
112130803Smarcel
113130803Smarcel  /* The remaining `global' registers and %y are saved in the `local'
114130803Smarcel     registers.  */
115130803Smarcel  delta = SPARC_L0_REGNUM - SPARC_G0_REGNUM;
116130803Smarcel  for (regnum = SPARC_G2_REGNUM; regnum <= SPARC_G7_REGNUM; regnum++)
117130803Smarcel    saved_regs[regnum].realreg = regnum + delta;
118130803Smarcel  saved_regs[SPARC64_Y_REGNUM].realreg = SPARC_L1_REGNUM;
119130803Smarcel
120130803Smarcel  /* The remaining `out' registers can be found in the current frame's
121130803Smarcel     `in' registers.  */
122130803Smarcel  delta = SPARC_I0_REGNUM - SPARC_O0_REGNUM;
123130803Smarcel  for (regnum = SPARC_O1_REGNUM; regnum <= SPARC_O5_REGNUM; regnum++)
124130803Smarcel    saved_regs[regnum].realreg = regnum + delta;
125130803Smarcel  saved_regs[SPARC_O7_REGNUM].realreg = SPARC_I7_REGNUM;
126130803Smarcel
127130803Smarcel  /* The `local' and `in' registers have been saved in the register
128130803Smarcel     save area.  */
129130803Smarcel  addr = saved_regs[SPARC_SP_REGNUM].addr;
130130803Smarcel  sp = get_frame_memory_unsigned (next_frame, addr, 8);
131130803Smarcel  for (regnum = SPARC_L0_REGNUM, addr = sp + BIAS;
132130803Smarcel       regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
133130803Smarcel    saved_regs[regnum].addr = addr;
134130803Smarcel
135130803Smarcel  /* TODO: Handle the floating-point registers.  */
136130803Smarcel
137130803Smarcel  return saved_regs;
138130803Smarcel}
139130803Smarcel
140130803Smarcelstatic struct sparc_frame_cache *
141130803Smarcelsparc64nbsd_sigcontext_frame_cache (struct frame_info *next_frame,
142130803Smarcel				    void **this_cache)
143130803Smarcel{
144130803Smarcel  struct sparc_frame_cache *cache;
145130803Smarcel  CORE_ADDR addr;
146130803Smarcel
147130803Smarcel  if (*this_cache)
148130803Smarcel    return *this_cache;
149130803Smarcel
150130803Smarcel  cache = sparc_frame_cache (next_frame, this_cache);
151130803Smarcel  gdb_assert (cache == *this_cache);
152130803Smarcel
153130803Smarcel  /* If we couldn't find the frame's function, we're probably dealing
154130803Smarcel     with an on-stack signal trampoline.  */
155130803Smarcel  if (cache->pc == 0)
156130803Smarcel    {
157130803Smarcel      cache->pc = sparc64nbsd_sigtramp_start;
158130803Smarcel
159130803Smarcel      /* Since we couldn't find the frame's function, the cache was
160130803Smarcel         initialized under the assumption that we're frameless.  */
161130803Smarcel      cache->frameless_p = 0;
162130803Smarcel      addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
163130803Smarcel      cache->base = addr;
164130803Smarcel    }
165130803Smarcel
166130803Smarcel  /* We find the appropriate instance of `struct sigcontext' at a
167130803Smarcel     fixed offset in the signal frame.  */
168130803Smarcel  addr = cache->base + BIAS + 128 + 8;
169130803Smarcel  cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
170130803Smarcel
171130803Smarcel  return cache;
172130803Smarcel}
173130803Smarcel
174130803Smarcelstatic void
175130803Smarcelsparc64nbsd_sigcontext_frame_this_id (struct frame_info *next_frame,
176130803Smarcel				      void **this_cache,
177130803Smarcel				      struct frame_id *this_id)
178130803Smarcel{
179130803Smarcel  struct sparc_frame_cache *cache =
180130803Smarcel    sparc64nbsd_sigcontext_frame_cache (next_frame, this_cache);
181130803Smarcel
182130803Smarcel  (*this_id) = frame_id_build (cache->base, cache->pc);
183130803Smarcel}
184130803Smarcel
185130803Smarcelstatic void
186130803Smarcelsparc64nbsd_sigcontext_frame_prev_register (struct frame_info *next_frame,
187130803Smarcel					    void **this_cache,
188130803Smarcel					    int regnum, int *optimizedp,
189130803Smarcel					    enum lval_type *lvalp,
190130803Smarcel					    CORE_ADDR *addrp,
191130803Smarcel					    int *realnump, void *valuep)
192130803Smarcel{
193130803Smarcel  struct sparc_frame_cache *cache =
194130803Smarcel    sparc64nbsd_sigcontext_frame_cache (next_frame, this_cache);
195130803Smarcel
196130803Smarcel  trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
197130803Smarcel			    optimizedp, lvalp, addrp, realnump, valuep);
198130803Smarcel}
199130803Smarcel
200130803Smarcelstatic const struct frame_unwind sparc64nbsd_sigcontext_frame_unwind =
201130803Smarcel{
202130803Smarcel  SIGTRAMP_FRAME,
203130803Smarcel  sparc64nbsd_sigcontext_frame_this_id,
204130803Smarcel  sparc64nbsd_sigcontext_frame_prev_register
205130803Smarcel};
206130803Smarcel
207130803Smarcelstatic const struct frame_unwind *
208130803Smarcelsparc64nbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
209130803Smarcel{
210130803Smarcel  CORE_ADDR pc = frame_pc_unwind (next_frame);
211130803Smarcel  char *name;
212130803Smarcel
213130803Smarcel  find_pc_partial_function (pc, &name, NULL, NULL);
214130803Smarcel  if (sparc64nbsd_pc_in_sigtramp (pc, name))
215130803Smarcel    {
216130803Smarcel      if (name == NULL || strncmp (name, "__sigtramp_sigcontext", 21))
217130803Smarcel	return &sparc64nbsd_sigcontext_frame_unwind;
218130803Smarcel    }
219130803Smarcel
220130803Smarcel  return NULL;
221130803Smarcel}
222130803Smarcel
223130803Smarcel
224130803Smarcelstatic void
225130803Smarcelsparc64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
226130803Smarcel{
227130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
228130803Smarcel
229130803Smarcel  tdep->gregset = XMALLOC (struct regset);
230130803Smarcel  tdep->gregset->descr = &sparc64nbsd_gregset;
231130803Smarcel  tdep->gregset->supply_regset = sparc64nbsd_supply_gregset;
232130803Smarcel  tdep->sizeof_gregset = 160;
233130803Smarcel
234130803Smarcel  tdep->fpregset = XMALLOC (struct regset);
235130803Smarcel  tdep->fpregset->supply_regset = sparc64nbsd_supply_fpregset;
236130803Smarcel  tdep->sizeof_fpregset = 272;
237130803Smarcel
238130803Smarcel  set_gdbarch_pc_in_sigtramp (gdbarch, sparc64nbsd_pc_in_sigtramp);
239130803Smarcel  frame_unwind_append_sniffer (gdbarch, sparc64nbsd_sigtramp_frame_sniffer);
240130803Smarcel
241130803Smarcel  sparc64_init_abi (info, gdbarch);
242130803Smarcel
243130803Smarcel  set_solib_svr4_fetch_link_map_offsets
244130803Smarcel    (gdbarch, nbsd_lp64_solib_svr4_fetch_link_map_offsets);
245130803Smarcel}
246130803Smarcel
247130803Smarcel
248130803Smarcel/* Provide a prototype to silence -Wmissing-prototypes.  */
249130803Smarcelvoid _initialize_sparc64nbsd_tdep (void);
250130803Smarcel
251130803Smarcelvoid
252130803Smarcel_initialize_sparc64nbsd_tdep (void)
253130803Smarcel{
254130803Smarcel  gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
255130803Smarcel			  GDB_OSABI_NETBSD_ELF, sparc64nbsd_init_abi);
256130803Smarcel}
257