xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/alpha-netbsd-tdep.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1*6881a400Schristos /* Target-dependent code for NetBSD/alpha.
2*6881a400Schristos 
3*6881a400Schristos    Copyright (C) 2002-2023 Free Software Foundation, Inc.
4*6881a400Schristos 
5*6881a400Schristos    Contributed by Wasabi Systems, Inc.
6*6881a400Schristos 
7*6881a400Schristos    This file is part of GDB.
8*6881a400Schristos 
9*6881a400Schristos    This program is free software; you can redistribute it and/or modify
10*6881a400Schristos    it under the terms of the GNU General Public License as published by
11*6881a400Schristos    the Free Software Foundation; either version 3 of the License, or
12*6881a400Schristos    (at your option) any later version.
13*6881a400Schristos 
14*6881a400Schristos    This program is distributed in the hope that it will be useful,
15*6881a400Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
16*6881a400Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*6881a400Schristos    GNU General Public License for more details.
18*6881a400Schristos 
19*6881a400Schristos    You should have received a copy of the GNU General Public License
20*6881a400Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21*6881a400Schristos 
22*6881a400Schristos #include "defs.h"
23*6881a400Schristos #include "frame.h"
24*6881a400Schristos #include "gdbcore.h"
25*6881a400Schristos #include "osabi.h"
26*6881a400Schristos #include "regcache.h"
27*6881a400Schristos #include "regset.h"
28*6881a400Schristos #include "value.h"
29*6881a400Schristos 
30*6881a400Schristos #include "alpha-tdep.h"
31*6881a400Schristos #include "alpha-bsd-tdep.h"
32*6881a400Schristos #include "netbsd-tdep.h"
33*6881a400Schristos #include "solib-svr4.h"
34*6881a400Schristos #include "target.h"
35*6881a400Schristos 
36*6881a400Schristos /* Core file support.  */
37*6881a400Schristos 
38*6881a400Schristos /* Sizeof `struct reg' in <machine/reg.h>.  */
39*6881a400Schristos #define ALPHANBSD_SIZEOF_GREGS	(32 * 8)
40*6881a400Schristos 
41*6881a400Schristos /* Sizeof `struct fpreg' in <machine/reg.h.  */
42*6881a400Schristos #define ALPHANBSD_SIZEOF_FPREGS	((32 * 8) + 8)
43*6881a400Schristos 
44*6881a400Schristos /* Supply register REGNUM from the buffer specified by FPREGS and LEN
45*6881a400Schristos    in the floating-point register set REGSET to register cache
46*6881a400Schristos    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
47*6881a400Schristos 
48*6881a400Schristos static void
49*6881a400Schristos alphanbsd_supply_fpregset (const struct regset *regset,
50*6881a400Schristos 			   struct regcache *regcache,
51*6881a400Schristos 			   int regnum, const void *fpregs, size_t len)
52*6881a400Schristos {
53*6881a400Schristos   const gdb_byte *regs = (const gdb_byte *) fpregs;
54*6881a400Schristos   int i;
55*6881a400Schristos 
56*6881a400Schristos   gdb_assert (len >= ALPHANBSD_SIZEOF_FPREGS);
57*6881a400Schristos 
58*6881a400Schristos   for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
59*6881a400Schristos     {
60*6881a400Schristos       if (regnum == i || regnum == -1)
61*6881a400Schristos 	regcache->raw_supply (i, regs + (i - ALPHA_FP0_REGNUM) * 8);
62*6881a400Schristos     }
63*6881a400Schristos 
64*6881a400Schristos   if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
65*6881a400Schristos     regcache->raw_supply (ALPHA_FPCR_REGNUM, regs + 32 * 8);
66*6881a400Schristos }
67*6881a400Schristos 
68*6881a400Schristos /* Supply register REGNUM from the buffer specified by GREGS and LEN
69*6881a400Schristos    in the general-purpose register set REGSET to register cache
70*6881a400Schristos    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
71*6881a400Schristos 
72*6881a400Schristos static void
73*6881a400Schristos alphanbsd_aout_supply_gregset (const struct regset *regset,
74*6881a400Schristos 			       struct regcache *regcache,
75*6881a400Schristos 			       int regnum, const void *gregs, size_t len)
76*6881a400Schristos {
77*6881a400Schristos   const gdb_byte *regs = (const gdb_byte *) gregs;
78*6881a400Schristos   int i;
79*6881a400Schristos 
80*6881a400Schristos   /* Table to map a GDB register number to a trapframe register index.  */
81*6881a400Schristos   static const int regmap[] =
82*6881a400Schristos   {
83*6881a400Schristos      0,   1,   2,   3,
84*6881a400Schristos      4,   5,   6,   7,
85*6881a400Schristos      8,   9,  10,  11,
86*6881a400Schristos     12,  13,  14,  15,
87*6881a400Schristos     30,  31,  32,  16,
88*6881a400Schristos     17,  18,  19,  20,
89*6881a400Schristos     21,  22,  23,  24,
90*6881a400Schristos     25,  29,  26
91*6881a400Schristos   };
92*6881a400Schristos 
93*6881a400Schristos   gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
94*6881a400Schristos 
95*6881a400Schristos   for (i = 0; i < ARRAY_SIZE(regmap); i++)
96*6881a400Schristos     {
97*6881a400Schristos       if (regnum == i || regnum == -1)
98*6881a400Schristos 	regcache->raw_supply (i, regs + regmap[i] * 8);
99*6881a400Schristos     }
100*6881a400Schristos 
101*6881a400Schristos   if (regnum == ALPHA_PC_REGNUM || regnum == -1)
102*6881a400Schristos     regcache->raw_supply (ALPHA_PC_REGNUM, regs + 31 * 8);
103*6881a400Schristos 
104*6881a400Schristos   if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
105*6881a400Schristos     {
106*6881a400Schristos       regs += ALPHANBSD_SIZEOF_GREGS;
107*6881a400Schristos       len -= ALPHANBSD_SIZEOF_GREGS;
108*6881a400Schristos       alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len);
109*6881a400Schristos     }
110*6881a400Schristos }
111*6881a400Schristos 
112*6881a400Schristos /* Supply register REGNUM from the buffer specified by GREGS and LEN
113*6881a400Schristos    in the general-purpose register set REGSET to register cache
114*6881a400Schristos    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
115*6881a400Schristos 
116*6881a400Schristos static void
117*6881a400Schristos alphanbsd_supply_gregset (const struct regset *regset,
118*6881a400Schristos 			  struct regcache *regcache,
119*6881a400Schristos 			  int regnum, const void *gregs, size_t len)
120*6881a400Schristos {
121*6881a400Schristos   const gdb_byte *regs = (const gdb_byte *) gregs;
122*6881a400Schristos   int i;
123*6881a400Schristos 
124*6881a400Schristos   if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
125*6881a400Schristos     {
126*6881a400Schristos       alphanbsd_aout_supply_gregset (regset, regcache, regnum, gregs, len);
127*6881a400Schristos       return;
128*6881a400Schristos     }
129*6881a400Schristos 
130*6881a400Schristos   for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
131*6881a400Schristos     {
132*6881a400Schristos       if (regnum == i || regnum == -1)
133*6881a400Schristos 	regcache->raw_supply (i, regs + i * 8);
134*6881a400Schristos     }
135*6881a400Schristos 
136*6881a400Schristos   if (regnum == ALPHA_PC_REGNUM || regnum == -1)
137*6881a400Schristos     regcache->raw_supply (ALPHA_PC_REGNUM, regs + 31 * 8);
138*6881a400Schristos }
139*6881a400Schristos 
140*6881a400Schristos /* NetBSD/alpha register sets.  */
141*6881a400Schristos 
142*6881a400Schristos static const struct regset alphanbsd_gregset =
143*6881a400Schristos {
144*6881a400Schristos   NULL,
145*6881a400Schristos   alphanbsd_supply_gregset,
146*6881a400Schristos   NULL,
147*6881a400Schristos   REGSET_VARIABLE_SIZE
148*6881a400Schristos };
149*6881a400Schristos 
150*6881a400Schristos static const struct regset alphanbsd_fpregset =
151*6881a400Schristos {
152*6881a400Schristos   NULL,
153*6881a400Schristos   alphanbsd_supply_fpregset
154*6881a400Schristos };
155*6881a400Schristos 
156*6881a400Schristos /* Iterate over supported core file register note sections. */
157*6881a400Schristos 
158*6881a400Schristos void
159*6881a400Schristos alphanbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
160*6881a400Schristos 					iterate_over_regset_sections_cb *cb,
161*6881a400Schristos 					void *cb_data,
162*6881a400Schristos 					const struct regcache *regcache)
163*6881a400Schristos {
164*6881a400Schristos   cb (".reg", ALPHANBSD_SIZEOF_GREGS, ALPHANBSD_SIZEOF_GREGS,
165*6881a400Schristos       &alphanbsd_gregset, NULL, cb_data);
166*6881a400Schristos   cb (".reg2", ALPHANBSD_SIZEOF_FPREGS, ALPHANBSD_SIZEOF_FPREGS,
167*6881a400Schristos       &alphanbsd_fpregset, NULL, cb_data);
168*6881a400Schristos }
169*6881a400Schristos 
170*6881a400Schristos 
171*6881a400Schristos /* Signal trampolines.  */
172*6881a400Schristos 
173*6881a400Schristos /* Under NetBSD/alpha, signal handler invocations can be identified by the
174*6881a400Schristos    designated code sequence that is used to return from a signal handler.
175*6881a400Schristos    In particular, the return address of a signal handler points to the
176*6881a400Schristos    following code sequence:
177*6881a400Schristos 
178*6881a400Schristos 	ldq	a0, 0(sp)
179*6881a400Schristos 	lda	sp, 16(sp)
180*6881a400Schristos 	lda	v0, 295(zero)	# __sigreturn14
181*6881a400Schristos 	call_pal callsys
182*6881a400Schristos 
183*6881a400Schristos    Each instruction has a unique encoding, so we simply attempt to match
184*6881a400Schristos    the instruction the PC is pointing to with any of the above instructions.
185*6881a400Schristos    If there is a hit, we know the offset to the start of the designated
186*6881a400Schristos    sequence and can then check whether we really are executing in the
187*6881a400Schristos    signal trampoline.  If not, -1 is returned, otherwise the offset from the
188*6881a400Schristos    start of the return sequence is returned.  */
189*6881a400Schristos static const gdb_byte sigtramp_retcode[] =
190*6881a400Schristos {
191*6881a400Schristos   0x00, 0x00, 0x1e, 0xa6,	/* ldq a0, 0(sp) */
192*6881a400Schristos   0x10, 0x00, 0xde, 0x23,	/* lda sp, 16(sp) */
193*6881a400Schristos   0x27, 0x01, 0x1f, 0x20,	/* lda v0, 295(zero) */
194*6881a400Schristos   0x83, 0x00, 0x00, 0x00,	/* call_pal callsys */
195*6881a400Schristos };
196*6881a400Schristos #define RETCODE_NWORDS		4
197*6881a400Schristos #define RETCODE_SIZE		(RETCODE_NWORDS * 4)
198*6881a400Schristos 
199*6881a400Schristos static LONGEST
200*6881a400Schristos alphanbsd_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
201*6881a400Schristos {
202*6881a400Schristos   gdb_byte ret[RETCODE_SIZE], w[4];
203*6881a400Schristos   LONGEST off;
204*6881a400Schristos   int i;
205*6881a400Schristos 
206*6881a400Schristos   if (target_read_memory (pc, w, 4) != 0)
207*6881a400Schristos     return -1;
208*6881a400Schristos 
209*6881a400Schristos   for (i = 0; i < RETCODE_NWORDS; i++)
210*6881a400Schristos     {
211*6881a400Schristos       if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
212*6881a400Schristos 	break;
213*6881a400Schristos     }
214*6881a400Schristos   if (i == RETCODE_NWORDS)
215*6881a400Schristos     return (-1);
216*6881a400Schristos 
217*6881a400Schristos   off = i * 4;
218*6881a400Schristos   pc -= off;
219*6881a400Schristos 
220*6881a400Schristos   if (target_read_memory (pc, ret, sizeof (ret)) != 0)
221*6881a400Schristos     return -1;
222*6881a400Schristos 
223*6881a400Schristos   if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
224*6881a400Schristos     return off;
225*6881a400Schristos 
226*6881a400Schristos   return -1;
227*6881a400Schristos }
228*6881a400Schristos 
229*6881a400Schristos static int
230*6881a400Schristos alphanbsd_pc_in_sigtramp (struct gdbarch *gdbarch,
231*6881a400Schristos 		 	  CORE_ADDR pc, const char *func_name)
232*6881a400Schristos {
233*6881a400Schristos   return (nbsd_pc_in_sigtramp (pc, func_name)
234*6881a400Schristos 	  || alphanbsd_sigtramp_offset (gdbarch, pc) >= 0);
235*6881a400Schristos }
236*6881a400Schristos 
237*6881a400Schristos static CORE_ADDR
238*6881a400Schristos alphanbsd_sigcontext_addr (frame_info_ptr frame)
239*6881a400Schristos {
240*6881a400Schristos   /* FIXME: This is not correct for all versions of NetBSD/alpha.
241*6881a400Schristos      We will probably need to disassemble the trampoline to figure
242*6881a400Schristos      out which trampoline frame type we have.  */
243*6881a400Schristos   if (!get_next_frame (frame))
244*6881a400Schristos     return 0;
245*6881a400Schristos   return get_frame_base (get_next_frame (frame));
246*6881a400Schristos }
247*6881a400Schristos 
248*6881a400Schristos 
249*6881a400Schristos static void
250*6881a400Schristos alphanbsd_init_abi (struct gdbarch_info info,
251*6881a400Schristos 		    struct gdbarch *gdbarch)
252*6881a400Schristos {
253*6881a400Schristos   alpha_gdbarch_tdep *tdep = gdbarch_tdep<alpha_gdbarch_tdep> (gdbarch);
254*6881a400Schristos 
255*6881a400Schristos   /* Hook into the DWARF CFI frame unwinder.  */
256*6881a400Schristos   alpha_dwarf2_init_abi (info, gdbarch);
257*6881a400Schristos 
258*6881a400Schristos   /* Hook into the MDEBUG frame unwinder.  */
259*6881a400Schristos   alpha_mdebug_init_abi (info, gdbarch);
260*6881a400Schristos 
261*6881a400Schristos   nbsd_init_abi (info, gdbarch);
262*6881a400Schristos 
263*6881a400Schristos   /* NetBSD/alpha does not provide single step support via ptrace(2); we
264*6881a400Schristos      must use software single-stepping.  */
265*6881a400Schristos   set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
266*6881a400Schristos 
267*6881a400Schristos   /* NetBSD/alpha has SVR4-style shared libraries.  */
268*6881a400Schristos   set_solib_svr4_fetch_link_map_offsets
269*6881a400Schristos     (gdbarch, svr4_lp64_fetch_link_map_offsets);
270*6881a400Schristos 
271*6881a400Schristos   tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
272*6881a400Schristos   tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
273*6881a400Schristos   tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
274*6881a400Schristos 
275*6881a400Schristos   tdep->jb_pc = 2;
276*6881a400Schristos   tdep->jb_elt_size = 8;
277*6881a400Schristos 
278*6881a400Schristos   set_gdbarch_iterate_over_regset_sections
279*6881a400Schristos     (gdbarch, alphanbsd_iterate_over_regset_sections);
280*6881a400Schristos }
281*6881a400Schristos 
282*6881a400Schristos 
283*6881a400Schristos void _initialize_alphanbsd_tdep ();
284*6881a400Schristos void
285*6881a400Schristos _initialize_alphanbsd_tdep ()
286*6881a400Schristos {
287*6881a400Schristos   /* Even though NetBSD/alpha used ELF since day one, it used the
288*6881a400Schristos      traditional a.out-style core dump format before NetBSD 1.6, but
289*6881a400Schristos      we don't support those.  */
290*6881a400Schristos   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD,
291*6881a400Schristos 			  alphanbsd_init_abi);
292*6881a400Schristos }
293