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