1 /* Target-dependent code for FreeBSD/mips. 2 3 Copyright (C) 2017-2019 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "osabi.h" 22 #include "regset.h" 23 #include "trad-frame.h" 24 #include "tramp-frame.h" 25 26 #include "fbsd-tdep.h" 27 #include "mips-tdep.h" 28 #include "mips-fbsd-tdep.h" 29 30 #include "solib-svr4.h" 31 32 /* Core file support. */ 33 34 /* Number of registers in `struct reg' from <machine/reg.h>. The 35 first 38 follow the standard MIPS layout. The 39th holds 36 IC_INT_REG on RM7K and RM9K processors. The 40th is a dummy for 37 padding. */ 38 #define MIPS_FBSD_NUM_GREGS 40 39 40 /* Number of registers in `struct fpreg' from <machine/reg.h>. The 41 first 32 hold floating point registers. 33 holds the FSR. The 42 34th holds FIR on FreeBSD 12.0 and newer kernels. On older kernels 43 it was a zero-filled dummy for padding. */ 44 #define MIPS_FBSD_NUM_FPREGS 34 45 46 /* Supply a single register. The register size might not match, so use 47 regcache->raw_supply_integer (). */ 48 49 static void 50 mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr, 51 size_t len) 52 { 53 regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, len, true); 54 } 55 56 /* Collect a single register. The register size might not match, so use 57 regcache->raw_collect_integer (). */ 58 59 static void 60 mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr, 61 size_t len) 62 { 63 regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len, true); 64 } 65 66 /* Supply the floating-point registers stored in FPREGS to REGCACHE. 67 Each floating-point register in FPREGS is REGSIZE bytes in 68 length. */ 69 70 void 71 mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum, 72 const void *fpregs, size_t regsize) 73 { 74 struct gdbarch *gdbarch = regcache->arch (); 75 const gdb_byte *regs = (const gdb_byte *) fpregs; 76 int i, fp0num; 77 78 fp0num = mips_regnum (gdbarch)->fp0; 79 for (i = 0; i <= 32; i++) 80 if (regnum == fp0num + i || regnum == -1) 81 mips_fbsd_supply_reg (regcache, fp0num + i, 82 regs + i * regsize, regsize); 83 if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1) 84 mips_fbsd_supply_reg (regcache, mips_regnum (gdbarch)->fp_control_status, 85 regs + 32 * regsize, regsize); 86 if ((regnum == mips_regnum (gdbarch)->fp_implementation_revision 87 || regnum == -1) 88 && extract_unsigned_integer (regs + 33 * regsize, regsize, 89 gdbarch_byte_order (gdbarch)) != 0) 90 mips_fbsd_supply_reg (regcache, 91 mips_regnum (gdbarch)->fp_implementation_revision, 92 regs + 33 * regsize, regsize); 93 } 94 95 /* Supply the general-purpose registers stored in GREGS to REGCACHE. 96 Each general-purpose register in GREGS is REGSIZE bytes in 97 length. */ 98 99 void 100 mips_fbsd_supply_gregs (struct regcache *regcache, int regnum, 101 const void *gregs, size_t regsize) 102 { 103 struct gdbarch *gdbarch = regcache->arch (); 104 const gdb_byte *regs = (const gdb_byte *) gregs; 105 int i; 106 107 for (i = 0; i <= mips_regnum (gdbarch)->pc; i++) 108 if (regnum == i || regnum == -1) 109 mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize); 110 } 111 112 /* Collect the floating-point registers from REGCACHE and store them 113 in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes 114 in length. */ 115 116 void 117 mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum, 118 void *fpregs, size_t regsize) 119 { 120 struct gdbarch *gdbarch = regcache->arch (); 121 gdb_byte *regs = (gdb_byte *) fpregs; 122 int i, fp0num; 123 124 fp0num = mips_regnum (gdbarch)->fp0; 125 for (i = 0; i < 32; i++) 126 if (regnum == fp0num + i || regnum == -1) 127 mips_fbsd_collect_reg (regcache, fp0num + i, 128 regs + i * regsize, regsize); 129 if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1) 130 mips_fbsd_collect_reg (regcache, mips_regnum (gdbarch)->fp_control_status, 131 regs + 32 * regsize, regsize); 132 if (regnum == mips_regnum (gdbarch)->fp_implementation_revision 133 || regnum == -1) 134 mips_fbsd_collect_reg (regcache, 135 mips_regnum (gdbarch)->fp_implementation_revision, 136 regs + 33 * regsize, regsize); 137 } 138 139 /* Collect the general-purpose registers from REGCACHE and store them 140 in GREGS. Each general-purpose register in GREGS is REGSIZE bytes 141 in length. */ 142 143 void 144 mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum, 145 void *gregs, size_t regsize) 146 { 147 struct gdbarch *gdbarch = regcache->arch (); 148 gdb_byte *regs = (gdb_byte *) gregs; 149 int i; 150 151 for (i = 0; i <= mips_regnum (gdbarch)->pc; i++) 152 if (regnum == i || regnum == -1) 153 mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize); 154 } 155 156 /* Supply register REGNUM from the buffer specified by FPREGS and LEN 157 in the floating-point register set REGSET to register cache 158 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 159 160 static void 161 mips_fbsd_supply_fpregset (const struct regset *regset, 162 struct regcache *regcache, 163 int regnum, const void *fpregs, size_t len) 164 { 165 size_t regsize = mips_abi_regsize (regcache->arch ()); 166 167 gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); 168 169 mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize); 170 } 171 172 /* Collect register REGNUM from the register cache REGCACHE and store 173 it in the buffer specified by FPREGS and LEN in the floating-point 174 register set REGSET. If REGNUM is -1, do this for all registers in 175 REGSET. */ 176 177 static void 178 mips_fbsd_collect_fpregset (const struct regset *regset, 179 const struct regcache *regcache, 180 int regnum, void *fpregs, size_t len) 181 { 182 size_t regsize = mips_abi_regsize (regcache->arch ()); 183 184 gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); 185 186 mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize); 187 } 188 189 /* Supply register REGNUM from the buffer specified by GREGS and LEN 190 in the general-purpose register set REGSET to register cache 191 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 192 193 static void 194 mips_fbsd_supply_gregset (const struct regset *regset, 195 struct regcache *regcache, int regnum, 196 const void *gregs, size_t len) 197 { 198 size_t regsize = mips_abi_regsize (regcache->arch ()); 199 200 gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); 201 202 mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize); 203 } 204 205 /* Collect register REGNUM from the register cache REGCACHE and store 206 it in the buffer specified by GREGS and LEN in the general-purpose 207 register set REGSET. If REGNUM is -1, do this for all registers in 208 REGSET. */ 209 210 static void 211 mips_fbsd_collect_gregset (const struct regset *regset, 212 const struct regcache *regcache, 213 int regnum, void *gregs, size_t len) 214 { 215 size_t regsize = mips_abi_regsize (regcache->arch ()); 216 217 gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); 218 219 mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize); 220 } 221 222 /* FreeBSD/mips register sets. */ 223 224 static const struct regset mips_fbsd_gregset = 225 { 226 NULL, 227 mips_fbsd_supply_gregset, 228 mips_fbsd_collect_gregset, 229 }; 230 231 static const struct regset mips_fbsd_fpregset = 232 { 233 NULL, 234 mips_fbsd_supply_fpregset, 235 mips_fbsd_collect_fpregset, 236 }; 237 238 /* Iterate over core file register note sections. */ 239 240 static void 241 mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, 242 iterate_over_regset_sections_cb *cb, 243 void *cb_data, 244 const struct regcache *regcache) 245 { 246 size_t regsize = mips_abi_regsize (gdbarch); 247 248 cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, MIPS_FBSD_NUM_GREGS * regsize, 249 &mips_fbsd_gregset, NULL, cb_data); 250 cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, MIPS_FBSD_NUM_FPREGS * regsize, 251 &mips_fbsd_fpregset, NULL, cb_data); 252 } 253 254 /* Signal trampoline support. */ 255 256 #define FBSD_SYS_sigreturn 417 257 258 #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn 259 #define MIPS_INST_SYSCALL 0x0000000c 260 #define MIPS_INST_BREAK 0x0000000d 261 262 #define O32_SIGFRAME_UCONTEXT_OFFSET (16) 263 #define O32_SIGSET_T_SIZE (16) 264 265 #define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE) 266 #define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4) 267 #define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4) 268 #define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32) 269 #define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4) 270 #define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4) 271 #define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4) 272 #define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4) 273 274 #define O32_UCONTEXT_REG_SIZE 4 275 276 static void 277 mips_fbsd_sigframe_init (const struct tramp_frame *self, 278 struct frame_info *this_frame, 279 struct trad_frame_cache *cache, 280 CORE_ADDR func) 281 { 282 struct gdbarch *gdbarch = get_frame_arch (this_frame); 283 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 284 CORE_ADDR sp, ucontext_addr, addr; 285 int regnum; 286 gdb_byte buf[4]; 287 288 /* We find the appropriate instance of `ucontext_t' at a 289 fixed offset in the signal frame. */ 290 sp = get_frame_register_signed (this_frame, 291 MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); 292 ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET; 293 294 /* PC. */ 295 regnum = mips_regnum (gdbarch)->pc; 296 trad_frame_set_reg_addr (cache, 297 regnum + gdbarch_num_regs (gdbarch), 298 ucontext_addr + O32_UCONTEXT_PC); 299 300 /* GPRs. */ 301 for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS; 302 regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE) 303 trad_frame_set_reg_addr (cache, 304 regnum + gdbarch_num_regs (gdbarch), 305 addr); 306 307 regnum = MIPS_PS_REGNUM; 308 trad_frame_set_reg_addr (cache, 309 regnum + gdbarch_num_regs (gdbarch), 310 ucontext_addr + O32_UCONTEXT_SR); 311 312 /* HI and LO. */ 313 regnum = mips_regnum (gdbarch)->lo; 314 trad_frame_set_reg_addr (cache, 315 regnum + gdbarch_num_regs (gdbarch), 316 ucontext_addr + O32_UCONTEXT_LO); 317 regnum = mips_regnum (gdbarch)->hi; 318 trad_frame_set_reg_addr (cache, 319 regnum + gdbarch_num_regs (gdbarch), 320 ucontext_addr + O32_UCONTEXT_HI); 321 322 if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0 323 && extract_unsigned_integer (buf, 4, byte_order) != 0) 324 { 325 for (regnum = 0, addr = ucontext_addr + O32_UCONTEXT_FPREGS; 326 regnum < 32; regnum++, addr += O32_UCONTEXT_REG_SIZE) 327 trad_frame_set_reg_addr (cache, 328 regnum + gdbarch_fp0_regnum (gdbarch), 329 addr); 330 trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status, 331 addr); 332 } 333 334 trad_frame_set_id (cache, frame_id_build (sp, func)); 335 } 336 337 #define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \ 338 + O32_SIGFRAME_UCONTEXT_OFFSET) 339 340 static const struct tramp_frame mips_fbsd_sigframe = 341 { 342 SIGTRAMP_FRAME, 343 MIPS_INSN32_SIZE, 344 { 345 { MIPS_INST_ADDIU_A0_SP_O32, ULONGEST_MAX }, /* addiu a0, sp, SIGF_UC */ 346 { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, /* li v0, SYS_sigreturn */ 347 { MIPS_INST_SYSCALL, ULONGEST_MAX }, /* syscall */ 348 { MIPS_INST_BREAK, ULONGEST_MAX }, /* break */ 349 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 350 }, 351 mips_fbsd_sigframe_init 352 }; 353 354 #define N64_SIGFRAME_UCONTEXT_OFFSET (32) 355 #define N64_SIGSET_T_SIZE (16) 356 357 #define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE) 358 #define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8) 359 #define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8) 360 #define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32) 361 #define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8) 362 #define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8) 363 #define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8) 364 #define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8) 365 366 #define N64_UCONTEXT_REG_SIZE 8 367 368 static void 369 mips64_fbsd_sigframe_init (const struct tramp_frame *self, 370 struct frame_info *this_frame, 371 struct trad_frame_cache *cache, 372 CORE_ADDR func) 373 { 374 struct gdbarch *gdbarch = get_frame_arch (this_frame); 375 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 376 CORE_ADDR sp, ucontext_addr, addr; 377 int regnum; 378 gdb_byte buf[4]; 379 380 /* We find the appropriate instance of `ucontext_t' at a 381 fixed offset in the signal frame. */ 382 sp = get_frame_register_signed (this_frame, 383 MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); 384 ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET; 385 386 /* PC. */ 387 regnum = mips_regnum (gdbarch)->pc; 388 trad_frame_set_reg_addr (cache, 389 regnum + gdbarch_num_regs (gdbarch), 390 ucontext_addr + N64_UCONTEXT_PC); 391 392 /* GPRs. */ 393 for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS; 394 regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE) 395 trad_frame_set_reg_addr (cache, 396 regnum + gdbarch_num_regs (gdbarch), 397 addr); 398 399 regnum = MIPS_PS_REGNUM; 400 trad_frame_set_reg_addr (cache, 401 regnum + gdbarch_num_regs (gdbarch), 402 ucontext_addr + N64_UCONTEXT_SR); 403 404 /* HI and LO. */ 405 regnum = mips_regnum (gdbarch)->lo; 406 trad_frame_set_reg_addr (cache, 407 regnum + gdbarch_num_regs (gdbarch), 408 ucontext_addr + N64_UCONTEXT_LO); 409 regnum = mips_regnum (gdbarch)->hi; 410 trad_frame_set_reg_addr (cache, 411 regnum + gdbarch_num_regs (gdbarch), 412 ucontext_addr + N64_UCONTEXT_HI); 413 414 if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0 415 && extract_unsigned_integer (buf, 4, byte_order) != 0) 416 { 417 for (regnum = 0, addr = ucontext_addr + N64_UCONTEXT_FPREGS; 418 regnum < 32; regnum++, addr += N64_UCONTEXT_REG_SIZE) 419 trad_frame_set_reg_addr (cache, 420 regnum + gdbarch_fp0_regnum (gdbarch), 421 addr); 422 trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status, 423 addr); 424 } 425 426 trad_frame_set_id (cache, frame_id_build (sp, func)); 427 } 428 429 #define MIPS_INST_ADDIU_A0_SP_N32 (0x27a40000 \ 430 + N64_SIGFRAME_UCONTEXT_OFFSET) 431 432 static const struct tramp_frame mipsn32_fbsd_sigframe = 433 { 434 SIGTRAMP_FRAME, 435 MIPS_INSN32_SIZE, 436 { 437 { MIPS_INST_ADDIU_A0_SP_N32, ULONGEST_MAX }, /* addiu a0, sp, SIGF_UC */ 438 { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, /* li v0, SYS_sigreturn */ 439 { MIPS_INST_SYSCALL, ULONGEST_MAX }, /* syscall */ 440 { MIPS_INST_BREAK, ULONGEST_MAX }, /* break */ 441 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 442 }, 443 mips64_fbsd_sigframe_init 444 }; 445 446 #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \ 447 + N64_SIGFRAME_UCONTEXT_OFFSET) 448 449 static const struct tramp_frame mips64_fbsd_sigframe = 450 { 451 SIGTRAMP_FRAME, 452 MIPS_INSN32_SIZE, 453 { 454 { MIPS_INST_DADDIU_A0_SP_N64, ULONGEST_MAX }, /* daddiu a0, sp, SIGF_UC */ 455 { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, /* li v0, SYS_sigreturn */ 456 { MIPS_INST_SYSCALL, ULONGEST_MAX }, /* syscall */ 457 { MIPS_INST_BREAK, ULONGEST_MAX }, /* break */ 458 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 459 }, 460 mips64_fbsd_sigframe_init 461 }; 462 463 /* Shared library support. */ 464 465 /* FreeBSD/mips uses a slightly different `struct link_map' than the 466 other FreeBSD platforms as it includes an additional `l_off' 467 member. */ 468 469 static struct link_map_offsets * 470 mips_fbsd_ilp32_fetch_link_map_offsets (void) 471 { 472 static struct link_map_offsets lmo; 473 static struct link_map_offsets *lmp = NULL; 474 475 if (lmp == NULL) 476 { 477 lmp = &lmo; 478 479 lmo.r_version_offset = 0; 480 lmo.r_version_size = 4; 481 lmo.r_map_offset = 4; 482 lmo.r_brk_offset = 8; 483 lmo.r_ldsomap_offset = -1; 484 485 lmo.link_map_size = 24; 486 lmo.l_addr_offset = 0; 487 lmo.l_name_offset = 8; 488 lmo.l_ld_offset = 12; 489 lmo.l_next_offset = 16; 490 lmo.l_prev_offset = 20; 491 } 492 493 return lmp; 494 } 495 496 static struct link_map_offsets * 497 mips_fbsd_lp64_fetch_link_map_offsets (void) 498 { 499 static struct link_map_offsets lmo; 500 static struct link_map_offsets *lmp = NULL; 501 502 if (lmp == NULL) 503 { 504 lmp = &lmo; 505 506 lmo.r_version_offset = 0; 507 lmo.r_version_size = 4; 508 lmo.r_map_offset = 8; 509 lmo.r_brk_offset = 16; 510 lmo.r_ldsomap_offset = -1; 511 512 lmo.link_map_size = 48; 513 lmo.l_addr_offset = 0; 514 lmo.l_name_offset = 16; 515 lmo.l_ld_offset = 24; 516 lmo.l_next_offset = 32; 517 lmo.l_prev_offset = 40; 518 } 519 520 return lmp; 521 } 522 523 static void 524 mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 525 { 526 enum mips_abi abi = mips_abi (gdbarch); 527 528 /* Generic FreeBSD support. */ 529 fbsd_init_abi (info, gdbarch); 530 531 set_gdbarch_software_single_step (gdbarch, mips_software_single_step); 532 533 switch (abi) 534 { 535 case MIPS_ABI_O32: 536 tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe); 537 break; 538 case MIPS_ABI_N32: 539 tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe); 540 break; 541 case MIPS_ABI_N64: 542 tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe); 543 break; 544 } 545 546 set_gdbarch_iterate_over_regset_sections 547 (gdbarch, mips_fbsd_iterate_over_regset_sections); 548 549 /* FreeBSD/mips has SVR4-style shared libraries. */ 550 set_solib_svr4_fetch_link_map_offsets 551 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ? 552 mips_fbsd_ilp32_fetch_link_map_offsets : 553 mips_fbsd_lp64_fetch_link_map_offsets)); 554 } 555 556 void 557 _initialize_mips_fbsd_tdep (void) 558 { 559 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD, 560 mips_fbsd_init_abi); 561 } 562