GDB (API)
/home/stan/gdb/src/gdb/alphanbsd-tdep.c
Go to the documentation of this file.
00001 /* Target-dependent code for NetBSD/alpha.
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 "frame.h"
00024 #include "gdbcore.h"
00025 #include "osabi.h"
00026 #include "regcache.h"
00027 #include "regset.h"
00028 #include "value.h"
00029 
00030 #include "gdb_assert.h"
00031 #include "gdb_string.h"
00032 
00033 #include "alpha-tdep.h"
00034 #include "alphabsd-tdep.h"
00035 #include "nbsd-tdep.h"
00036 #include "solib-svr4.h"
00037 #include "target.h"
00038 
00039 /* Core file support.  */
00040 
00041 /* Even though NetBSD/alpha used ELF since day one, it used the
00042    traditional a.out-style core dump format before NetBSD 1.6.  */
00043 
00044 /* Sizeof `struct reg' in <machine/reg.h>.  */
00045 #define ALPHANBSD_SIZEOF_GREGS  (32 * 8)
00046 
00047 /* Sizeof `struct fpreg' in <machine/reg.h.  */
00048 #define ALPHANBSD_SIZEOF_FPREGS ((32 * 8) + 8)
00049 
00050 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
00051    in the floating-point register set REGSET to register cache
00052    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
00053 
00054 static void
00055 alphanbsd_supply_fpregset (const struct regset *regset,
00056                            struct regcache *regcache,
00057                            int regnum, const void *fpregs, size_t len)
00058 {
00059   const gdb_byte *regs = fpregs;
00060   int i;
00061 
00062   gdb_assert (len >= ALPHANBSD_SIZEOF_FPREGS);
00063 
00064   for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
00065     {
00066       if (regnum == i || regnum == -1)
00067         regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
00068     }
00069 
00070   if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
00071     regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 32 * 8);
00072 }
00073 
00074 /* Supply register REGNUM from the buffer specified by GREGS and LEN
00075    in the general-purpose register set REGSET to register cache
00076    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
00077 
00078 static void
00079 alphanbsd_supply_gregset (const struct regset *regset,
00080                           struct regcache *regcache,
00081                           int regnum, const void *gregs, size_t len)
00082 {
00083   const gdb_byte *regs = gregs;
00084   int i;
00085 
00086   gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
00087 
00088   for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
00089     {
00090       if (regnum == i || regnum == -1)
00091         regcache_raw_supply (regcache, i, regs + i * 8);
00092     }
00093 
00094   if (regnum == ALPHA_PC_REGNUM || regnum == -1)
00095     regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
00096 }
00097 
00098 /* Supply register REGNUM from the buffer specified by GREGS and LEN
00099    in the general-purpose register set REGSET to register cache
00100    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
00101 
00102 static void
00103 alphanbsd_aout_supply_gregset (const struct regset *regset,
00104                                struct regcache *regcache,
00105                                int regnum, const void *gregs, size_t len)
00106 {
00107   const gdb_byte *regs = gregs;
00108   int i;
00109 
00110   /* Table to map a GDB register number to a trapframe register index.  */
00111   static const int regmap[] =
00112   {
00113      0,   1,   2,   3,
00114      4,   5,   6,   7,
00115      8,   9,  10,  11,
00116     12,  13,  14,  15, 
00117     30,  31,  32,  16, 
00118     17,  18,  19,  20,
00119     21,  22,  23,  24,
00120     25,  29,  26
00121   };
00122 
00123   gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
00124 
00125   for (i = 0; i < ARRAY_SIZE(regmap); i++)
00126     {
00127       if (regnum == i || regnum == -1)
00128         regcache_raw_supply (regcache, i, regs + regmap[i] * 8);
00129     }
00130 
00131   if (regnum == ALPHA_PC_REGNUM || regnum == -1)
00132     regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
00133 
00134   if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
00135     {
00136       regs += ALPHANBSD_SIZEOF_GREGS;
00137       len -= ALPHANBSD_SIZEOF_GREGS;
00138       alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len);
00139     }
00140 }
00141 
00142 /* NetBSD/alpha register sets.  */
00143 
00144 static struct regset alphanbsd_gregset =
00145 {
00146   NULL,
00147   alphanbsd_supply_gregset
00148 };
00149 
00150 static struct regset alphanbsd_fpregset =
00151 {
00152   NULL,
00153   alphanbsd_supply_fpregset
00154 };
00155 
00156 static struct regset alphanbsd_aout_gregset =
00157 {
00158   NULL,
00159   alphanbsd_aout_supply_gregset
00160 };
00161 
00162 /* Return the appropriate register set for the core section identified
00163    by SECT_NAME and SECT_SIZE.  */
00164 
00165 const struct regset *
00166 alphanbsd_regset_from_core_section (struct gdbarch *gdbarch,
00167                                     const char *sect_name, size_t sect_size)
00168 {
00169   if (strcmp (sect_name, ".reg") == 0 && sect_size >= ALPHANBSD_SIZEOF_GREGS)
00170     {
00171       if (sect_size >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
00172         return &alphanbsd_aout_gregset;
00173       else
00174         return &alphanbsd_gregset;
00175     }
00176 
00177   if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ALPHANBSD_SIZEOF_FPREGS)
00178     return &alphanbsd_fpregset;
00179 
00180   return NULL;
00181 }
00182 
00183 
00184 /* Signal trampolines.  */
00185 
00186 /* Under NetBSD/alpha, signal handler invocations can be identified by the
00187    designated code sequence that is used to return from a signal handler.
00188    In particular, the return address of a signal handler points to the
00189    following code sequence:
00190 
00191         ldq     a0, 0(sp)
00192         lda     sp, 16(sp)
00193         lda     v0, 295(zero)   # __sigreturn14
00194         call_pal callsys
00195 
00196    Each instruction has a unique encoding, so we simply attempt to match
00197    the instruction the PC is pointing to with any of the above instructions.
00198    If there is a hit, we know the offset to the start of the designated
00199    sequence and can then check whether we really are executing in the
00200    signal trampoline.  If not, -1 is returned, otherwise the offset from the
00201    start of the return sequence is returned.  */
00202 static const gdb_byte sigtramp_retcode[] =
00203 {
00204   0x00, 0x00, 0x1e, 0xa6,       /* ldq a0, 0(sp) */
00205   0x10, 0x00, 0xde, 0x23,       /* lda sp, 16(sp) */
00206   0x27, 0x01, 0x1f, 0x20,       /* lda v0, 295(zero) */
00207   0x83, 0x00, 0x00, 0x00,       /* call_pal callsys */
00208 };
00209 #define RETCODE_NWORDS          4
00210 #define RETCODE_SIZE            (RETCODE_NWORDS * 4)
00211 
00212 static LONGEST
00213 alphanbsd_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
00214 {
00215   gdb_byte ret[RETCODE_SIZE], w[4];
00216   LONGEST off;
00217   int i;
00218 
00219   if (target_read_memory (pc, w, 4) != 0)
00220     return -1;
00221 
00222   for (i = 0; i < RETCODE_NWORDS; i++)
00223     {
00224       if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
00225         break;
00226     }
00227   if (i == RETCODE_NWORDS)
00228     return (-1);
00229 
00230   off = i * 4;
00231   pc -= off;
00232 
00233   if (target_read_memory (pc, ret, sizeof (ret)) != 0)
00234     return -1;
00235 
00236   if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
00237     return off;
00238 
00239   return -1;
00240 }
00241 
00242 static int
00243 alphanbsd_pc_in_sigtramp (struct gdbarch *gdbarch,
00244                           CORE_ADDR pc, const char *func_name)
00245 {
00246   return (nbsd_pc_in_sigtramp (pc, func_name)
00247           || alphanbsd_sigtramp_offset (gdbarch, pc) >= 0);
00248 }
00249 
00250 static CORE_ADDR
00251 alphanbsd_sigcontext_addr (struct frame_info *frame)
00252 {
00253   /* FIXME: This is not correct for all versions of NetBSD/alpha.
00254      We will probably need to disassemble the trampoline to figure
00255      out which trampoline frame type we have.  */
00256   if (!get_next_frame (frame))
00257     return 0;
00258   return get_frame_base (get_next_frame (frame));
00259 }
00260 
00261 
00262 static void
00263 alphanbsd_init_abi (struct gdbarch_info info,
00264                     struct gdbarch *gdbarch)
00265 {
00266   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
00267 
00268   /* Hook into the DWARF CFI frame unwinder.  */
00269   alpha_dwarf2_init_abi (info, gdbarch);
00270 
00271   /* Hook into the MDEBUG frame unwinder.  */
00272   alpha_mdebug_init_abi (info, gdbarch);
00273 
00274   /* NetBSD/alpha does not provide single step support via ptrace(2); we
00275      must use software single-stepping.  */
00276   set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
00277 
00278   /* NetBSD/alpha has SVR4-style shared libraries.  */
00279   set_solib_svr4_fetch_link_map_offsets
00280     (gdbarch, svr4_lp64_fetch_link_map_offsets);
00281 
00282   tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
00283   tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
00284   tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
00285 
00286   tdep->jb_pc = 2;
00287   tdep->jb_elt_size = 8;
00288 
00289   set_gdbarch_regset_from_core_section
00290     (gdbarch, alphanbsd_regset_from_core_section);
00291 }
00292 
00293 
00294 static enum gdb_osabi
00295 alphanbsd_core_osabi_sniffer (bfd *abfd)
00296 {
00297   if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
00298     return GDB_OSABI_NETBSD_ELF;
00299 
00300   return GDB_OSABI_UNKNOWN;
00301 }
00302 
00303 
00304 /* Provide a prototype to silence -Wmissing-prototypes.  */
00305 void _initialize_alphanbsd_tdep (void);
00306 
00307 void
00308 _initialize_alphanbsd_tdep (void)
00309 {
00310   /* BFD doesn't set a flavour for NetBSD style a.out core files.  */
00311   gdbarch_register_osabi_sniffer (bfd_arch_alpha, bfd_target_unknown_flavour,
00312                                   alphanbsd_core_osabi_sniffer);
00313 
00314   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
00315                           alphanbsd_init_abi);
00316 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines