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