1699b0f92Schristos /* Target-dependent code for FreeBSD/mips. 2699b0f92Schristos 3*6881a400Schristos Copyright (C) 2017-2023 Free Software Foundation, Inc. 4699b0f92Schristos 5699b0f92Schristos This file is part of GDB. 6699b0f92Schristos 7699b0f92Schristos This program is free software; you can redistribute it and/or modify 8699b0f92Schristos it under the terms of the GNU General Public License as published by 9699b0f92Schristos the Free Software Foundation; either version 3 of the License, or 10699b0f92Schristos (at your option) any later version. 11699b0f92Schristos 12699b0f92Schristos This program is distributed in the hope that it will be useful, 13699b0f92Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 14699b0f92Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15699b0f92Schristos GNU General Public License for more details. 16699b0f92Schristos 17699b0f92Schristos You should have received a copy of the GNU General Public License 18699b0f92Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19699b0f92Schristos 20699b0f92Schristos #include "defs.h" 21699b0f92Schristos #include "osabi.h" 22699b0f92Schristos #include "regset.h" 23699b0f92Schristos #include "trad-frame.h" 24699b0f92Schristos #include "tramp-frame.h" 25699b0f92Schristos 26699b0f92Schristos #include "fbsd-tdep.h" 27699b0f92Schristos #include "mips-tdep.h" 28699b0f92Schristos #include "mips-fbsd-tdep.h" 29699b0f92Schristos 30699b0f92Schristos #include "solib-svr4.h" 31699b0f92Schristos 32699b0f92Schristos /* Core file support. */ 33699b0f92Schristos 34699b0f92Schristos /* Number of registers in `struct reg' from <machine/reg.h>. The 35699b0f92Schristos first 38 follow the standard MIPS layout. The 39th holds 36699b0f92Schristos IC_INT_REG on RM7K and RM9K processors. The 40th is a dummy for 37699b0f92Schristos padding. */ 38699b0f92Schristos #define MIPS_FBSD_NUM_GREGS 40 39699b0f92Schristos 40699b0f92Schristos /* Number of registers in `struct fpreg' from <machine/reg.h>. The 41699b0f92Schristos first 32 hold floating point registers. 33 holds the FSR. The 427f2ac410Schristos 34th holds FIR on FreeBSD 12.0 and newer kernels. On older kernels 437f2ac410Schristos it was a zero-filled dummy for padding. */ 44699b0f92Schristos #define MIPS_FBSD_NUM_FPREGS 34 45699b0f92Schristos 467f2ac410Schristos /* Supply a single register. The register size might not match, so use 477f2ac410Schristos regcache->raw_supply_integer (). */ 48699b0f92Schristos 49699b0f92Schristos static void 50699b0f92Schristos mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr, 51699b0f92Schristos size_t len) 52699b0f92Schristos { 537f2ac410Schristos regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, len, true); 54699b0f92Schristos } 55699b0f92Schristos 567f2ac410Schristos /* Collect a single register. The register size might not match, so use 577f2ac410Schristos regcache->raw_collect_integer (). */ 58699b0f92Schristos 59699b0f92Schristos static void 60699b0f92Schristos mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr, 61699b0f92Schristos size_t len) 62699b0f92Schristos { 637f2ac410Schristos regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len, true); 64699b0f92Schristos } 65699b0f92Schristos 66699b0f92Schristos /* Supply the floating-point registers stored in FPREGS to REGCACHE. 67699b0f92Schristos Each floating-point register in FPREGS is REGSIZE bytes in 68699b0f92Schristos length. */ 69699b0f92Schristos 70699b0f92Schristos void 71699b0f92Schristos mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum, 72699b0f92Schristos const void *fpregs, size_t regsize) 73699b0f92Schristos { 747f2ac410Schristos struct gdbarch *gdbarch = regcache->arch (); 75699b0f92Schristos const gdb_byte *regs = (const gdb_byte *) fpregs; 767f2ac410Schristos int i, fp0num; 77699b0f92Schristos 787f2ac410Schristos fp0num = mips_regnum (gdbarch)->fp0; 797f2ac410Schristos for (i = 0; i <= 32; i++) 807f2ac410Schristos if (regnum == fp0num + i || regnum == -1) 817f2ac410Schristos mips_fbsd_supply_reg (regcache, fp0num + i, 827f2ac410Schristos regs + i * regsize, regsize); 837f2ac410Schristos if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1) 847f2ac410Schristos mips_fbsd_supply_reg (regcache, mips_regnum (gdbarch)->fp_control_status, 857f2ac410Schristos regs + 32 * regsize, regsize); 867f2ac410Schristos if ((regnum == mips_regnum (gdbarch)->fp_implementation_revision 877f2ac410Schristos || regnum == -1) 887f2ac410Schristos && extract_unsigned_integer (regs + 33 * regsize, regsize, 897f2ac410Schristos gdbarch_byte_order (gdbarch)) != 0) 907f2ac410Schristos mips_fbsd_supply_reg (regcache, 917f2ac410Schristos mips_regnum (gdbarch)->fp_implementation_revision, 927f2ac410Schristos regs + 33 * regsize, regsize); 93699b0f92Schristos } 94699b0f92Schristos 95699b0f92Schristos /* Supply the general-purpose registers stored in GREGS to REGCACHE. 96699b0f92Schristos Each general-purpose register in GREGS is REGSIZE bytes in 97699b0f92Schristos length. */ 98699b0f92Schristos 99699b0f92Schristos void 100699b0f92Schristos mips_fbsd_supply_gregs (struct regcache *regcache, int regnum, 101699b0f92Schristos const void *gregs, size_t regsize) 102699b0f92Schristos { 1037f2ac410Schristos struct gdbarch *gdbarch = regcache->arch (); 104699b0f92Schristos const gdb_byte *regs = (const gdb_byte *) gregs; 105699b0f92Schristos int i; 106699b0f92Schristos 1077f2ac410Schristos for (i = 0; i <= mips_regnum (gdbarch)->pc; i++) 108699b0f92Schristos if (regnum == i || regnum == -1) 109699b0f92Schristos mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize); 110699b0f92Schristos } 111699b0f92Schristos 112699b0f92Schristos /* Collect the floating-point registers from REGCACHE and store them 113699b0f92Schristos in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes 114699b0f92Schristos in length. */ 115699b0f92Schristos 116699b0f92Schristos void 117699b0f92Schristos mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum, 118699b0f92Schristos void *fpregs, size_t regsize) 119699b0f92Schristos { 1207f2ac410Schristos struct gdbarch *gdbarch = regcache->arch (); 121699b0f92Schristos gdb_byte *regs = (gdb_byte *) fpregs; 1227f2ac410Schristos int i, fp0num; 123699b0f92Schristos 1247f2ac410Schristos fp0num = mips_regnum (gdbarch)->fp0; 1257f2ac410Schristos for (i = 0; i < 32; i++) 1267f2ac410Schristos if (regnum == fp0num + i || regnum == -1) 1277f2ac410Schristos mips_fbsd_collect_reg (regcache, fp0num + i, 1287f2ac410Schristos regs + i * regsize, regsize); 1297f2ac410Schristos if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1) 1307f2ac410Schristos mips_fbsd_collect_reg (regcache, mips_regnum (gdbarch)->fp_control_status, 1317f2ac410Schristos regs + 32 * regsize, regsize); 1327f2ac410Schristos if (regnum == mips_regnum (gdbarch)->fp_implementation_revision 1337f2ac410Schristos || regnum == -1) 1347f2ac410Schristos mips_fbsd_collect_reg (regcache, 1357f2ac410Schristos mips_regnum (gdbarch)->fp_implementation_revision, 1367f2ac410Schristos regs + 33 * regsize, regsize); 137699b0f92Schristos } 138699b0f92Schristos 139699b0f92Schristos /* Collect the general-purpose registers from REGCACHE and store them 140699b0f92Schristos in GREGS. Each general-purpose register in GREGS is REGSIZE bytes 141699b0f92Schristos in length. */ 142699b0f92Schristos 143699b0f92Schristos void 144699b0f92Schristos mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum, 145699b0f92Schristos void *gregs, size_t regsize) 146699b0f92Schristos { 1477f2ac410Schristos struct gdbarch *gdbarch = regcache->arch (); 148699b0f92Schristos gdb_byte *regs = (gdb_byte *) gregs; 149699b0f92Schristos int i; 150699b0f92Schristos 1517f2ac410Schristos for (i = 0; i <= mips_regnum (gdbarch)->pc; i++) 152699b0f92Schristos if (regnum == i || regnum == -1) 153699b0f92Schristos mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize); 154699b0f92Schristos } 155699b0f92Schristos 156699b0f92Schristos /* Supply register REGNUM from the buffer specified by FPREGS and LEN 157699b0f92Schristos in the floating-point register set REGSET to register cache 158699b0f92Schristos REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 159699b0f92Schristos 160699b0f92Schristos static void 161699b0f92Schristos mips_fbsd_supply_fpregset (const struct regset *regset, 162699b0f92Schristos struct regcache *regcache, 163699b0f92Schristos int regnum, const void *fpregs, size_t len) 164699b0f92Schristos { 1657f2ac410Schristos size_t regsize = mips_abi_regsize (regcache->arch ()); 166699b0f92Schristos 167699b0f92Schristos gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); 168699b0f92Schristos 169699b0f92Schristos mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize); 170699b0f92Schristos } 171699b0f92Schristos 172699b0f92Schristos /* Collect register REGNUM from the register cache REGCACHE and store 173699b0f92Schristos it in the buffer specified by FPREGS and LEN in the floating-point 174699b0f92Schristos register set REGSET. If REGNUM is -1, do this for all registers in 175699b0f92Schristos REGSET. */ 176699b0f92Schristos 177699b0f92Schristos static void 178699b0f92Schristos mips_fbsd_collect_fpregset (const struct regset *regset, 179699b0f92Schristos const struct regcache *regcache, 180699b0f92Schristos int regnum, void *fpregs, size_t len) 181699b0f92Schristos { 1827f2ac410Schristos size_t regsize = mips_abi_regsize (regcache->arch ()); 183699b0f92Schristos 184699b0f92Schristos gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); 185699b0f92Schristos 186699b0f92Schristos mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize); 187699b0f92Schristos } 188699b0f92Schristos 189699b0f92Schristos /* Supply register REGNUM from the buffer specified by GREGS and LEN 190699b0f92Schristos in the general-purpose register set REGSET to register cache 191699b0f92Schristos REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 192699b0f92Schristos 193699b0f92Schristos static void 194699b0f92Schristos mips_fbsd_supply_gregset (const struct regset *regset, 195699b0f92Schristos struct regcache *regcache, int regnum, 196699b0f92Schristos const void *gregs, size_t len) 197699b0f92Schristos { 1987f2ac410Schristos size_t regsize = mips_abi_regsize (regcache->arch ()); 199699b0f92Schristos 200699b0f92Schristos gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); 201699b0f92Schristos 202699b0f92Schristos mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize); 203699b0f92Schristos } 204699b0f92Schristos 205699b0f92Schristos /* Collect register REGNUM from the register cache REGCACHE and store 206699b0f92Schristos it in the buffer specified by GREGS and LEN in the general-purpose 207699b0f92Schristos register set REGSET. If REGNUM is -1, do this for all registers in 208699b0f92Schristos REGSET. */ 209699b0f92Schristos 210699b0f92Schristos static void 211699b0f92Schristos mips_fbsd_collect_gregset (const struct regset *regset, 212699b0f92Schristos const struct regcache *regcache, 213699b0f92Schristos int regnum, void *gregs, size_t len) 214699b0f92Schristos { 2157f2ac410Schristos size_t regsize = mips_abi_regsize (regcache->arch ()); 216699b0f92Schristos 217699b0f92Schristos gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); 218699b0f92Schristos 219699b0f92Schristos mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize); 220699b0f92Schristos } 221699b0f92Schristos 222699b0f92Schristos /* FreeBSD/mips register sets. */ 223699b0f92Schristos 224699b0f92Schristos static const struct regset mips_fbsd_gregset = 225699b0f92Schristos { 226699b0f92Schristos NULL, 227699b0f92Schristos mips_fbsd_supply_gregset, 228699b0f92Schristos mips_fbsd_collect_gregset, 229699b0f92Schristos }; 230699b0f92Schristos 231699b0f92Schristos static const struct regset mips_fbsd_fpregset = 232699b0f92Schristos { 233699b0f92Schristos NULL, 234699b0f92Schristos mips_fbsd_supply_fpregset, 235699b0f92Schristos mips_fbsd_collect_fpregset, 236699b0f92Schristos }; 237699b0f92Schristos 238699b0f92Schristos /* Iterate over core file register note sections. */ 239699b0f92Schristos 240699b0f92Schristos static void 241699b0f92Schristos mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, 242699b0f92Schristos iterate_over_regset_sections_cb *cb, 243699b0f92Schristos void *cb_data, 244699b0f92Schristos const struct regcache *regcache) 245699b0f92Schristos { 246699b0f92Schristos size_t regsize = mips_abi_regsize (gdbarch); 247699b0f92Schristos 2487f2ac410Schristos cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, MIPS_FBSD_NUM_GREGS * regsize, 2497f2ac410Schristos &mips_fbsd_gregset, NULL, cb_data); 2507f2ac410Schristos cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, MIPS_FBSD_NUM_FPREGS * regsize, 2517f2ac410Schristos &mips_fbsd_fpregset, NULL, cb_data); 252699b0f92Schristos } 253699b0f92Schristos 254699b0f92Schristos /* Signal trampoline support. */ 255699b0f92Schristos 256699b0f92Schristos #define FBSD_SYS_sigreturn 417 257699b0f92Schristos 258699b0f92Schristos #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn 259699b0f92Schristos #define MIPS_INST_SYSCALL 0x0000000c 260699b0f92Schristos #define MIPS_INST_BREAK 0x0000000d 261699b0f92Schristos 262699b0f92Schristos #define O32_SIGFRAME_UCONTEXT_OFFSET (16) 263699b0f92Schristos #define O32_SIGSET_T_SIZE (16) 264699b0f92Schristos 265699b0f92Schristos #define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE) 266699b0f92Schristos #define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4) 267699b0f92Schristos #define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4) 268699b0f92Schristos #define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32) 269699b0f92Schristos #define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4) 270699b0f92Schristos #define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4) 271699b0f92Schristos #define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4) 272699b0f92Schristos #define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4) 273699b0f92Schristos 274699b0f92Schristos #define O32_UCONTEXT_REG_SIZE 4 275699b0f92Schristos 276699b0f92Schristos static void 277699b0f92Schristos mips_fbsd_sigframe_init (const struct tramp_frame *self, 278*6881a400Schristos frame_info_ptr this_frame, 279699b0f92Schristos struct trad_frame_cache *cache, 280699b0f92Schristos CORE_ADDR func) 281699b0f92Schristos { 282699b0f92Schristos struct gdbarch *gdbarch = get_frame_arch (this_frame); 283699b0f92Schristos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 284699b0f92Schristos CORE_ADDR sp, ucontext_addr, addr; 285699b0f92Schristos int regnum; 286699b0f92Schristos gdb_byte buf[4]; 287699b0f92Schristos 288699b0f92Schristos /* We find the appropriate instance of `ucontext_t' at a 289699b0f92Schristos fixed offset in the signal frame. */ 290699b0f92Schristos sp = get_frame_register_signed (this_frame, 291699b0f92Schristos MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); 292699b0f92Schristos ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET; 293699b0f92Schristos 294699b0f92Schristos /* PC. */ 295699b0f92Schristos regnum = mips_regnum (gdbarch)->pc; 296699b0f92Schristos trad_frame_set_reg_addr (cache, 297699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 298699b0f92Schristos ucontext_addr + O32_UCONTEXT_PC); 299699b0f92Schristos 300699b0f92Schristos /* GPRs. */ 301699b0f92Schristos for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS; 302699b0f92Schristos regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE) 303699b0f92Schristos trad_frame_set_reg_addr (cache, 304699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 305699b0f92Schristos addr); 306699b0f92Schristos 307699b0f92Schristos regnum = MIPS_PS_REGNUM; 308699b0f92Schristos trad_frame_set_reg_addr (cache, 309699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 310699b0f92Schristos ucontext_addr + O32_UCONTEXT_SR); 311699b0f92Schristos 312699b0f92Schristos /* HI and LO. */ 313699b0f92Schristos regnum = mips_regnum (gdbarch)->lo; 314699b0f92Schristos trad_frame_set_reg_addr (cache, 315699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 316699b0f92Schristos ucontext_addr + O32_UCONTEXT_LO); 317699b0f92Schristos regnum = mips_regnum (gdbarch)->hi; 318699b0f92Schristos trad_frame_set_reg_addr (cache, 319699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 320699b0f92Schristos ucontext_addr + O32_UCONTEXT_HI); 321699b0f92Schristos 322699b0f92Schristos if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0 323699b0f92Schristos && extract_unsigned_integer (buf, 4, byte_order) != 0) 324699b0f92Schristos { 325699b0f92Schristos for (regnum = 0, addr = ucontext_addr + O32_UCONTEXT_FPREGS; 326699b0f92Schristos regnum < 32; regnum++, addr += O32_UCONTEXT_REG_SIZE) 327699b0f92Schristos trad_frame_set_reg_addr (cache, 328699b0f92Schristos regnum + gdbarch_fp0_regnum (gdbarch), 329699b0f92Schristos addr); 330699b0f92Schristos trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status, 331699b0f92Schristos addr); 332699b0f92Schristos } 333699b0f92Schristos 334699b0f92Schristos trad_frame_set_id (cache, frame_id_build (sp, func)); 335699b0f92Schristos } 336699b0f92Schristos 337699b0f92Schristos #define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \ 338699b0f92Schristos + O32_SIGFRAME_UCONTEXT_OFFSET) 339699b0f92Schristos 340699b0f92Schristos static const struct tramp_frame mips_fbsd_sigframe = 341699b0f92Schristos { 342699b0f92Schristos SIGTRAMP_FRAME, 343699b0f92Schristos MIPS_INSN32_SIZE, 344699b0f92Schristos { 3457f2ac410Schristos { MIPS_INST_ADDIU_A0_SP_O32, ULONGEST_MAX }, /* addiu a0, sp, SIGF_UC */ 3467f2ac410Schristos { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, /* li v0, SYS_sigreturn */ 3477f2ac410Schristos { MIPS_INST_SYSCALL, ULONGEST_MAX }, /* syscall */ 3487f2ac410Schristos { MIPS_INST_BREAK, ULONGEST_MAX }, /* break */ 3497f2ac410Schristos { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 350699b0f92Schristos }, 351699b0f92Schristos mips_fbsd_sigframe_init 352699b0f92Schristos }; 353699b0f92Schristos 354699b0f92Schristos #define N64_SIGFRAME_UCONTEXT_OFFSET (32) 355699b0f92Schristos #define N64_SIGSET_T_SIZE (16) 356699b0f92Schristos 357699b0f92Schristos #define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE) 358699b0f92Schristos #define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8) 359699b0f92Schristos #define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8) 360699b0f92Schristos #define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32) 361699b0f92Schristos #define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8) 362699b0f92Schristos #define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8) 363699b0f92Schristos #define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8) 364699b0f92Schristos #define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8) 365699b0f92Schristos 366699b0f92Schristos #define N64_UCONTEXT_REG_SIZE 8 367699b0f92Schristos 368699b0f92Schristos static void 369699b0f92Schristos mips64_fbsd_sigframe_init (const struct tramp_frame *self, 370*6881a400Schristos frame_info_ptr this_frame, 371699b0f92Schristos struct trad_frame_cache *cache, 372699b0f92Schristos CORE_ADDR func) 373699b0f92Schristos { 374699b0f92Schristos struct gdbarch *gdbarch = get_frame_arch (this_frame); 375699b0f92Schristos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 376699b0f92Schristos CORE_ADDR sp, ucontext_addr, addr; 377699b0f92Schristos int regnum; 378699b0f92Schristos gdb_byte buf[4]; 379699b0f92Schristos 380699b0f92Schristos /* We find the appropriate instance of `ucontext_t' at a 381699b0f92Schristos fixed offset in the signal frame. */ 382699b0f92Schristos sp = get_frame_register_signed (this_frame, 383699b0f92Schristos MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); 384699b0f92Schristos ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET; 385699b0f92Schristos 386699b0f92Schristos /* PC. */ 387699b0f92Schristos regnum = mips_regnum (gdbarch)->pc; 388699b0f92Schristos trad_frame_set_reg_addr (cache, 389699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 390699b0f92Schristos ucontext_addr + N64_UCONTEXT_PC); 391699b0f92Schristos 392699b0f92Schristos /* GPRs. */ 393699b0f92Schristos for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS; 394699b0f92Schristos regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE) 395699b0f92Schristos trad_frame_set_reg_addr (cache, 396699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 397699b0f92Schristos addr); 398699b0f92Schristos 399699b0f92Schristos regnum = MIPS_PS_REGNUM; 400699b0f92Schristos trad_frame_set_reg_addr (cache, 401699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 402699b0f92Schristos ucontext_addr + N64_UCONTEXT_SR); 403699b0f92Schristos 404699b0f92Schristos /* HI and LO. */ 405699b0f92Schristos regnum = mips_regnum (gdbarch)->lo; 406699b0f92Schristos trad_frame_set_reg_addr (cache, 407699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 408699b0f92Schristos ucontext_addr + N64_UCONTEXT_LO); 409699b0f92Schristos regnum = mips_regnum (gdbarch)->hi; 410699b0f92Schristos trad_frame_set_reg_addr (cache, 411699b0f92Schristos regnum + gdbarch_num_regs (gdbarch), 412699b0f92Schristos ucontext_addr + N64_UCONTEXT_HI); 413699b0f92Schristos 414699b0f92Schristos if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0 415699b0f92Schristos && extract_unsigned_integer (buf, 4, byte_order) != 0) 416699b0f92Schristos { 417699b0f92Schristos for (regnum = 0, addr = ucontext_addr + N64_UCONTEXT_FPREGS; 418699b0f92Schristos regnum < 32; regnum++, addr += N64_UCONTEXT_REG_SIZE) 419699b0f92Schristos trad_frame_set_reg_addr (cache, 420699b0f92Schristos regnum + gdbarch_fp0_regnum (gdbarch), 421699b0f92Schristos addr); 422699b0f92Schristos trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status, 423699b0f92Schristos addr); 424699b0f92Schristos } 425699b0f92Schristos 426699b0f92Schristos trad_frame_set_id (cache, frame_id_build (sp, func)); 427699b0f92Schristos } 428699b0f92Schristos 4297f2ac410Schristos #define MIPS_INST_ADDIU_A0_SP_N32 (0x27a40000 \ 4307f2ac410Schristos + N64_SIGFRAME_UCONTEXT_OFFSET) 4317f2ac410Schristos 4327f2ac410Schristos static const struct tramp_frame mipsn32_fbsd_sigframe = 4337f2ac410Schristos { 4347f2ac410Schristos SIGTRAMP_FRAME, 4357f2ac410Schristos MIPS_INSN32_SIZE, 4367f2ac410Schristos { 4377f2ac410Schristos { MIPS_INST_ADDIU_A0_SP_N32, ULONGEST_MAX }, /* addiu a0, sp, SIGF_UC */ 4387f2ac410Schristos { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, /* li v0, SYS_sigreturn */ 4397f2ac410Schristos { MIPS_INST_SYSCALL, ULONGEST_MAX }, /* syscall */ 4407f2ac410Schristos { MIPS_INST_BREAK, ULONGEST_MAX }, /* break */ 4417f2ac410Schristos { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 4427f2ac410Schristos }, 4437f2ac410Schristos mips64_fbsd_sigframe_init 4447f2ac410Schristos }; 4457f2ac410Schristos 446699b0f92Schristos #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \ 447699b0f92Schristos + N64_SIGFRAME_UCONTEXT_OFFSET) 448699b0f92Schristos 449699b0f92Schristos static const struct tramp_frame mips64_fbsd_sigframe = 450699b0f92Schristos { 451699b0f92Schristos SIGTRAMP_FRAME, 452699b0f92Schristos MIPS_INSN32_SIZE, 453699b0f92Schristos { 4547f2ac410Schristos { MIPS_INST_DADDIU_A0_SP_N64, ULONGEST_MAX }, /* daddiu a0, sp, SIGF_UC */ 4557f2ac410Schristos { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX }, /* li v0, SYS_sigreturn */ 4567f2ac410Schristos { MIPS_INST_SYSCALL, ULONGEST_MAX }, /* syscall */ 4577f2ac410Schristos { MIPS_INST_BREAK, ULONGEST_MAX }, /* break */ 4587f2ac410Schristos { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 459699b0f92Schristos }, 460699b0f92Schristos mips64_fbsd_sigframe_init 461699b0f92Schristos }; 462699b0f92Schristos 463699b0f92Schristos /* Shared library support. */ 464699b0f92Schristos 4657d62b00eSchristos /* FreeBSD/mips can use an alternate routine in the runtime linker to 4667d62b00eSchristos resolve functions. */ 4677d62b00eSchristos 4687d62b00eSchristos static CORE_ADDR 4697d62b00eSchristos mips_fbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc) 4707d62b00eSchristos { 4717d62b00eSchristos struct bound_minimal_symbol msym 4727d62b00eSchristos = lookup_bound_minimal_symbol ("_mips_rtld_bind"); 473*6881a400Schristos if (msym.minsym != nullptr && msym.value_address () == pc) 4747d62b00eSchristos return frame_unwind_caller_pc (get_current_frame ()); 4757d62b00eSchristos 4767d62b00eSchristos return fbsd_skip_solib_resolver (gdbarch, pc); 4777d62b00eSchristos } 4787d62b00eSchristos 479699b0f92Schristos /* FreeBSD/mips uses a slightly different `struct link_map' than the 480699b0f92Schristos other FreeBSD platforms as it includes an additional `l_off' 481699b0f92Schristos member. */ 482699b0f92Schristos 483699b0f92Schristos static struct link_map_offsets * 484699b0f92Schristos mips_fbsd_ilp32_fetch_link_map_offsets (void) 485699b0f92Schristos { 486699b0f92Schristos static struct link_map_offsets lmo; 487699b0f92Schristos static struct link_map_offsets *lmp = NULL; 488699b0f92Schristos 489699b0f92Schristos if (lmp == NULL) 490699b0f92Schristos { 491699b0f92Schristos lmp = &lmo; 492699b0f92Schristos 493699b0f92Schristos lmo.r_version_offset = 0; 494699b0f92Schristos lmo.r_version_size = 4; 495699b0f92Schristos lmo.r_map_offset = 4; 496699b0f92Schristos lmo.r_brk_offset = 8; 497699b0f92Schristos lmo.r_ldsomap_offset = -1; 498*6881a400Schristos lmo.r_next_offset = -1; 499699b0f92Schristos 500699b0f92Schristos lmo.link_map_size = 24; 501699b0f92Schristos lmo.l_addr_offset = 0; 502699b0f92Schristos lmo.l_name_offset = 8; 503699b0f92Schristos lmo.l_ld_offset = 12; 504699b0f92Schristos lmo.l_next_offset = 16; 505699b0f92Schristos lmo.l_prev_offset = 20; 506699b0f92Schristos } 507699b0f92Schristos 508699b0f92Schristos return lmp; 509699b0f92Schristos } 510699b0f92Schristos 511699b0f92Schristos static struct link_map_offsets * 512699b0f92Schristos mips_fbsd_lp64_fetch_link_map_offsets (void) 513699b0f92Schristos { 514699b0f92Schristos static struct link_map_offsets lmo; 515699b0f92Schristos static struct link_map_offsets *lmp = NULL; 516699b0f92Schristos 517699b0f92Schristos if (lmp == NULL) 518699b0f92Schristos { 519699b0f92Schristos lmp = &lmo; 520699b0f92Schristos 521699b0f92Schristos lmo.r_version_offset = 0; 522699b0f92Schristos lmo.r_version_size = 4; 523699b0f92Schristos lmo.r_map_offset = 8; 524699b0f92Schristos lmo.r_brk_offset = 16; 525699b0f92Schristos lmo.r_ldsomap_offset = -1; 526*6881a400Schristos lmo.r_next_offset = -1; 527699b0f92Schristos 528699b0f92Schristos lmo.link_map_size = 48; 529699b0f92Schristos lmo.l_addr_offset = 0; 530699b0f92Schristos lmo.l_name_offset = 16; 531699b0f92Schristos lmo.l_ld_offset = 24; 532699b0f92Schristos lmo.l_next_offset = 32; 533699b0f92Schristos lmo.l_prev_offset = 40; 534699b0f92Schristos } 535699b0f92Schristos 536699b0f92Schristos return lmp; 537699b0f92Schristos } 538699b0f92Schristos 539699b0f92Schristos static void 540699b0f92Schristos mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 541699b0f92Schristos { 542699b0f92Schristos enum mips_abi abi = mips_abi (gdbarch); 543699b0f92Schristos 544699b0f92Schristos /* Generic FreeBSD support. */ 545699b0f92Schristos fbsd_init_abi (info, gdbarch); 546699b0f92Schristos 547699b0f92Schristos set_gdbarch_software_single_step (gdbarch, mips_software_single_step); 548699b0f92Schristos 549699b0f92Schristos switch (abi) 550699b0f92Schristos { 551699b0f92Schristos case MIPS_ABI_O32: 552699b0f92Schristos tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe); 553699b0f92Schristos break; 554699b0f92Schristos case MIPS_ABI_N32: 5557f2ac410Schristos tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe); 556699b0f92Schristos break; 557699b0f92Schristos case MIPS_ABI_N64: 558699b0f92Schristos tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe); 559699b0f92Schristos break; 560699b0f92Schristos } 561699b0f92Schristos 562699b0f92Schristos set_gdbarch_iterate_over_regset_sections 563699b0f92Schristos (gdbarch, mips_fbsd_iterate_over_regset_sections); 564699b0f92Schristos 5657d62b00eSchristos set_gdbarch_skip_solib_resolver (gdbarch, mips_fbsd_skip_solib_resolver); 5667d62b00eSchristos 567699b0f92Schristos /* FreeBSD/mips has SVR4-style shared libraries. */ 568699b0f92Schristos set_solib_svr4_fetch_link_map_offsets 569699b0f92Schristos (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ? 570699b0f92Schristos mips_fbsd_ilp32_fetch_link_map_offsets : 571699b0f92Schristos mips_fbsd_lp64_fetch_link_map_offsets)); 572699b0f92Schristos } 573699b0f92Schristos 5747d62b00eSchristos void _initialize_mips_fbsd_tdep (); 575699b0f92Schristos void 5767d62b00eSchristos _initialize_mips_fbsd_tdep () 577699b0f92Schristos { 578699b0f92Schristos gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD, 579699b0f92Schristos mips_fbsd_init_abi); 580699b0f92Schristos } 581