mips-netbsd-tdep.c revision 1.1 1 /* Target-dependent code for NetBSD/mips.
2
3 Copyright (C) 2002-2023 Free Software Foundation, Inc.
4
5 Contributed by Wasabi Systems, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "defs.h"
23 #include "gdbcore.h"
24 #include "regcache.h"
25 #include "regset.h"
26 #include "target.h"
27 #include "value.h"
28 #include "osabi.h"
29
30 #include "netbsd-tdep.h"
31 #include "mips-netbsd-tdep.h"
32 #include "mips-tdep.h"
33
34 #include "solib-svr4.h"
35
36 /* Shorthand for some register numbers used below. */
37 #define MIPS_PC_REGNUM MIPS_EMBED_PC_REGNUM
38 #define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
39 #define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
40
41 /* Core file support. */
42
43 /* Number of registers in `struct reg' from <machine/reg.h>. */
44 #define MIPSNBSD_NUM_GREGS 38
45
46 /* Number of registers in `struct fpreg' from <machine/reg.h>. */
47 #define MIPSNBSD_NUM_FPREGS 33
48
49 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
50 in the floating-point register set REGSET to register cache
51 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
52
53 static void
54 mipsnbsd_supply_fpregset (const struct regset *regset,
55 struct regcache *regcache,
56 int regnum, const void *fpregs, size_t len)
57 {
58 size_t regsize = mips_isa_regsize (regcache->arch ());
59 const char *regs = (const char *) fpregs;
60 int i;
61
62 gdb_assert (len >= MIPSNBSD_NUM_FPREGS * regsize);
63
64 for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
65 {
66 if (regnum == i || regnum == -1)
67 regcache->raw_supply (i, regs + (i - MIPS_FP0_REGNUM) * regsize);
68 }
69 }
70
71 /* Supply register REGNUM from the buffer specified by GREGS and LEN
72 in the general-purpose register set REGSET to register cache
73 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
74
75 static void
76 mipsnbsd_supply_gregset (const struct regset *regset,
77 struct regcache *regcache, int regnum,
78 const void *gregs, size_t len)
79 {
80 size_t regsize = mips_isa_regsize (regcache->arch ());
81 const char *regs = (const char *) gregs;
82 int i;
83
84 gdb_assert (len >= MIPSNBSD_NUM_GREGS * regsize);
85
86 for (i = 0; i <= MIPS_PC_REGNUM; i++)
87 {
88 if (regnum == i || regnum == -1)
89 regcache->raw_supply (i, regs + i * regsize);
90 }
91
92 if (len >= (MIPSNBSD_NUM_GREGS + MIPSNBSD_NUM_FPREGS) * regsize)
93 {
94 regs += MIPSNBSD_NUM_GREGS * regsize;
95 len -= MIPSNBSD_NUM_GREGS * regsize;
96 mipsnbsd_supply_fpregset (regset, regcache, regnum, regs, len);
97 }
98 if (regnum == -1 || regnum == MIPS_ZERO_REGNUM)
99 regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
100 }
101
102 /* NetBSD/mips register sets. */
103
104 static const struct regset mipsnbsd_gregset =
105 {
106 NULL,
107 mipsnbsd_supply_gregset,
108 NULL,
109 REGSET_VARIABLE_SIZE
110 };
111
112 static const struct regset mipsnbsd_fpregset =
113 {
114 NULL,
115 mipsnbsd_supply_fpregset
116 };
117
118 /* Iterate over core file register note sections. */
119
120 static void
121 mipsnbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
122 iterate_over_regset_sections_cb *cb,
123 void *cb_data,
124 const struct regcache *regcache)
125 {
126 size_t regsize = mips_isa_regsize (gdbarch);
127
128 cb (".reg", MIPSNBSD_NUM_GREGS * regsize, MIPSNBSD_NUM_GREGS * regsize,
129 &mipsnbsd_gregset, NULL, cb_data);
130 cb (".reg2", MIPSNBSD_NUM_FPREGS * regsize, MIPSNBSD_NUM_FPREGS * regsize,
131 &mipsnbsd_fpregset, NULL, cb_data);
132 }
133
134
136 /* Conveniently, GDB uses the same register numbering as the
137 ptrace register structure used by NetBSD/mips. */
138
139 void
140 mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno)
141 {
142 struct gdbarch *gdbarch = regcache->arch ();
143 int i;
144
145 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
146 {
147 if (regno == i || regno == -1)
148 {
149 if (gdbarch_cannot_fetch_register (gdbarch, i))
150 regcache->raw_supply (i, NULL);
151 else
152 regcache->raw_supply
153 (i, regs + (i * mips_isa_regsize (gdbarch)));
154 }
155 }
156 if (regno == -1 || regno == MIPS_ZERO_REGNUM)
157 regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
158 }
159
160 void
161 mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
162 {
163 struct gdbarch *gdbarch = regcache->arch ();
164 int i;
165
166 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
167 if ((regno == i || regno == -1)
168 && ! gdbarch_cannot_store_register (gdbarch, i))
169 regcache->raw_collect (i, regs + (i * mips_isa_regsize (gdbarch)));
170 }
171
172 void
173 mipsnbsd_supply_fpreg (struct regcache *regcache,
174 const char *fpregs, int regno)
175 {
176 struct gdbarch *gdbarch = regcache->arch ();
177 int i;
178
179 for (i = gdbarch_fp0_regnum (gdbarch);
180 i <= mips_regnum (gdbarch)->fp_implementation_revision;
181 i++)
182 {
183 if (regno == i || regno == -1)
184 {
185 if (gdbarch_cannot_fetch_register (gdbarch, i))
186 regcache->raw_supply (i, NULL);
187 else
188 regcache->raw_supply (i,
189 fpregs
190 + ((i - gdbarch_fp0_regnum (gdbarch))
191 * mips_isa_regsize (gdbarch)));
192 }
193 }
194 }
195
196 void
197 mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
198 {
199 struct gdbarch *gdbarch = regcache->arch ();
200 int i;
201
202 for (i = gdbarch_fp0_regnum (gdbarch);
203 i <= mips_regnum (gdbarch)->fp_control_status;
204 i++)
205 if ((regno == i || regno == -1)
206 && ! gdbarch_cannot_store_register (gdbarch, i))
207 regcache->raw_collect
208 (i, (fpregs + ((i - gdbarch_fp0_regnum (gdbarch))
209 * mips_isa_regsize (gdbarch))));
210 }
211
212 #if 0
213
214 /* Under NetBSD/mips, signal handler invocations can be identified by the
215 designated code sequence that is used to return from a signal handler.
216 In particular, the return address of a signal handler points to the
217 following code sequence:
218
219 addu a0, sp, 16
220 li v0, 295 # __sigreturn14
221 syscall
222
223 Each instruction has a unique encoding, so we simply attempt to match
224 the instruction the PC is pointing to with any of the above instructions.
225 If there is a hit, we know the offset to the start of the designated
226 sequence and can then check whether we really are executing in the
227 signal trampoline. If not, -1 is returned, otherwise the offset from the
228 start of the return sequence is returned. */
229
230 #define RETCODE_NWORDS 3
231 #define RETCODE_SIZE (RETCODE_NWORDS * 4)
232
233 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
234 {
235 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
236 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
237 0x0c, 0x00, 0x00, 0x00, /* syscall */
238 };
239
240 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
241 {
242 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
243 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
244 0x00, 0x00, 0x00, 0x0c, /* syscall */
245 };
246
247 #endif
248
249 /* Figure out where the longjmp will land. We expect that we have
250 just entered longjmp and haven't yet setup the stack frame, so the
251 args are still in the argument regs. MIPS_A0_REGNUM points at the
252 jmp_buf structure from which we extract the PC that we will land
253 at. The PC is copied into *pc. This routine returns true on
254 success. */
255
256 #define NBSD_MIPS_JB_PC (2 * 4)
257 #define NBSD_MIPS_JB_ELEMENT_SIZE(gdbarch) mips_isa_regsize (gdbarch)
258 #define NBSD_MIPS_JB_OFFSET(gdbarch) (NBSD_MIPS_JB_PC * \
259 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch))
260
261 static int
262 mipsnbsd_get_longjmp_target (frame_info_ptr frame, CORE_ADDR *pc)
263 {
264 struct gdbarch *gdbarch = get_frame_arch (frame);
265 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
266 CORE_ADDR jb_addr;
267 gdb_byte *buf;
268
269 buf = (gdb_byte *) alloca (NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch));
270
271 jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
272
273 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET (gdbarch), buf,
274 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)))
275 return 0;
276
277 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch),
278 byte_order);
279 return 1;
280 }
281
282 static int
283 mipsnbsd_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
284 {
285 return regno == mips_regnum (gdbarch)->fp_implementation_revision;
286 }
287
288 static int
289 mipsnbsd_cannot_store_register (struct gdbarch *gdbarch, int regno)
290 {
291 return (regno == MIPS_ZERO_REGNUM
292 || regno == mips_regnum (gdbarch)->fp_implementation_revision);
293 }
294
295 /* Shared library support. */
296
297 /* NetBSD/mips uses a slightly different `struct link_map' than the
298 other NetBSD platforms. */
299
300 static struct link_map_offsets *
301 mipsnbsd_ilp32_fetch_link_map_offsets (void)
302 {
303 static struct link_map_offsets lmo;
304 static struct link_map_offsets *lmp = NULL;
305
306 if (lmp == NULL)
307 {
308 lmp = &lmo;
309
310 lmo.r_version_offset = 0;
311 lmo.r_version_size = 4;
312 lmo.r_map_offset = 4;
313 lmo.r_brk_offset = 8;
314 lmo.r_ldsomap_offset = -1;
315 lmo.r_next_offset = -1;
316
317 /* Everything we need is in the first 24 bytes. */
318 lmo.link_map_size = 24;
319 lmo.l_addr_offset = 4;
320 lmo.l_name_offset = 8;
321 lmo.l_ld_offset = 12;
322 lmo.l_next_offset = 16;
323 lmo.l_prev_offset = 20;
324 }
325
326 return lmp;
327 }
328
329 static struct link_map_offsets *
330 mipsnbsd_lp64_fetch_link_map_offsets (void)
331 {
332 static struct link_map_offsets lmo;
333 static struct link_map_offsets *lmp = NULL;
334
335 if (lmp == NULL)
336 {
337 lmp = &lmo;
338
339 lmo.r_version_offset = 0;
340 lmo.r_version_size = 4;
341 lmo.r_map_offset = 8;
342 lmo.r_brk_offset = 16;
343 lmo.r_ldsomap_offset = -1;
344 lmo.r_next_offset = -1;
345
346 /* Everything we need is in the first 40 bytes. */
347 lmo.link_map_size = 48;
348 lmo.l_addr_offset = 0;
349 lmo.l_name_offset = 16;
350 lmo.l_ld_offset = 24;
351 lmo.l_next_offset = 32;
352 lmo.l_prev_offset = 40;
353 }
354
355 return lmp;
356 }
357
358
360 static void
361 mipsnbsd_init_abi (struct gdbarch_info info,
362 struct gdbarch *gdbarch)
363 {
364 nbsd_init_abi (info, gdbarch);
365
366 set_gdbarch_iterate_over_regset_sections
367 (gdbarch, mipsnbsd_iterate_over_regset_sections);
368
369 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
370
371 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
372 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
373
374 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
375
376 /* NetBSD/mips has SVR4-style shared libraries. */
377 set_solib_svr4_fetch_link_map_offsets
378 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
379 mipsnbsd_ilp32_fetch_link_map_offsets :
380 mipsnbsd_lp64_fetch_link_map_offsets));
381 }
382
383 void _initialize_mipsnbsd_tdep ();
384 void
385 _initialize_mipsnbsd_tdep ()
386 {
387 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD,
388 mipsnbsd_init_abi);
389 }
390