GDB (API)
|
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 }