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