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