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