1 /* Target-dependent code for NetBSD/mips.
3 Copyright (C) 2002-2017 Free Software Foundation, Inc.
5 Contributed by Wasabi Systems, Inc.
7 This file is part of GDB.
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.
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.
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/>. */
30 #include "nbsd-tdep.h"
31 #include "mips-nbsd-tdep.h"
32 #include "mips-tdep.h"
34 #include "solib-svr4.h"
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
41 /* Core file support. */
43 /* Number of registers in `struct reg' from <machine/reg.h>. */
44 #define MIPSNBSD_NUM_GREGS 38
46 /* Number of registers in `struct fpreg' from <machine/reg.h>. */
47 #define MIPSNBSD_NUM_FPREGS 33
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. */
54 mipsnbsd_supply_fpregset (const struct regset *regset,
55 struct regcache *regcache,
56 int regnum, const void *fpregs, size_t len)
58 size_t regsize = mips_isa_regsize (regcache->arch ());
59 const char *regs = (const char *) fpregs;
62 gdb_assert (len >= MIPSNBSD_NUM_FPREGS * regsize);
64 for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
66 if (regnum == i || regnum == -1)
67 regcache_raw_supply (regcache, i,
68 regs + (i - MIPS_FP0_REGNUM) * regsize);
72 /* Supply register REGNUM from the buffer specified by GREGS and LEN
73 in the general-purpose register set REGSET to register cache
74 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
77 mipsnbsd_supply_gregset (const struct regset *regset,
78 struct regcache *regcache, int regnum,
79 const void *gregs, size_t len)
81 size_t regsize = mips_isa_regsize (regcache->arch ());
82 const char *regs = (const char *) gregs;
85 gdb_assert (len >= MIPSNBSD_NUM_GREGS * regsize);
87 for (i = 0; i <= MIPS_PC_REGNUM; i++)
89 if (regnum == i || regnum == -1)
90 regcache_raw_supply (regcache, i, regs + i * regsize);
93 if (len >= (MIPSNBSD_NUM_GREGS + MIPSNBSD_NUM_FPREGS) * regsize)
95 regs += MIPSNBSD_NUM_GREGS * regsize;
96 len -= MIPSNBSD_NUM_GREGS * regsize;
97 mipsnbsd_supply_fpregset (regset, regcache, regnum, regs, len);
101 /* NetBSD/mips register sets. */
103 static const struct regset mipsnbsd_gregset =
106 mipsnbsd_supply_gregset,
111 static const struct regset mipsnbsd_fpregset =
114 mipsnbsd_supply_fpregset
117 /* Iterate over core file register note sections. */
120 mipsnbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
121 iterate_over_regset_sections_cb *cb,
123 const struct regcache *regcache)
125 size_t regsize = mips_isa_regsize (gdbarch);
127 cb (".reg", MIPSNBSD_NUM_GREGS * regsize, &mipsnbsd_gregset,
129 cb (".reg2", MIPSNBSD_NUM_FPREGS * regsize, &mipsnbsd_fpregset,
134 /* Conveniently, GDB uses the same register numbering as the
135 ptrace register structure used by NetBSD/mips. */
138 mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno)
140 struct gdbarch *gdbarch = regcache->arch ();
143 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
145 if (regno == i || regno == -1)
147 if (gdbarch_cannot_fetch_register (gdbarch, i))
148 regcache_raw_supply (regcache, i, NULL);
150 regcache_raw_supply (regcache, i,
151 regs + (i * mips_isa_regsize (gdbarch)));
157 mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
159 struct gdbarch *gdbarch = regcache->arch ();
162 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
163 if ((regno == i || regno == -1)
164 && ! gdbarch_cannot_store_register (gdbarch, i))
165 regcache_raw_collect (regcache, i,
166 regs + (i * mips_isa_regsize (gdbarch)));
170 mipsnbsd_supply_fpreg (struct regcache *regcache,
171 const char *fpregs, int regno)
173 struct gdbarch *gdbarch = regcache->arch ();
176 for (i = gdbarch_fp0_regnum (gdbarch);
177 i <= mips_regnum (gdbarch)->fp_implementation_revision;
180 if (regno == i || regno == -1)
182 if (gdbarch_cannot_fetch_register (gdbarch, i))
183 regcache_raw_supply (regcache, i, NULL);
185 regcache_raw_supply (regcache, i,
187 + ((i - gdbarch_fp0_regnum (gdbarch))
188 * mips_isa_regsize (gdbarch)));
194 mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
196 struct gdbarch *gdbarch = regcache->arch ();
199 for (i = gdbarch_fp0_regnum (gdbarch);
200 i <= mips_regnum (gdbarch)->fp_control_status;
202 if ((regno == i || regno == -1)
203 && ! gdbarch_cannot_store_register (gdbarch, i))
204 regcache_raw_collect (regcache, i,
205 fpregs + ((i - gdbarch_fp0_regnum (gdbarch))
206 * mips_isa_regsize (gdbarch)));
211 /* Under NetBSD/mips, signal handler invocations can be identified by the
212 designated code sequence that is used to return from a signal handler.
213 In particular, the return address of a signal handler points to the
214 following code sequence:
217 li v0, 295 # __sigreturn14
220 Each instruction has a unique encoding, so we simply attempt to match
221 the instruction the PC is pointing to with any of the above instructions.
222 If there is a hit, we know the offset to the start of the designated
223 sequence and can then check whether we really are executing in the
224 signal trampoline. If not, -1 is returned, otherwise the offset from the
225 start of the return sequence is returned. */
227 #define RETCODE_NWORDS 3
228 #define RETCODE_SIZE (RETCODE_NWORDS * 4)
230 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
232 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
233 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
234 0x0c, 0x00, 0x00, 0x00, /* syscall */
237 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
239 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
240 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
241 0x00, 0x00, 0x00, 0x0c, /* syscall */
246 /* Figure out where the longjmp will land. We expect that we have
247 just entered longjmp and haven't yet setup the stack frame, so the
248 args are still in the argument regs. MIPS_A0_REGNUM points at the
249 jmp_buf structure from which we extract the PC that we will land
250 at. The PC is copied into *pc. This routine returns true on
253 #define NBSD_MIPS_JB_PC (2 * 4)
254 #define NBSD_MIPS_JB_ELEMENT_SIZE(gdbarch) mips_isa_regsize (gdbarch)
255 #define NBSD_MIPS_JB_OFFSET(gdbarch) (NBSD_MIPS_JB_PC * \
256 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch))
259 mipsnbsd_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
261 struct gdbarch *gdbarch = get_frame_arch (frame);
262 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
266 buf = (gdb_byte *) alloca (NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch));
268 jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
270 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET (gdbarch), buf,
271 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)))
274 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch),
280 mipsnbsd_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
282 return (regno == MIPS_ZERO_REGNUM
283 || regno == mips_regnum (gdbarch)->fp_implementation_revision);
287 mipsnbsd_cannot_store_register (struct gdbarch *gdbarch, int regno)
289 return (regno == MIPS_ZERO_REGNUM
290 || regno == mips_regnum (gdbarch)->fp_implementation_revision);
293 /* Shared library support. */
295 /* NetBSD/mips uses a slightly different `struct link_map' than the
296 other NetBSD platforms. */
298 static struct link_map_offsets *
299 mipsnbsd_ilp32_fetch_link_map_offsets (void)
301 static struct link_map_offsets lmo;
302 static struct link_map_offsets *lmp = NULL;
308 lmo.r_version_offset = 0;
309 lmo.r_version_size = 4;
310 lmo.r_map_offset = 4;
311 lmo.r_brk_offset = 8;
312 lmo.r_ldsomap_offset = -1;
314 /* Everything we need is in the first 24 bytes. */
315 lmo.link_map_size = 24;
316 lmo.l_addr_offset = 4;
317 lmo.l_name_offset = 8;
318 lmo.l_ld_offset = 12;
319 lmo.l_next_offset = 16;
320 lmo.l_prev_offset = 20;
326 static struct link_map_offsets *
327 mipsnbsd_lp64_fetch_link_map_offsets (void)
329 static struct link_map_offsets lmo;
330 static struct link_map_offsets *lmp = NULL;
336 lmo.r_version_offset = 0;
337 lmo.r_version_size = 4;
338 lmo.r_map_offset = 8;
339 lmo.r_brk_offset = 16;
340 lmo.r_ldsomap_offset = -1;
342 /* Everything we need is in the first 40 bytes. */
343 lmo.link_map_size = 48;
344 lmo.l_addr_offset = 0;
345 lmo.l_name_offset = 16;
346 lmo.l_ld_offset = 24;
347 lmo.l_next_offset = 32;
348 lmo.l_prev_offset = 40;
356 mipsnbsd_init_abi (struct gdbarch_info info,
357 struct gdbarch *gdbarch)
359 set_gdbarch_iterate_over_regset_sections
360 (gdbarch, mipsnbsd_iterate_over_regset_sections);
362 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
364 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
365 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
367 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
369 /* NetBSD/mips has SVR4-style shared libraries. */
370 set_solib_svr4_fetch_link_map_offsets
371 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
372 mipsnbsd_ilp32_fetch_link_map_offsets :
373 mipsnbsd_lp64_fetch_link_map_offsets));
377 _initialize_mipsnbsd_tdep (void)
379 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD,