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 135 /* Conveniently, GDB uses the same register numbering as the 136 ptrace register structure used by NetBSD/mips. */ 137 138 void 139 mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno) 140 { 141 struct gdbarch *gdbarch = regcache->arch (); 142 int i; 143 144 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++) 145 { 146 if (regno == i || regno == -1) 147 { 148 if (gdbarch_cannot_fetch_register (gdbarch, i)) 149 regcache->raw_supply (i, NULL); 150 else 151 regcache->raw_supply 152 (i, regs + (i * mips_isa_regsize (gdbarch))); 153 } 154 } 155 if (regno == -1 || regno == MIPS_ZERO_REGNUM) 156 regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM); 157 } 158 159 void 160 mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno) 161 { 162 struct gdbarch *gdbarch = regcache->arch (); 163 int i; 164 165 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++) 166 if ((regno == i || regno == -1) 167 && ! gdbarch_cannot_store_register (gdbarch, i)) 168 regcache->raw_collect (i, regs + (i * mips_isa_regsize (gdbarch))); 169 } 170 171 void 172 mipsnbsd_supply_fpreg (struct regcache *regcache, 173 const char *fpregs, int regno) 174 { 175 struct gdbarch *gdbarch = regcache->arch (); 176 int i; 177 178 for (i = gdbarch_fp0_regnum (gdbarch); 179 i <= mips_regnum (gdbarch)->fp_implementation_revision; 180 i++) 181 { 182 if (regno == i || regno == -1) 183 { 184 if (gdbarch_cannot_fetch_register (gdbarch, i)) 185 regcache->raw_supply (i, NULL); 186 else 187 regcache->raw_supply (i, 188 fpregs 189 + ((i - gdbarch_fp0_regnum (gdbarch)) 190 * mips_isa_regsize (gdbarch))); 191 } 192 } 193 } 194 195 void 196 mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno) 197 { 198 struct gdbarch *gdbarch = regcache->arch (); 199 int i; 200 201 for (i = gdbarch_fp0_regnum (gdbarch); 202 i <= mips_regnum (gdbarch)->fp_control_status; 203 i++) 204 if ((regno == i || regno == -1) 205 && ! gdbarch_cannot_store_register (gdbarch, i)) 206 regcache->raw_collect 207 (i, (fpregs + ((i - gdbarch_fp0_regnum (gdbarch)) 208 * mips_isa_regsize (gdbarch)))); 209 } 210 211 #if 0 212 213 /* Under NetBSD/mips, signal handler invocations can be identified by the 214 designated code sequence that is used to return from a signal handler. 215 In particular, the return address of a signal handler points to the 216 following code sequence: 217 218 addu a0, sp, 16 219 li v0, 295 # __sigreturn14 220 syscall 221 222 Each instruction has a unique encoding, so we simply attempt to match 223 the instruction the PC is pointing to with any of the above instructions. 224 If there is a hit, we know the offset to the start of the designated 225 sequence and can then check whether we really are executing in the 226 signal trampoline. If not, -1 is returned, otherwise the offset from the 227 start of the return sequence is returned. */ 228 229 #define RETCODE_NWORDS 3 230 #define RETCODE_SIZE (RETCODE_NWORDS * 4) 231 232 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] = 233 { 234 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */ 235 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */ 236 0x0c, 0x00, 0x00, 0x00, /* syscall */ 237 }; 238 239 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] = 240 { 241 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */ 242 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */ 243 0x00, 0x00, 0x00, 0x0c, /* syscall */ 244 }; 245 246 #endif 247 248 /* Figure out where the longjmp will land. We expect that we have 249 just entered longjmp and haven't yet setup the stack frame, so the 250 args are still in the argument regs. MIPS_A0_REGNUM points at the 251 jmp_buf structure from which we extract the PC that we will land 252 at. The PC is copied into *pc. This routine returns true on 253 success. */ 254 255 #define NBSD_MIPS_JB_PC (2 * 4) 256 #define NBSD_MIPS_JB_ELEMENT_SIZE(gdbarch) mips_isa_regsize (gdbarch) 257 #define NBSD_MIPS_JB_OFFSET(gdbarch) (NBSD_MIPS_JB_PC * \ 258 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)) 259 260 static int 261 mipsnbsd_get_longjmp_target (frame_info_ptr frame, CORE_ADDR *pc) 262 { 263 struct gdbarch *gdbarch = get_frame_arch (frame); 264 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 265 CORE_ADDR jb_addr; 266 gdb_byte *buf; 267 268 buf = (gdb_byte *) alloca (NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)); 269 270 jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM); 271 272 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET (gdbarch), buf, 273 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch))) 274 return 0; 275 276 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch), 277 byte_order); 278 return 1; 279 } 280 281 static int 282 mipsnbsd_cannot_fetch_register (struct gdbarch *gdbarch, int regno) 283 { 284 return regno == mips_regnum (gdbarch)->fp_implementation_revision; 285 } 286 287 static int 288 mipsnbsd_cannot_store_register (struct gdbarch *gdbarch, int regno) 289 { 290 return (regno == MIPS_ZERO_REGNUM 291 || regno == mips_regnum (gdbarch)->fp_implementation_revision); 292 } 293 294 /* Shared library support. */ 295 296 /* NetBSD/mips uses a slightly different `struct link_map' than the 297 other NetBSD platforms. */ 298 299 static struct link_map_offsets * 300 mipsnbsd_ilp32_fetch_link_map_offsets (void) 301 { 302 static struct link_map_offsets lmo; 303 static struct link_map_offsets *lmp = NULL; 304 305 if (lmp == NULL) 306 { 307 lmp = &lmo; 308 309 lmo.r_version_offset = 0; 310 lmo.r_version_size = 4; 311 lmo.r_map_offset = 4; 312 lmo.r_brk_offset = 8; 313 lmo.r_ldsomap_offset = -1; 314 lmo.r_next_offset = -1; 315 316 /* Everything we need is in the first 24 bytes. */ 317 lmo.link_map_size = 24; 318 lmo.l_addr_offset = 4; 319 lmo.l_name_offset = 8; 320 lmo.l_ld_offset = 12; 321 lmo.l_next_offset = 16; 322 lmo.l_prev_offset = 20; 323 } 324 325 return lmp; 326 } 327 328 static struct link_map_offsets * 329 mipsnbsd_lp64_fetch_link_map_offsets (void) 330 { 331 static struct link_map_offsets lmo; 332 static struct link_map_offsets *lmp = NULL; 333 334 if (lmp == NULL) 335 { 336 lmp = &lmo; 337 338 lmo.r_version_offset = 0; 339 lmo.r_version_size = 4; 340 lmo.r_map_offset = 8; 341 lmo.r_brk_offset = 16; 342 lmo.r_ldsomap_offset = -1; 343 lmo.r_next_offset = -1; 344 345 /* Everything we need is in the first 40 bytes. */ 346 lmo.link_map_size = 48; 347 lmo.l_addr_offset = 0; 348 lmo.l_name_offset = 16; 349 lmo.l_ld_offset = 24; 350 lmo.l_next_offset = 32; 351 lmo.l_prev_offset = 40; 352 } 353 354 return lmp; 355 } 356 357 358 static void 359 mipsnbsd_init_abi (struct gdbarch_info info, 360 struct gdbarch *gdbarch) 361 { 362 nbsd_init_abi (info, gdbarch); 363 364 set_gdbarch_iterate_over_regset_sections 365 (gdbarch, mipsnbsd_iterate_over_regset_sections); 366 367 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target); 368 369 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register); 370 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register); 371 372 set_gdbarch_software_single_step (gdbarch, mips_software_single_step); 373 374 /* NetBSD/mips has SVR4-style shared libraries. */ 375 set_solib_svr4_fetch_link_map_offsets 376 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ? 377 mipsnbsd_ilp32_fetch_link_map_offsets : 378 mipsnbsd_lp64_fetch_link_map_offsets)); 379 } 380 381 void _initialize_mipsnbsd_tdep (); 382 void 383 _initialize_mipsnbsd_tdep () 384 { 385 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD, 386 mipsnbsd_init_abi); 387 } 388