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
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
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
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 *
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
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
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 *
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 *
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
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
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 *
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
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
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