xref: /openbsd-src/gnu/usr.bin/binutils/gdb/sparc64obsd-tdep.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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_core_gregset =
46 {
47   0 * 8,			/* "tstate" */
48   1 * 8,			/* %pc */
49   2 * 8,			/* %npc */
50   3 * 8,			/* %y */
51   -1,				/* %fprs */
52   -1,
53   7 * 8,			/* %g1 */
54   22 * 8,			/* %l0 */
55   4				/* sizeof (%y) */
56 };
57 
58 static void
59 sparc64obsd_supply_gregset (const struct regset *regset,
60 			    struct regcache *regcache,
61 			    int regnum, const void *gregs, size_t len)
62 {
63   const char *regs = gregs;
64 
65   sparc64_supply_gregset (&sparc64obsd_core_gregset, regcache, regnum, regs);
66   sparc64_supply_fpregset (regcache, regnum, regs + 288);
67 }
68 
69 
70 /* Signal trampolines.  */
71 
72 /* The OpenBSD kernel maps the signal trampoline at some random
73    location in user space, which means that the traditional BSD way of
74    detecting it won't work.
75 
76    The signal trampoline will be mapped at an address that is page
77    aligned.  We recognize the signal trampoline by the looking for the
78    sigreturn system call.  The offset where we can find the code that
79    makes this system call varies from release to release.  For OpenBSD
80    3.6 and later releases we can find the code at offset 0xec.  For
81    OpenBSD 3.5 and earlier releases, we find it at offset 0xe8.  */
82 
83 static const int sparc64obsd_page_size = 8192;
84 static const int sparc64obsd_sigreturn_offset[] = { 0xf0, 0xec, 0xe8, -1 };
85 
86 static int
87 sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
88 {
89   CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
90   unsigned long insn;
91   const int *offset;
92 
93   if (name)
94     return 0;
95 
96   for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
97     {
98       /* Check for "restore %g0, SYS_sigreturn, %g1".  */
99       insn = sparc_fetch_instruction (start_pc + *offset);
100       if (insn != 0x83e82067)
101 	continue;
102 
103       /* Check for "t ST_SYSCALL".  */
104       insn = sparc_fetch_instruction (start_pc + *offset + 8);
105       if (insn != 0x91d02000)
106 	continue;
107 
108       return 1;
109     }
110 
111   return 0;
112 }
113 
114 static struct sparc_frame_cache *
115 sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
116 {
117   struct sparc_frame_cache *cache;
118   CORE_ADDR addr;
119 
120   if (*this_cache)
121     return *this_cache;
122 
123   cache = sparc_frame_cache (next_frame, this_cache);
124   gdb_assert (cache == *this_cache);
125 
126   /* If we couldn't find the frame's function, we're probably dealing
127      with an on-stack signal trampoline.  */
128   if (cache->pc == 0)
129     {
130       cache->pc = frame_pc_unwind (next_frame);
131       cache->pc &= ~(sparc64obsd_page_size - 1);
132 
133       /* Since we couldn't find the frame's function, the cache was
134          initialized under the assumption that we're frameless.  */
135       cache->frameless_p = 0;
136       addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
137       cache->base = addr;
138     }
139 
140   /* We find the appropriate instance of `struct sigcontext' at a
141      fixed offset in the signal frame.  */
142   addr = cache->base + BIAS + 128 + 16;
143   cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
144 
145   return cache;
146 }
147 
148 static void
149 sparc64obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
150 			   struct frame_id *this_id)
151 {
152   struct sparc_frame_cache *cache =
153     sparc64obsd_frame_cache (next_frame, this_cache);
154 
155   (*this_id) = frame_id_build (cache->base, cache->pc);
156 }
157 
158 static void
159 sparc64obsd_frame_prev_register (struct frame_info *next_frame,
160 				 void **this_cache,
161 				 int regnum, int *optimizedp,
162 				 enum lval_type *lvalp, CORE_ADDR *addrp,
163 				 int *realnump, void *valuep)
164 {
165   struct sparc_frame_cache *cache =
166     sparc64obsd_frame_cache (next_frame, this_cache);
167 
168   trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
169 				optimizedp, lvalp, addrp, realnump, valuep);
170 }
171 
172 static const struct frame_unwind sparc64obsd_frame_unwind =
173 {
174   SIGTRAMP_FRAME,
175   sparc64obsd_frame_this_id,
176   sparc64obsd_frame_prev_register
177 };
178 
179 static const struct frame_unwind *
180 sparc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
181 {
182   CORE_ADDR pc = frame_pc_unwind (next_frame);
183   char *name;
184 
185   find_pc_partial_function (pc, &name, NULL, NULL);
186   if (sparc64obsd_pc_in_sigtramp (pc, name))
187     return &sparc64obsd_frame_unwind;
188 
189   return NULL;
190 }
191 
192 /* Kernel debugging support.  */
193 
194 static struct sparc_frame_cache *
195 sparc64obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache)
196 {
197   struct sparc_frame_cache *cache;
198   CORE_ADDR sp, trapframe_addr;
199   int regnum;
200 
201   if (*this_cache)
202     return *this_cache;
203 
204   cache = sparc_frame_cache (next_frame, this_cache);
205   gdb_assert (cache == *this_cache);
206 
207   sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
208   trapframe_addr = sp + BIAS + 176;
209 
210   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
211 
212   cache->saved_regs[SPARC64_STATE_REGNUM].addr = trapframe_addr;
213   cache->saved_regs[SPARC64_PC_REGNUM].addr = trapframe_addr + 8;
214   cache->saved_regs[SPARC64_NPC_REGNUM].addr = trapframe_addr + 16;
215 
216   for (regnum = SPARC_G0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
217     cache->saved_regs[regnum].addr =
218       trapframe_addr + 48 + (regnum - SPARC_G0_REGNUM) * 8;
219 
220   return cache;
221 }
222 
223 static void
224 sparc64obsd_trapframe_this_id (struct frame_info *next_frame,
225 			       void **this_cache, struct frame_id *this_id)
226 {
227   struct sparc_frame_cache *cache =
228     sparc64obsd_trapframe_cache (next_frame, this_cache);
229 
230   (*this_id) = frame_id_build (cache->base, cache->pc);
231 }
232 
233 static void
234 sparc64obsd_trapframe_prev_register (struct frame_info *next_frame,
235 				     void **this_cache,
236 				     int regnum, int *optimizedp,
237 				     enum lval_type *lvalp, CORE_ADDR *addrp,
238 				     int *realnump, void *valuep)
239 {
240   struct sparc_frame_cache *cache =
241     sparc64obsd_trapframe_cache (next_frame, this_cache);
242 
243   trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
244 				optimizedp, lvalp, addrp, realnump, valuep);
245 }
246 
247 static const struct frame_unwind sparc64obsd_trapframe_unwind =
248 {
249   NORMAL_FRAME,
250   sparc64obsd_trapframe_this_id,
251   sparc64obsd_trapframe_prev_register
252 };
253 
254 static const struct frame_unwind *
255 sparc64obsd_trapframe_sniffer (struct frame_info *next_frame)
256 {
257   ULONGEST pstate;
258   char *name;
259 
260   /* Check whether we are in privileged mode, and bail out if we're not.  */
261   pstate = frame_unwind_register_unsigned (next_frame, SPARC64_PSTATE_REGNUM);
262   if ((pstate & SPARC64_PSTATE_PRIV) == 0)
263     return NULL;
264 
265   find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL);
266   if (name && ((strcmp (name, "Lslowtrap_reenter") == 0)
267 	       || (strcmp (name, "Ldatafault_internal") == 0)))
268     return &sparc64obsd_trapframe_unwind;
269 
270   return NULL;
271 }
272 
273 
274 static void
275 sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
276 {
277   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
278 
279   tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
280   tdep->sizeof_gregset = 832;
281 
282   frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
283   frame_unwind_append_sniffer (gdbarch, sparc64obsd_trapframe_sniffer);
284 
285   sparc64_init_abi (info, gdbarch);
286 
287   /* OpenBSD/sparc64 has SVR4-style shared libraries...  */
288   set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
289   set_solib_svr4_fetch_link_map_offsets
290     (gdbarch, svr4_lp64_fetch_link_map_offsets);
291   set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
292 }
293 
294 
295 /* Provide a prototype to silence -Wmissing-prototypes.  */
296 void _initialize_sparc64obsd_tdep (void);
297 
298 void
299 _initialize_sparc64obsd_tdep (void)
300 {
301   gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
302 			  GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi);
303 }
304