1 /* Target-dependent code for OpenBSD/sparc64.
2
3 Copyright 2004, 2005, 2006 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 2 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, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "defs.h"
23 #include "frame.h"
24 #include "frame-unwind.h"
25 #include "osabi.h"
26 #include "regset.h"
27 #include "symtab.h"
28 #include "objfiles.h"
29 #include "solib-svr4.h"
30 #include "trad-frame.h"
31
32 #include "gdb_assert.h"
33
34 #include "obsd-tdep.h"
35 #include "sparc64-tdep.h"
36
37 /* OpenBSD uses the traditional NetBSD core file format, even for
38 ports that use ELF. The core files don't use multiple register
39 sets. Instead, the general-purpose and floating-point registers
40 are lumped together in a single section. Unlike on NetBSD, OpenBSD
41 uses a different layout for its general-purpose registers than the
42 layout used for ptrace(2). */
43
44 /* From <machine/reg.h>. */
45 const struct sparc_gregset sparc64obsd_gregset =
46 {
47 0 * 8, /* "tstate" */
48 1 * 8, /* %pc */
49 2 * 8, /* %npc */
50 3 * 8, /* %y */
51 -1, /* %fprs */
52 -1,
53 5 * 8, /* %g1 */
54 20 * 8, /* %l0 */
55 4 /* sizeof (%y) */
56 };
57
58 const struct sparc_gregset sparc64obsd_core_gregset =
59 {
60 0 * 8, /* "tstate" */
61 1 * 8, /* %pc */
62 2 * 8, /* %npc */
63 3 * 8, /* %y */
64 -1, /* %fprs */
65 -1,
66 7 * 8, /* %g1 */
67 22 * 8, /* %l0 */
68 4 /* sizeof (%y) */
69 };
70
71 static void
sparc64obsd_supply_gregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * gregs,size_t len)72 sparc64obsd_supply_gregset (const struct regset *regset,
73 struct regcache *regcache,
74 int regnum, const void *gregs, size_t len)
75 {
76 const char *regs = gregs;
77
78 if (len < 832)
79 {
80 sparc64_supply_gregset (&sparc64obsd_gregset, regcache, regnum, regs);
81 return;
82 }
83
84 sparc64_supply_gregset (&sparc64obsd_core_gregset, regcache, regnum, regs);
85 sparc64_supply_fpregset (regcache, regnum, regs + 288);
86 }
87
88 static void
sparc64obsd_supply_fpregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * fpregs,size_t len)89 sparc64obsd_supply_fpregset (const struct regset *regset,
90 struct regcache *regcache,
91 int regnum, const void *fpregs, size_t len)
92 {
93 sparc64_supply_fpregset (regcache, regnum, fpregs);
94 }
95
96
97 /* Signal trampolines. */
98
99 /* The OpenBSD kernel maps the signal trampoline at some random
100 location in user space, which means that the traditional BSD way of
101 detecting it won't work.
102
103 The signal trampoline will be mapped at an address that is page
104 aligned. We recognize the signal trampoline by the looking for the
105 sigreturn system call. The offset where we can find the code that
106 makes this system call varies from release to release. For OpenBSD
107 3.6 and later releases we can find the code at offset 0xec. For
108 OpenBSD 3.5 and earlier releases, we find it at offset 0xe8. */
109
110 static const int sparc64obsd_page_size = 8192;
111 static const int sparc64obsd_sigreturn_offset[] = { 0xf0, 0xec, 0xe8, -1 };
112
113 static int
sparc64obsd_pc_in_sigtramp(CORE_ADDR pc,char * name)114 sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
115 {
116 CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
117 unsigned long insn;
118 const int *offset;
119
120 if (name)
121 return 0;
122
123 for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
124 {
125 /* Check for "restore %g0, SYS_sigreturn, %g1". */
126 insn = sparc_fetch_instruction (start_pc + *offset);
127 if (insn != 0x83e82067)
128 continue;
129
130 /* Check for "t ST_SYSCALL". */
131 insn = sparc_fetch_instruction (start_pc + *offset + 8);
132 if (insn != 0x91d02000)
133 continue;
134
135 return 1;
136 }
137
138 return 0;
139 }
140
141 static struct sparc_frame_cache *
sparc64obsd_frame_cache(struct frame_info * next_frame,void ** this_cache)142 sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
143 {
144 struct sparc_frame_cache *cache;
145 CORE_ADDR addr;
146
147 if (*this_cache)
148 return *this_cache;
149
150 cache = sparc_frame_cache (next_frame, this_cache);
151 gdb_assert (cache == *this_cache);
152
153 /* If we couldn't find the frame's function, we're probably dealing
154 with an on-stack signal trampoline. */
155 if (cache->pc == 0)
156 {
157 cache->pc = frame_pc_unwind (next_frame);
158 cache->pc &= ~(sparc64obsd_page_size - 1);
159
160 /* Since we couldn't find the frame's function, the cache was
161 initialized under the assumption that we're frameless. */
162 cache->frameless_p = 0;
163 addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
164 cache->base = addr;
165 }
166
167 /* We find the appropriate instance of `struct sigcontext' at a
168 fixed offset in the signal frame. */
169 addr = cache->base + BIAS + 128 + 16;
170 cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
171
172 return cache;
173 }
174
175 static void
sparc64obsd_frame_this_id(struct frame_info * next_frame,void ** this_cache,struct frame_id * this_id)176 sparc64obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
177 struct frame_id *this_id)
178 {
179 struct sparc_frame_cache *cache =
180 sparc64obsd_frame_cache (next_frame, this_cache);
181
182 (*this_id) = frame_id_build (cache->base, cache->pc);
183 }
184
185 static void
sparc64obsd_frame_prev_register(struct frame_info * next_frame,void ** this_cache,int regnum,int * optimizedp,enum lval_type * lvalp,CORE_ADDR * addrp,int * realnump,void * valuep)186 sparc64obsd_frame_prev_register (struct frame_info *next_frame,
187 void **this_cache,
188 int regnum, int *optimizedp,
189 enum lval_type *lvalp, CORE_ADDR *addrp,
190 int *realnump, void *valuep)
191 {
192 struct sparc_frame_cache *cache =
193 sparc64obsd_frame_cache (next_frame, this_cache);
194
195 trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
196 optimizedp, lvalp, addrp, realnump, valuep);
197 }
198
199 static const struct frame_unwind sparc64obsd_frame_unwind =
200 {
201 SIGTRAMP_FRAME,
202 sparc64obsd_frame_this_id,
203 sparc64obsd_frame_prev_register
204 };
205
206 static const struct frame_unwind *
sparc64obsd_sigtramp_frame_sniffer(struct frame_info * next_frame)207 sparc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
208 {
209 CORE_ADDR pc = frame_pc_unwind (next_frame);
210 char *name;
211
212 find_pc_partial_function (pc, &name, NULL, NULL);
213 if (sparc64obsd_pc_in_sigtramp (pc, name))
214 return &sparc64obsd_frame_unwind;
215
216 return NULL;
217 }
218
219 /* Kernel debugging support. */
220
221 static struct sparc_frame_cache *
sparc64obsd_trapframe_cache(struct frame_info * next_frame,void ** this_cache)222 sparc64obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache)
223 {
224 struct sparc_frame_cache *cache;
225 CORE_ADDR sp, trapframe_addr;
226 int regnum;
227
228 if (*this_cache)
229 return *this_cache;
230
231 cache = sparc_frame_cache (next_frame, this_cache);
232 gdb_assert (cache == *this_cache);
233
234 sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
235 trapframe_addr = sp + BIAS + 176;
236
237 cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
238
239 cache->saved_regs[SPARC64_STATE_REGNUM].addr = trapframe_addr;
240 cache->saved_regs[SPARC64_PC_REGNUM].addr = trapframe_addr + 8;
241 cache->saved_regs[SPARC64_NPC_REGNUM].addr = trapframe_addr + 16;
242
243 for (regnum = SPARC_G0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
244 cache->saved_regs[regnum].addr =
245 trapframe_addr + 48 + (regnum - SPARC_G0_REGNUM) * 8;
246
247 return cache;
248 }
249
250 static void
sparc64obsd_trapframe_this_id(struct frame_info * next_frame,void ** this_cache,struct frame_id * this_id)251 sparc64obsd_trapframe_this_id (struct frame_info *next_frame,
252 void **this_cache, struct frame_id *this_id)
253 {
254 struct sparc_frame_cache *cache =
255 sparc64obsd_trapframe_cache (next_frame, this_cache);
256
257 (*this_id) = frame_id_build (cache->base, cache->pc);
258 }
259
260 static void
sparc64obsd_trapframe_prev_register(struct frame_info * next_frame,void ** this_cache,int regnum,int * optimizedp,enum lval_type * lvalp,CORE_ADDR * addrp,int * realnump,void * valuep)261 sparc64obsd_trapframe_prev_register (struct frame_info *next_frame,
262 void **this_cache,
263 int regnum, int *optimizedp,
264 enum lval_type *lvalp, CORE_ADDR *addrp,
265 int *realnump, void *valuep)
266 {
267 struct sparc_frame_cache *cache =
268 sparc64obsd_trapframe_cache (next_frame, this_cache);
269
270 trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
271 optimizedp, lvalp, addrp, realnump, valuep);
272 }
273
274 static const struct frame_unwind sparc64obsd_trapframe_unwind =
275 {
276 NORMAL_FRAME,
277 sparc64obsd_trapframe_this_id,
278 sparc64obsd_trapframe_prev_register
279 };
280
281 static const struct frame_unwind *
sparc64obsd_trapframe_sniffer(struct frame_info * next_frame)282 sparc64obsd_trapframe_sniffer (struct frame_info *next_frame)
283 {
284 ULONGEST pstate;
285 char *name;
286
287 /* Check whether we are in privileged mode, and bail out if we're not. */
288 pstate = frame_unwind_register_unsigned (next_frame, SPARC64_PSTATE_REGNUM);
289 if ((pstate & SPARC64_PSTATE_PRIV) == 0)
290 return NULL;
291
292 find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL);
293 if (name && ((strcmp (name, "Lslowtrap_reenter") == 0)
294 || (strcmp (name, "Ldatafault_internal") == 0)))
295 return &sparc64obsd_trapframe_unwind;
296
297 return NULL;
298 }
299
300
301 static void
sparc64obsd_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)302 sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
303 {
304 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
305
306 tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
307 tdep->sizeof_gregset = 288;
308
309 tdep->fpregset = regset_alloc (gdbarch, sparc64obsd_supply_fpregset, NULL);
310 tdep->sizeof_fpregset = 272;
311
312 frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
313 frame_unwind_append_sniffer (gdbarch, sparc64obsd_trapframe_sniffer);
314
315 sparc64_init_abi (info, gdbarch);
316
317 /* OpenBSD/sparc64 has SVR4-style shared libraries... */
318 set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
319 set_solib_svr4_fetch_link_map_offsets
320 (gdbarch, svr4_lp64_fetch_link_map_offsets);
321 set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
322 }
323
324
325 /* Provide a prototype to silence -Wmissing-prototypes. */
326 void _initialize_sparc64obsd_tdep (void);
327
328 void
_initialize_sparc64obsd_tdep(void)329 _initialize_sparc64obsd_tdep (void)
330 {
331 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
332 GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi);
333 }
334