1 /* Target-dependent code for NetBSD/mips. 2 3 Copyright (C) 2002-2024 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 "extract-store-integer.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 (const 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