1/* Target-dependent code for OpenBSD/sparc64.
2
3   Copyright (C) 2004, 2005, 2006, 2007 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 3 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, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "frame.h"
22#include "frame-unwind.h"
23#include "gdbcore.h"
24#include "osabi.h"
25#include "regcache.h"
26#include "regset.h"
27#include "symtab.h"
28#include "objfiles.h"
29#include "trad-frame.h"
30
31#include "gdb_assert.h"
32
33#include "obsd-tdep.h"
34#include "sparc64-tdep.h"
35#include "solib-svr4.h"
36#include "bsd-uthread.h"
37
38/* OpenBSD uses the traditional NetBSD core file format, even for
39   ports that use ELF.  The core files don't use multiple register
40   sets.  Instead, the general-purpose and floating-point registers
41   are lumped together in a single section.  Unlike on NetBSD, OpenBSD
42   uses a different layout for its general-purpose registers than the
43   layout used for ptrace(2).  */
44
45/* From <machine/reg.h>.  */
46const struct sparc_gregset sparc64obsd_core_gregset =
47{
48  0 * 8,			/* "tstate" */
49  1 * 8,			/* %pc */
50  2 * 8,			/* %npc */
51  3 * 8,			/* %y */
52  -1,				/* %fprs */
53  -1,
54  7 * 8,			/* %g1 */
55  22 * 8,			/* %l0 */
56  4				/* sizeof (%y) */
57};
58
59static void
60sparc64obsd_supply_gregset (const struct regset *regset,
61			    struct regcache *regcache,
62			    int regnum, const void *gregs, size_t len)
63{
64  const char *regs = gregs;
65
66  sparc64_supply_gregset (&sparc64obsd_core_gregset, regcache, regnum, regs);
67  sparc64_supply_fpregset (regcache, regnum, regs + 288);
68}
69
70
71/* Signal trampolines.  */
72
73/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
74   in virtual memory.  The randomness makes it somewhat tricky to
75   detect it, but fortunately we can rely on the fact that the start
76   of the sigtramp routine is page-aligned.  We recognize the
77   trampoline by looking for the code that invokes the sigreturn
78   system call.  The offset where we can find that code varies from
79   release to release.
80
81   By the way, the mapping mentioned above is read-only, so you cannot
82   place a breakpoint in the signal trampoline.  */
83
84/* Default page size.  */
85static const int sparc64obsd_page_size = 8192;
86
87/* Offset for sigreturn(2).  */
88static const int sparc64obsd_sigreturn_offset[] = {
89  0xf0,				/* OpenBSD 3.8 */
90  0xec,				/* OpenBSD 3.6 */
91  0xe8,				/* OpenBSD 3.2 */
92  -1
93};
94
95static int
96sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
97{
98  CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
99  unsigned long insn;
100  const int *offset;
101
102  if (name)
103    return 0;
104
105  for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
106    {
107      /* Check for "restore %g0, SYS_sigreturn, %g1".  */
108      insn = sparc_fetch_instruction (start_pc + *offset);
109      if (insn != 0x83e82067)
110	continue;
111
112      /* Check for "t ST_SYSCALL".  */
113      insn = sparc_fetch_instruction (start_pc + *offset + 8);
114      if (insn != 0x91d02000)
115	continue;
116
117      return 1;
118    }
119
120  return 0;
121}
122
123static struct sparc_frame_cache *
124sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
125{
126  struct sparc_frame_cache *cache;
127  CORE_ADDR addr;
128
129  if (*this_cache)
130    return *this_cache;
131
132  cache = sparc_frame_cache (next_frame, this_cache);
133  gdb_assert (cache == *this_cache);
134
135  /* If we couldn't find the frame's function, we're probably dealing
136     with an on-stack signal trampoline.  */
137  if (cache->pc == 0)
138    {
139      cache->pc = frame_pc_unwind (next_frame);
140      cache->pc &= ~(sparc64obsd_page_size - 1);
141
142      /* Since we couldn't find the frame's function, the cache was
143         initialized under the assumption that we're frameless.  */
144      cache->frameless_p = 0;
145      addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
146      if (addr & 1)
147	addr += BIAS;
148      cache->base = addr;
149    }
150
151  /* We find the appropriate instance of `struct sigcontext' at a
152     fixed offset in the signal frame.  */
153  addr = cache->base + 128 + 16;
154  cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
155
156  return cache;
157}
158
159static void
160sparc64obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
161			   struct frame_id *this_id)
162{
163  struct sparc_frame_cache *cache =
164    sparc64obsd_frame_cache (next_frame, this_cache);
165
166  (*this_id) = frame_id_build (cache->base, cache->pc);
167}
168
169static void
170sparc64obsd_frame_prev_register (struct frame_info *next_frame,
171				 void **this_cache,
172				 int regnum, int *optimizedp,
173				 enum lval_type *lvalp, CORE_ADDR *addrp,
174				 int *realnump, gdb_byte *valuep)
175{
176  struct sparc_frame_cache *cache =
177    sparc64obsd_frame_cache (next_frame, this_cache);
178
179  trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
180				optimizedp, lvalp, addrp, realnump, valuep);
181}
182
183static const struct frame_unwind sparc64obsd_frame_unwind =
184{
185  SIGTRAMP_FRAME,
186  sparc64obsd_frame_this_id,
187  sparc64obsd_frame_prev_register
188};
189
190static const struct frame_unwind *
191sparc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
192{
193  CORE_ADDR pc = frame_pc_unwind (next_frame);
194  char *name;
195
196  find_pc_partial_function (pc, &name, NULL, NULL);
197  if (sparc64obsd_pc_in_sigtramp (pc, name))
198    return &sparc64obsd_frame_unwind;
199
200  return NULL;
201}
202
203/* Kernel debugging support.  */
204
205static struct sparc_frame_cache *
206sparc64obsd_trapframe_cache (struct frame_info *next_frame, void **this_cache)
207{
208  struct sparc_frame_cache *cache;
209  CORE_ADDR sp, trapframe_addr;
210  int regnum;
211
212  if (*this_cache)
213    return *this_cache;
214
215  cache = sparc_frame_cache (next_frame, this_cache);
216  gdb_assert (cache == *this_cache);
217
218  sp = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
219  trapframe_addr = sp + BIAS + 176;
220
221  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
222
223  cache->saved_regs[SPARC64_STATE_REGNUM].addr = trapframe_addr;
224  cache->saved_regs[SPARC64_PC_REGNUM].addr = trapframe_addr + 8;
225  cache->saved_regs[SPARC64_NPC_REGNUM].addr = trapframe_addr + 16;
226
227  for (regnum = SPARC_G0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
228    cache->saved_regs[regnum].addr =
229      trapframe_addr + 48 + (regnum - SPARC_G0_REGNUM) * 8;
230
231  return cache;
232}
233
234static void
235sparc64obsd_trapframe_this_id (struct frame_info *next_frame,
236			       void **this_cache, struct frame_id *this_id)
237{
238  struct sparc_frame_cache *cache =
239    sparc64obsd_trapframe_cache (next_frame, this_cache);
240
241  (*this_id) = frame_id_build (cache->base, cache->pc);
242}
243
244static void
245sparc64obsd_trapframe_prev_register (struct frame_info *next_frame,
246				     void **this_cache,
247				     int regnum, int *optimizedp,
248				     enum lval_type *lvalp, CORE_ADDR *addrp,
249				     int *realnump, gdb_byte *valuep)
250{
251  struct sparc_frame_cache *cache =
252    sparc64obsd_trapframe_cache (next_frame, this_cache);
253
254  trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
255				optimizedp, lvalp, addrp, realnump, valuep);
256}
257
258static const struct frame_unwind sparc64obsd_trapframe_unwind =
259{
260  NORMAL_FRAME,
261  sparc64obsd_trapframe_this_id,
262  sparc64obsd_trapframe_prev_register
263};
264
265static const struct frame_unwind *
266sparc64obsd_trapframe_sniffer (struct frame_info *next_frame)
267{
268  CORE_ADDR pc;
269  ULONGEST pstate;
270  char *name;
271
272  /* Check whether we are in privileged mode, and bail out if we're not.  */
273  pstate = frame_unwind_register_unsigned (next_frame, SPARC64_PSTATE_REGNUM);
274  if ((pstate & SPARC64_PSTATE_PRIV) == 0)
275    return NULL;
276
277  pc = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
278  find_pc_partial_function (pc, &name, NULL, NULL);
279  if (name && strcmp (name, "Lslowtrap_reenter") == 0)
280    return &sparc64obsd_trapframe_unwind;
281
282  return NULL;
283}
284
285
286/* Threads support.  */
287
288/* Offset wthin the thread structure where we can find %fp and %i7.  */
289#define SPARC64OBSD_UTHREAD_FP_OFFSET	232
290#define SPARC64OBSD_UTHREAD_PC_OFFSET	240
291
292static void
293sparc64obsd_supply_uthread (struct regcache *regcache,
294			    int regnum, CORE_ADDR addr)
295{
296  CORE_ADDR fp, fp_addr = addr + SPARC64OBSD_UTHREAD_FP_OFFSET;
297  gdb_byte buf[8];
298
299  gdb_assert (regnum >= -1);
300
301  fp = read_memory_unsigned_integer (fp_addr, 8);
302  if (regnum == SPARC_SP_REGNUM || regnum == -1)
303    {
304      store_unsigned_integer (buf, 8, fp);
305      regcache_raw_supply (regcache, SPARC_SP_REGNUM, buf);
306
307      if (regnum == SPARC_SP_REGNUM)
308	return;
309    }
310
311  if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM
312      || regnum == -1)
313    {
314      CORE_ADDR i7, i7_addr = addr + SPARC64OBSD_UTHREAD_PC_OFFSET;
315
316      i7 = read_memory_unsigned_integer (i7_addr, 8);
317      if (regnum == SPARC64_PC_REGNUM || regnum == -1)
318	{
319	  store_unsigned_integer (buf, 8, i7 + 8);
320	  regcache_raw_supply (regcache, SPARC64_PC_REGNUM, buf);
321	}
322      if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
323	{
324	  store_unsigned_integer (buf, 8, i7 + 12);
325	  regcache_raw_supply (regcache, SPARC64_NPC_REGNUM, buf);
326	}
327
328      if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
329	return;
330    }
331
332  sparc_supply_rwindow (regcache, fp, regnum);
333}
334
335static void
336sparc64obsd_collect_uthread(const struct regcache *regcache,
337			    int regnum, CORE_ADDR addr)
338{
339  CORE_ADDR sp;
340  gdb_byte buf[8];
341
342  gdb_assert (regnum >= -1);
343
344  if (regnum == SPARC_SP_REGNUM || regnum == -1)
345    {
346      CORE_ADDR fp_addr = addr + SPARC64OBSD_UTHREAD_FP_OFFSET;
347
348      regcache_raw_collect (regcache, SPARC_SP_REGNUM, buf);
349      write_memory (fp_addr,buf, 8);
350    }
351
352  if (regnum == SPARC64_PC_REGNUM || regnum == -1)
353    {
354      CORE_ADDR i7, i7_addr = addr + SPARC64OBSD_UTHREAD_PC_OFFSET;
355
356      regcache_raw_collect (regcache, SPARC64_PC_REGNUM, buf);
357      i7 = extract_unsigned_integer (buf, 8) - 8;
358      write_memory_unsigned_integer (i7_addr, 8, i7);
359
360      if (regnum == SPARC64_PC_REGNUM)
361	return;
362    }
363
364  regcache_raw_collect (regcache, SPARC_SP_REGNUM, buf);
365  sp = extract_unsigned_integer (buf, 8);
366  sparc_collect_rwindow (regcache, sp, regnum);
367}
368
369
370static void
371sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
372{
373  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
374
375  tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
376  tdep->sizeof_gregset = 832;
377
378  /* Make sure we can single-step "new" syscalls.  */
379  tdep->step_trap = sparcnbsd_step_trap;
380
381  frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
382  frame_unwind_append_sniffer (gdbarch, sparc64obsd_trapframe_sniffer);
383
384  sparc64_init_abi (info, gdbarch);
385
386  /* OpenBSD/sparc64 has SVR4-style shared libraries.  */
387  set_solib_svr4_fetch_link_map_offsets
388    (gdbarch, svr4_lp64_fetch_link_map_offsets);
389  set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
390
391  /* OpenBSD provides a user-level threads implementation.  */
392  bsd_uthread_set_supply_uthread (gdbarch, sparc64obsd_supply_uthread);
393  bsd_uthread_set_collect_uthread (gdbarch, sparc64obsd_collect_uthread);
394}
395
396
397/* Provide a prototype to silence -Wmissing-prototypes.  */
398void _initialize_sparc64obsd_tdep (void);
399
400void
401_initialize_sparc64obsd_tdep (void)
402{
403  gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
404			  GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi);
405}
406