Home | History | Annotate | Line # | Download | only in gdb
      1 /* Target-dependent code for NetBSD/mips.
      2 
      3    Copyright (C) 2002-2024 Free Software Foundation, Inc.
      4 
      5    Contributed by Wasabi Systems, Inc.
      6 
      7    This file is part of GDB.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21 
     22 #include "extract-store-integer.h"
     23 #include "gdbcore.h"
     24 #include "regcache.h"
     25 #include "regset.h"
     26 #include "target.h"
     27 #include "value.h"
     28 #include "osabi.h"
     29 
     30 #include "netbsd-tdep.h"
     31 #include "mips-netbsd-tdep.h"
     32 #include "mips-tdep.h"
     33 
     34 #include "solib-svr4.h"
     35 
     36 /* Shorthand for some register numbers used below.  */
     37 #define MIPS_PC_REGNUM  MIPS_EMBED_PC_REGNUM
     38 #define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
     39 #define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
     40 
     41 /* Core file support.  */
     42 
     43 /* Number of registers in `struct reg' from <machine/reg.h>.  */
     44 #define MIPSNBSD_NUM_GREGS	38
     45 
     46 /* Number of registers in `struct fpreg' from <machine/reg.h>.  */
     47 #define MIPSNBSD_NUM_FPREGS	33
     48 
     49 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
     50    in the floating-point register set REGSET to register cache
     51    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
     52 
     53 static void
     54 mipsnbsd_supply_fpregset (const struct regset *regset,
     55 			  struct regcache *regcache,
     56 			  int regnum, const void *fpregs, size_t len)
     57 {
     58   size_t regsize = mips_isa_regsize (regcache->arch ());
     59   const char *regs = (const char *) fpregs;
     60   int i;
     61 
     62   gdb_assert (len >= MIPSNBSD_NUM_FPREGS * regsize);
     63 
     64   for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
     65     {
     66       if (regnum == i || regnum == -1)
     67 	regcache->raw_supply (i, regs + (i - MIPS_FP0_REGNUM) * regsize);
     68     }
     69 }
     70 
     71 /* Supply register REGNUM from the buffer specified by GREGS and LEN
     72    in the general-purpose register set REGSET to register cache
     73    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
     74 
     75 static void
     76 mipsnbsd_supply_gregset (const struct regset *regset,
     77 			 struct regcache *regcache, int regnum,
     78 			 const void *gregs, size_t len)
     79 {
     80   size_t regsize = mips_isa_regsize (regcache->arch ());
     81   const char *regs = (const char *) gregs;
     82   int i;
     83 
     84   gdb_assert (len >= MIPSNBSD_NUM_GREGS * regsize);
     85 
     86   for (i = 0; i <= MIPS_PC_REGNUM; i++)
     87     {
     88       if (regnum == i || regnum == -1)
     89 	regcache->raw_supply (i, regs + i * regsize);
     90     }
     91 
     92   if (len >= (MIPSNBSD_NUM_GREGS + MIPSNBSD_NUM_FPREGS) * regsize)
     93     {
     94       regs += MIPSNBSD_NUM_GREGS * regsize;
     95       len -= MIPSNBSD_NUM_GREGS * regsize;
     96       mipsnbsd_supply_fpregset (regset, regcache, regnum, regs, len);
     97     }
     98   if (regnum == -1 || regnum == MIPS_ZERO_REGNUM)
     99     regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
    100 }
    101 
    102 /* NetBSD/mips register sets.  */
    103 
    104 static const struct regset mipsnbsd_gregset =
    105 {
    106   NULL,
    107   mipsnbsd_supply_gregset,
    108   NULL,
    109   REGSET_VARIABLE_SIZE
    110 };
    111 
    112 static const struct regset mipsnbsd_fpregset =
    113 {
    114   NULL,
    115   mipsnbsd_supply_fpregset
    116 };
    117 
    118 /* Iterate over core file register note sections.  */
    119 
    120 static void
    121 mipsnbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
    122 				       iterate_over_regset_sections_cb *cb,
    123 				       void *cb_data,
    124 				       const struct regcache *regcache)
    125 {
    126   size_t regsize = mips_isa_regsize (gdbarch);
    127 
    128   cb (".reg", MIPSNBSD_NUM_GREGS * regsize, MIPSNBSD_NUM_GREGS * regsize,
    129       &mipsnbsd_gregset, NULL, cb_data);
    130   cb (".reg2", MIPSNBSD_NUM_FPREGS * regsize, MIPSNBSD_NUM_FPREGS * regsize,
    131       &mipsnbsd_fpregset, NULL, cb_data);
    132 }
    133 
    134 
    136 /* Conveniently, GDB uses the same register numbering as the
    137    ptrace register structure used by NetBSD/mips.  */
    138 
    139 void
    140 mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno)
    141 {
    142   struct gdbarch *gdbarch = regcache->arch ();
    143   int i;
    144 
    145   for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
    146     {
    147       if (regno == i || regno == -1)
    148 	{
    149 	  if (gdbarch_cannot_fetch_register (gdbarch, i))
    150 	    regcache->raw_supply (i, NULL);
    151 	  else
    152 	    regcache->raw_supply
    153 	      (i, regs + (i * mips_isa_regsize (gdbarch)));
    154 	}
    155     }
    156   if (regno == -1 || regno == MIPS_ZERO_REGNUM)
    157     regcache->raw_supply_zeroed (MIPS_ZERO_REGNUM);
    158 }
    159 
    160 void
    161 mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
    162 {
    163   struct gdbarch *gdbarch = regcache->arch ();
    164   int i;
    165 
    166   for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
    167     if ((regno == i || regno == -1)
    168 	&& ! gdbarch_cannot_store_register (gdbarch, i))
    169       regcache->raw_collect (i, regs + (i * mips_isa_regsize (gdbarch)));
    170 }
    171 
    172 void
    173 mipsnbsd_supply_fpreg (struct regcache *regcache,
    174 		       const char *fpregs, int regno)
    175 {
    176   struct gdbarch *gdbarch = regcache->arch ();
    177   int i;
    178 
    179   for (i = gdbarch_fp0_regnum (gdbarch);
    180        i <= mips_regnum (gdbarch)->fp_implementation_revision;
    181        i++)
    182     {
    183       if (regno == i || regno == -1)
    184 	{
    185 	  if (gdbarch_cannot_fetch_register (gdbarch, i))
    186 	    regcache->raw_supply (i, NULL);
    187 	  else
    188 	    regcache->raw_supply (i,
    189 				 fpregs
    190 				 + ((i - gdbarch_fp0_regnum (gdbarch))
    191 				    * mips_isa_regsize (gdbarch)));
    192 	}
    193     }
    194 }
    195 
    196 void
    197 mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
    198 {
    199   struct gdbarch *gdbarch = regcache->arch ();
    200   int i;
    201 
    202   for (i = gdbarch_fp0_regnum (gdbarch);
    203        i <= mips_regnum (gdbarch)->fp_control_status;
    204        i++)
    205     if ((regno == i || regno == -1)
    206 	&& ! gdbarch_cannot_store_register (gdbarch, i))
    207       regcache->raw_collect
    208 	(i, (fpregs + ((i - gdbarch_fp0_regnum (gdbarch))
    209 	     * mips_isa_regsize (gdbarch))));
    210 }
    211 
    212 #if 0
    213 
    214 /* Under NetBSD/mips, signal handler invocations can be identified by the
    215    designated code sequence that is used to return from a signal handler.
    216    In particular, the return address of a signal handler points to the
    217    following code sequence:
    218 
    219 	addu	a0, sp, 16
    220 	li	v0, 295			# __sigreturn14
    221 	syscall
    222 
    223    Each instruction has a unique encoding, so we simply attempt to match
    224    the instruction the PC is pointing to with any of the above instructions.
    225    If there is a hit, we know the offset to the start of the designated
    226    sequence and can then check whether we really are executing in the
    227    signal trampoline.  If not, -1 is returned, otherwise the offset from the
    228    start of the return sequence is returned.  */
    229 
    230 #define RETCODE_NWORDS	3
    231 #define RETCODE_SIZE	(RETCODE_NWORDS * 4)
    232 
    233 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
    234 {
    235   0x10, 0x00, 0xa4, 0x27,	/* addu a0, sp, 16 */
    236   0x27, 0x01, 0x02, 0x24,	/* li v0, 295 */
    237   0x0c, 0x00, 0x00, 0x00,	/* syscall */
    238 };
    239 
    240 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
    241 {
    242   0x27, 0xa4, 0x00, 0x10,	/* addu a0, sp, 16 */
    243   0x24, 0x02, 0x01, 0x27,	/* li v0, 295 */
    244   0x00, 0x00, 0x00, 0x0c,	/* syscall */
    245 };
    246 
    247 #endif
    248 
    249 /* Figure out where the longjmp will land.  We expect that we have
    250    just entered longjmp and haven't yet setup the stack frame, so the
    251    args are still in the argument regs.  MIPS_A0_REGNUM points at the
    252    jmp_buf structure from which we extract the PC that we will land
    253    at.  The PC is copied into *pc.  This routine returns true on
    254    success.  */
    255 
    256 #define NBSD_MIPS_JB_PC			(2 * 4)
    257 #define NBSD_MIPS_JB_ELEMENT_SIZE(gdbarch)	mips_isa_regsize (gdbarch)
    258 #define NBSD_MIPS_JB_OFFSET(gdbarch)		(NBSD_MIPS_JB_PC * \
    259 					 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch))
    260 
    261 static int
    262 mipsnbsd_get_longjmp_target (const frame_info_ptr &frame, CORE_ADDR *pc)
    263 {
    264   struct gdbarch *gdbarch = get_frame_arch (frame);
    265   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
    266   CORE_ADDR jb_addr;
    267   gdb_byte *buf;
    268 
    269   buf = (gdb_byte *) alloca (NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch));
    270 
    271   jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
    272 
    273   if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET (gdbarch), buf,
    274 			  NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)))
    275     return 0;
    276 
    277   *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch),
    278 				  byte_order);
    279   return 1;
    280 }
    281 
    282 static int
    283 mipsnbsd_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
    284 {
    285   return regno == mips_regnum (gdbarch)->fp_implementation_revision;
    286 }
    287 
    288 static int
    289 mipsnbsd_cannot_store_register (struct gdbarch *gdbarch, int regno)
    290 {
    291   return (regno == MIPS_ZERO_REGNUM
    292 	  || regno == mips_regnum (gdbarch)->fp_implementation_revision);
    293 }
    294 
    295 /* Shared library support.  */
    296 
    297 /* NetBSD/mips uses a slightly different `struct link_map' than the
    298    other NetBSD platforms.  */
    299 
    300 static struct link_map_offsets *
    301 mipsnbsd_ilp32_fetch_link_map_offsets (void)
    302 {
    303   static struct link_map_offsets lmo;
    304   static struct link_map_offsets *lmp = NULL;
    305 
    306   if (lmp == NULL)
    307     {
    308       lmp = &lmo;
    309 
    310       lmo.r_version_offset = 0;
    311       lmo.r_version_size = 4;
    312       lmo.r_map_offset = 4;
    313       lmo.r_brk_offset = 8;
    314       lmo.r_ldsomap_offset = -1;
    315       lmo.r_next_offset = -1;
    316 
    317       /* Everything we need is in the first 24 bytes.  */
    318       lmo.link_map_size = 24;
    319       lmo.l_addr_offset = 4;
    320       lmo.l_name_offset = 8;
    321       lmo.l_ld_offset = 12;
    322       lmo.l_next_offset = 16;
    323       lmo.l_prev_offset = 20;
    324     }
    325 
    326   return lmp;
    327 }
    328 
    329 static struct link_map_offsets *
    330 mipsnbsd_lp64_fetch_link_map_offsets (void)
    331 {
    332   static struct link_map_offsets lmo;
    333   static struct link_map_offsets *lmp = NULL;
    334 
    335   if (lmp == NULL)
    336     {
    337       lmp = &lmo;
    338 
    339       lmo.r_version_offset = 0;
    340       lmo.r_version_size = 4;
    341       lmo.r_map_offset = 8;
    342       lmo.r_brk_offset = 16;
    343       lmo.r_ldsomap_offset = -1;
    344       lmo.r_next_offset = -1;
    345 
    346       /* Everything we need is in the first 40 bytes.  */
    347       lmo.link_map_size = 48;
    348       lmo.l_addr_offset = 0;
    349       lmo.l_name_offset = 16;
    350       lmo.l_ld_offset = 24;
    351       lmo.l_next_offset = 32;
    352       lmo.l_prev_offset = 40;
    353     }
    354 
    355   return lmp;
    356 }
    357 
    358 
    360 static void
    361 mipsnbsd_init_abi (struct gdbarch_info info,
    362 		   struct gdbarch *gdbarch)
    363 {
    364   nbsd_init_abi (info, gdbarch);
    365 
    366   set_gdbarch_iterate_over_regset_sections
    367     (gdbarch, mipsnbsd_iterate_over_regset_sections);
    368 
    369   set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
    370 
    371   set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
    372   set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
    373 
    374   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
    375 
    376   /* NetBSD/mips has SVR4-style shared libraries.  */
    377   set_solib_svr4_fetch_link_map_offsets
    378     (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
    379 	       mipsnbsd_ilp32_fetch_link_map_offsets :
    380 	       mipsnbsd_lp64_fetch_link_map_offsets));
    381 }
    382 
    383 void _initialize_mipsnbsd_tdep ();
    384 void
    385 _initialize_mipsnbsd_tdep ()
    386 {
    387   gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD,
    388 			  mipsnbsd_init_abi);
    389 }
    390