Home | History | Annotate | Line # | Download | only in gdb
mips-fbsd-tdep.c revision 1.1.1.2
      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