GDB (API)
/home/stan/gdb/src/gdb/mipsnbsd-tdep.c
Go to the documentation of this file.
00001 /* Target-dependent code for NetBSD/mips.
00002 
00003    Copyright (C) 2002-2013 Free Software Foundation, Inc.
00004 
00005    Contributed by Wasabi Systems, Inc.
00006 
00007    This file is part of GDB.
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 3 of the License, or
00012    (at your option) any later version.
00013 
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00021 
00022 #include "defs.h"
00023 #include "gdbcore.h"
00024 #include "regcache.h"
00025 #include "regset.h"
00026 #include "target.h"
00027 #include "value.h"
00028 #include "osabi.h"
00029 
00030 #include "gdb_assert.h"
00031 #include "gdb_string.h"
00032 
00033 #include "nbsd-tdep.h"
00034 #include "mipsnbsd-tdep.h"
00035 #include "mips-tdep.h"
00036 
00037 #include "solib-svr4.h"
00038 
00039 /* Shorthand for some register numbers used below.  */
00040 #define MIPS_PC_REGNUM  MIPS_EMBED_PC_REGNUM
00041 #define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
00042 #define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
00043 
00044 /* Core file support.  */
00045 
00046 /* Number of registers in `struct reg' from <machine/reg.h>.  */
00047 #define MIPSNBSD_NUM_GREGS      38
00048 
00049 /* Number of registers in `struct fpreg' from <machine/reg.h>.  */
00050 #define MIPSNBSD_NUM_FPREGS     33
00051 
00052 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
00053    in the floating-point register set REGSET to register cache
00054    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
00055 
00056 static void
00057 mipsnbsd_supply_fpregset (const struct regset *regset,
00058                           struct regcache *regcache,
00059                           int regnum, const void *fpregs, size_t len)
00060 {
00061   size_t regsize = mips_isa_regsize (get_regcache_arch (regcache));
00062   const char *regs = fpregs;
00063   int i;
00064 
00065   gdb_assert (len >= MIPSNBSD_NUM_FPREGS * regsize);
00066 
00067   for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
00068     {
00069       if (regnum == i || regnum == -1)
00070         regcache_raw_supply (regcache, i,
00071                              regs + (i - MIPS_FP0_REGNUM) * regsize);
00072     }
00073 }
00074 
00075 /* Supply register REGNUM from the buffer specified by GREGS and LEN
00076    in the general-purpose register set REGSET to register cache
00077    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
00078 
00079 static void
00080 mipsnbsd_supply_gregset (const struct regset *regset,
00081                          struct regcache *regcache, int regnum,
00082                          const void *gregs, size_t len)
00083 {
00084   size_t regsize = mips_isa_regsize (get_regcache_arch (regcache));
00085   const char *regs = gregs;
00086   int i;
00087 
00088   gdb_assert (len >= MIPSNBSD_NUM_GREGS * regsize);
00089 
00090   for (i = 0; i <= MIPS_PC_REGNUM; i++)
00091     {
00092       if (regnum == i || regnum == -1)
00093         regcache_raw_supply (regcache, i, regs + i * regsize);
00094     }
00095 
00096   if (len >= (MIPSNBSD_NUM_GREGS + MIPSNBSD_NUM_FPREGS) * regsize)
00097     {
00098       regs += MIPSNBSD_NUM_GREGS * regsize;
00099       len -= MIPSNBSD_NUM_GREGS * regsize;
00100       mipsnbsd_supply_fpregset (regset, regcache, regnum, regs, len);
00101     }
00102 }
00103 
00104 /* NetBSD/mips register sets.  */
00105 
00106 static struct regset mipsnbsd_gregset =
00107 {
00108   NULL,
00109   mipsnbsd_supply_gregset
00110 };
00111 
00112 static struct regset mipsnbsd_fpregset =
00113 {
00114   NULL,
00115   mipsnbsd_supply_fpregset
00116 };
00117 
00118 /* Return the appropriate register set for the core section identified
00119    by SECT_NAME and SECT_SIZE.  */
00120 
00121 static const struct regset *
00122 mipsnbsd_regset_from_core_section (struct gdbarch *gdbarch,
00123                                    const char *sect_name, size_t sect_size)
00124 {
00125   size_t regsize = mips_isa_regsize (gdbarch);
00126   
00127   if (strcmp (sect_name, ".reg") == 0
00128       && sect_size >= MIPSNBSD_NUM_GREGS * regsize)
00129     return &mipsnbsd_gregset;
00130 
00131   if (strcmp (sect_name, ".reg2") == 0
00132       && sect_size >= MIPSNBSD_NUM_FPREGS * regsize)
00133     return &mipsnbsd_fpregset;
00134 
00135   return NULL;
00136 }
00137 
00138 
00139 /* Conveniently, GDB uses the same register numbering as the
00140    ptrace register structure used by NetBSD/mips.  */
00141 
00142 void
00143 mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno)
00144 {
00145   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00146   int i;
00147 
00148   for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
00149     {
00150       if (regno == i || regno == -1)
00151         {
00152           if (gdbarch_cannot_fetch_register (gdbarch, i))
00153             regcache_raw_supply (regcache, i, NULL);
00154           else
00155             regcache_raw_supply (regcache, i,
00156                                  regs + (i * mips_isa_regsize (gdbarch)));
00157         }
00158     }
00159 }
00160 
00161 void
00162 mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
00163 {
00164   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00165   int i;
00166 
00167   for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
00168     if ((regno == i || regno == -1)
00169         && ! gdbarch_cannot_store_register (gdbarch, i))
00170       regcache_raw_collect (regcache, i,
00171                             regs + (i * mips_isa_regsize (gdbarch)));
00172 }
00173 
00174 void
00175 mipsnbsd_supply_fpreg (struct regcache *regcache,
00176                        const char *fpregs, int regno)
00177 {
00178   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00179   int i;
00180 
00181   for (i = gdbarch_fp0_regnum (gdbarch);
00182        i <= mips_regnum (gdbarch)->fp_implementation_revision;
00183        i++)
00184     {
00185       if (regno == i || regno == -1)
00186         {
00187           if (gdbarch_cannot_fetch_register (gdbarch, i))
00188             regcache_raw_supply (regcache, i, NULL);
00189           else
00190             regcache_raw_supply (regcache, i,
00191                                  fpregs 
00192                                  + ((i - gdbarch_fp0_regnum (gdbarch))
00193                                     * mips_isa_regsize (gdbarch)));
00194         }
00195     }
00196 }
00197 
00198 void
00199 mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
00200 {
00201   struct gdbarch *gdbarch = get_regcache_arch (regcache);
00202   int i;
00203 
00204   for (i = gdbarch_fp0_regnum (gdbarch);
00205        i <= mips_regnum (gdbarch)->fp_control_status;
00206        i++)
00207     if ((regno == i || regno == -1) 
00208         && ! gdbarch_cannot_store_register (gdbarch, i))
00209       regcache_raw_collect (regcache, i,
00210                             fpregs + ((i - gdbarch_fp0_regnum (gdbarch))
00211                               * mips_isa_regsize (gdbarch)));
00212 }
00213 
00214 /* Under NetBSD/mips, signal handler invocations can be identified by the
00215    designated code sequence that is used to return from a signal handler.
00216    In particular, the return address of a signal handler points to the
00217    following code sequence:
00218 
00219         addu    a0, sp, 16
00220         li      v0, 295                 # __sigreturn14
00221         syscall
00222    
00223    Each instruction has a unique encoding, so we simply attempt to match
00224    the instruction the PC is pointing to with any of the above instructions.
00225    If there is a hit, we know the offset to the start of the designated
00226    sequence and can then check whether we really are executing in the
00227    signal trampoline.  If not, -1 is returned, otherwise the offset from the
00228    start of the return sequence is returned.  */
00229 
00230 #define RETCODE_NWORDS  3
00231 #define RETCODE_SIZE    (RETCODE_NWORDS * 4)
00232 
00233 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
00234 {
00235   0x10, 0x00, 0xa4, 0x27,       /* addu a0, sp, 16 */
00236   0x27, 0x01, 0x02, 0x24,       /* li v0, 295 */
00237   0x0c, 0x00, 0x00, 0x00,       /* syscall */
00238 };
00239 
00240 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
00241 {
00242   0x27, 0xa4, 0x00, 0x10,       /* addu a0, sp, 16 */
00243   0x24, 0x02, 0x01, 0x27,       /* li v0, 295 */
00244   0x00, 0x00, 0x00, 0x0c,       /* syscall */
00245 };
00246 
00247 /* Figure out where the longjmp will land.  We expect that we have
00248    just entered longjmp and haven't yet setup the stack frame, so the
00249    args are still in the argument regs.  MIPS_A0_REGNUM points at the
00250    jmp_buf structure from which we extract the PC that we will land
00251    at.  The PC is copied into *pc.  This routine returns true on
00252    success.  */
00253 
00254 #define NBSD_MIPS_JB_PC                 (2 * 4)
00255 #define NBSD_MIPS_JB_ELEMENT_SIZE(gdbarch)      mips_isa_regsize (gdbarch)
00256 #define NBSD_MIPS_JB_OFFSET(gdbarch)            (NBSD_MIPS_JB_PC * \
00257                                          NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch))
00258 
00259 static int
00260 mipsnbsd_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
00261 {
00262   struct gdbarch *gdbarch = get_frame_arch (frame);
00263   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
00264   CORE_ADDR jb_addr;
00265   gdb_byte *buf;
00266 
00267   buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch));
00268 
00269   jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
00270 
00271   if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET (gdbarch), buf,
00272                           NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)))
00273     return 0;
00274 
00275   *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch),
00276                                   byte_order);
00277   return 1;
00278 }
00279 
00280 static int
00281 mipsnbsd_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
00282 {
00283   return (regno == MIPS_ZERO_REGNUM
00284           || regno == mips_regnum (gdbarch)->fp_implementation_revision);
00285 }
00286 
00287 static int
00288 mipsnbsd_cannot_store_register (struct gdbarch *gdbarch, int regno)
00289 {
00290   return (regno == MIPS_ZERO_REGNUM
00291           || regno == mips_regnum (gdbarch)->fp_implementation_revision);
00292 }
00293 
00294 /* Shared library support.  */
00295 
00296 /* NetBSD/mips uses a slightly different `struct link_map' than the
00297    other NetBSD platforms.  */
00298 
00299 static struct link_map_offsets *
00300 mipsnbsd_ilp32_fetch_link_map_offsets (void)
00301 {
00302   static struct link_map_offsets lmo;
00303   static struct link_map_offsets *lmp = NULL;
00304 
00305   if (lmp == NULL) 
00306     {
00307       lmp = &lmo;
00308 
00309       lmo.r_version_offset = 0;
00310       lmo.r_version_size = 4;
00311       lmo.r_map_offset = 4;
00312       lmo.r_brk_offset = 8;
00313       lmo.r_ldsomap_offset = -1;
00314 
00315       /* Everything we need is in the first 24 bytes.  */
00316       lmo.link_map_size = 24;
00317       lmo.l_addr_offset = 4;
00318       lmo.l_name_offset = 8;
00319       lmo.l_ld_offset = 12;
00320       lmo.l_next_offset = 16;
00321       lmo.l_prev_offset = 20;
00322     }
00323 
00324   return lmp;
00325 }
00326 
00327 static struct link_map_offsets *
00328 mipsnbsd_lp64_fetch_link_map_offsets (void)
00329 {
00330   static struct link_map_offsets lmo;
00331   static struct link_map_offsets *lmp = NULL;
00332 
00333   if (lmp == NULL)
00334     {
00335       lmp = &lmo;
00336 
00337       lmo.r_version_offset = 0;
00338       lmo.r_version_size = 4;
00339       lmo.r_map_offset = 8;
00340       lmo.r_brk_offset = 16;
00341       lmo.r_ldsomap_offset = -1;
00342 
00343       /* Everything we need is in the first 40 bytes.  */
00344       lmo.link_map_size = 48;
00345       lmo.l_addr_offset = 0;
00346       lmo.l_name_offset = 16; 
00347       lmo.l_ld_offset = 24;
00348       lmo.l_next_offset = 32;
00349       lmo.l_prev_offset = 40;
00350     }
00351 
00352   return lmp;
00353 }
00354 
00355 
00356 static void
00357 mipsnbsd_init_abi (struct gdbarch_info info,
00358                    struct gdbarch *gdbarch)
00359 {
00360   set_gdbarch_regset_from_core_section
00361     (gdbarch, mipsnbsd_regset_from_core_section);
00362 
00363   set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
00364 
00365   set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
00366   set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
00367 
00368   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
00369 
00370   /* NetBSD/mips has SVR4-style shared libraries.  */
00371   set_solib_svr4_fetch_link_map_offsets
00372     (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
00373                mipsnbsd_ilp32_fetch_link_map_offsets :
00374                mipsnbsd_lp64_fetch_link_map_offsets));
00375 }
00376 
00377 
00378 /* Provide a prototype to silence -Wmissing-prototypes.  */
00379 extern initialize_file_ftype _initialize_mipsnbsd_tdep;
00380 
00381 void
00382 _initialize_mipsnbsd_tdep (void)
00383 {
00384   gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF,
00385                           mipsnbsd_init_abi);
00386 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines