* NEWS (New native configurations): Mention OpenBSD/sparc and
[external/binutils.git] / gdb / sparc64nbsd-tdep.c
1 /* Target-dependent code for NetBSD/sparc64.
2
3    Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
4    Based on code contributed by Wasabi Systems, Inc.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
22
23 #include "defs.h"
24 #include "frame.h"
25 #include "frame-unwind.h"
26 #include "gdbcore.h"
27 #include "osabi.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "symtab.h"
31 #include "solib-svr4.h"
32 #include "trad-frame.h"
33
34 #include "gdb_assert.h"
35 #include "gdb_string.h"
36
37 #include "sparc64-tdep.h"
38 #include "nbsd-tdep.h"
39
40 /* From <machine/reg.h>.  */
41 const struct sparc_gregset sparc64nbsd_gregset =
42 {
43   0 * 8,                        /* "tstate" */
44   1 * 8,                        /* %pc */
45   2 * 8,                        /* %npc */
46   3 * 8,                        /* %y */
47   -1,                           /* %fprs */
48   -1,
49   5 * 8,                        /* %g1 */
50   -1,                           /* %l0 */
51   4                             /* sizeof (%y) */
52 };
53 \f
54
55 static void
56 sparc64nbsd_supply_gregset (const struct regset *regset,
57                             struct regcache *regcache,
58                             int regnum, const void *gregs, size_t len)
59 {
60   sparc64_supply_gregset (regset->descr, regcache, regnum, gregs);
61 }
62
63 static void
64 sparc64nbsd_supply_fpregset (const struct regset *regset,
65                              struct regcache *regcache,
66                              int regnum, const void *fpregs, size_t len)
67 {
68   sparc64_supply_fpregset (regcache, regnum, fpregs);
69 }
70 \f
71
72 /* Signal trampolines.  */
73
74 /* The following variables describe the location of an on-stack signal
75    trampoline.  The current values correspond to the memory layout for
76    NetBSD 1.3 and up.  These shouldn't be necessary for NetBSD 2.0 and
77    up, since NetBSD uses signal trampolines provided by libc now.  */
78
79 static const CORE_ADDR sparc64nbsd_sigtramp_start = 0xffffffffffffdee4ULL;
80 static const CORE_ADDR sparc64nbsd_sigtramp_end = 0xffffffffffffe000ULL;
81
82 static int
83 sparc64nbsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
84 {
85   if (pc >= sparc64nbsd_sigtramp_start && pc < sparc64nbsd_sigtramp_end)
86     return 1;
87
88   return nbsd_pc_in_sigtramp (pc, name);
89 }
90
91 static struct sparc_frame_cache *
92 sparc64nbsd_sigcontext_frame_cache (struct frame_info *next_frame,
93                                     void **this_cache)
94 {
95   struct sparc_frame_cache *cache;
96   CORE_ADDR addr, sigcontext_addr, sp;
97   LONGEST fprs;
98   int regnum, delta;
99
100   if (*this_cache)
101     return *this_cache;
102
103   cache = sparc_frame_cache (next_frame, this_cache);
104   gdb_assert (cache == *this_cache);
105
106   /* The registers are saved in bits and pieces scattered all over the
107      place.  The code below records their location on the assumption
108      that the part of the signal trampoline that saves the state has
109      been executed.  */
110
111   /* If we couldn't find the frame's function, we're probably dealing
112      with an on-stack signal trampoline.  */
113   if (cache->pc == 0)
114     {
115       cache->pc = sparc64nbsd_sigtramp_start;
116
117       /* Since we couldn't find the frame's function, the cache was
118          initialized under the assumption that we're frameless.  */
119       cache->frameless_p = 0;
120       addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
121       cache->base = addr;
122     }
123
124   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
125
126   /* We find the appropriate instance of `struct sigcontext' at a
127      fixed offset in the signal frame.  */
128   sigcontext_addr = cache->base + BIAS + 128 + 8;
129
130   cache->saved_regs[SPARC_SP_REGNUM].addr = sigcontext_addr + 8;
131   cache->saved_regs[SPARC64_PC_REGNUM].addr = sigcontext_addr + 16;
132   cache->saved_regs[SPARC64_NPC_REGNUM].addr = sigcontext_addr + 24;
133   cache->saved_regs[SPARC64_STATE_REGNUM].addr = sigcontext_addr + 32;
134   cache->saved_regs[SPARC_G1_REGNUM].addr = sigcontext_addr + 40;
135   cache->saved_regs[SPARC_O0_REGNUM].addr = sigcontext_addr + 48;
136
137   /* The remaining `global' registers and %y are saved in the `local'
138      registers.  */
139   delta = SPARC_L0_REGNUM - SPARC_G0_REGNUM;
140   for (regnum = SPARC_G2_REGNUM; regnum <= SPARC_G7_REGNUM; regnum++)
141     cache->saved_regs[regnum].realreg = regnum + delta;
142   cache->saved_regs[SPARC64_Y_REGNUM].realreg = SPARC_L1_REGNUM;
143
144   /* The remaining `out' registers can be found in the current frame's
145      `in' registers.  */
146   delta = SPARC_I0_REGNUM - SPARC_O0_REGNUM;
147   for (regnum = SPARC_O1_REGNUM; regnum <= SPARC_O5_REGNUM; regnum++)
148     cache->saved_regs[regnum].realreg = regnum + delta;
149   cache->saved_regs[SPARC_O7_REGNUM].realreg = SPARC_I7_REGNUM;
150
151   /* The `local' and `in' registers have been saved in the register
152      save area.  */
153   addr = cache->saved_regs[SPARC_SP_REGNUM].addr;
154   sp = get_frame_memory_unsigned (next_frame, addr, 8);
155   for (regnum = SPARC_L0_REGNUM, addr = sp + BIAS;
156        regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
157     cache->saved_regs[regnum].addr = addr;
158
159   /* TODO: Handle the floating-point registers.  */
160
161   return cache;
162 }
163
164 static void
165 sparc64nbsd_sigcontext_frame_this_id (struct frame_info *next_frame,
166                                       void **this_cache,
167                                       struct frame_id *this_id)
168 {
169   struct sparc_frame_cache *cache =
170     sparc64nbsd_sigcontext_frame_cache (next_frame, this_cache);
171
172   (*this_id) = frame_id_build (cache->base, cache->pc);
173 }
174
175 static void
176 sparc64nbsd_sigcontext_frame_prev_register (struct frame_info *next_frame,
177                                             void **this_cache,
178                                             int regnum, int *optimizedp,
179                                             enum lval_type *lvalp,
180                                             CORE_ADDR *addrp,
181                                             int *realnump, void *valuep)
182 {
183   struct sparc_frame_cache *cache =
184     sparc64nbsd_sigcontext_frame_cache (next_frame, this_cache);
185
186   trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
187                             optimizedp, lvalp, addrp, realnump, valuep);
188 }
189
190 static const struct frame_unwind sparc64nbsd_sigcontext_frame_unwind =
191 {
192   SIGTRAMP_FRAME,
193   sparc64nbsd_sigcontext_frame_this_id,
194   sparc64nbsd_sigcontext_frame_prev_register
195 };
196
197 static const struct frame_unwind *
198 sparc64nbsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
199 {
200   CORE_ADDR pc = frame_pc_unwind (next_frame);
201   char *name;
202
203   find_pc_partial_function (pc, &name, NULL, NULL);
204   if (sparc64nbsd_pc_in_sigtramp (pc, name))
205     {
206       if (name == NULL || strncmp (name, "__sigtramp_sigcontext", 21))
207         return &sparc64nbsd_sigcontext_frame_unwind;
208     }
209
210   return NULL;
211 }
212 \f
213
214 static void
215 sparc64nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
216 {
217   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
218
219   tdep->gregset = XMALLOC (struct regset);
220   tdep->gregset->descr = &sparc64nbsd_gregset;
221   tdep->gregset->supply_regset = sparc64nbsd_supply_gregset;
222   tdep->sizeof_gregset = 160;
223
224   tdep->fpregset = XMALLOC (struct regset);
225   tdep->fpregset->supply_regset = sparc64nbsd_supply_fpregset;
226   tdep->sizeof_fpregset = 272;
227
228   set_gdbarch_pc_in_sigtramp (gdbarch, sparc64nbsd_pc_in_sigtramp);
229   frame_unwind_append_sniffer (gdbarch, sparc64nbsd_sigtramp_frame_sniffer);
230
231   sparc64_init_abi (info, gdbarch);
232
233   set_solib_svr4_fetch_link_map_offsets
234     (gdbarch, nbsd_lp64_solib_svr4_fetch_link_map_offsets);
235 }
236
237 \f
238 /* Provide a prototype to silence -Wmissing-prototypes.  */
239 void _initialize_sparc64nbsd_tdep (void);
240
241 void
242 _initialize_sparc64nbsd_tdep (void)
243 {
244   gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
245                           GDB_OSABI_NETBSD_ELF, sparc64nbsd_init_abi);
246   gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
247                           GDB_OSABI_OPENBSD_ELF, sparc64nbsd_init_abi);
248 }