1/* Target-dependent code for NetBSD/Alpha. 2 3 Copyright 2002, 2003, 2004 Free Software Foundation, Inc. 4 Contributed by Wasabi Systems, Inc. 5 6 This file is part of GDB. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place - Suite 330, 21 Boston, MA 02111-1307, USA. */ 22 23#include "defs.h" 24#include "gdbcore.h" 25#include "frame.h" 26#include "regcache.h" 27#include "value.h" 28#include "osabi.h" 29 30#include "solib-svr4.h" 31 32#include "alpha-tdep.h" 33#include "alphabsd-tdep.h" 34#include "nbsd-tdep.h" 35 36static void 37fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, 38 CORE_ADDR ignore) 39{ 40 char *regs, *fpregs; 41 int regno; 42 43 /* Table to map a gdb register number to a trapframe register index. */ 44 static const int regmap[] = 45 { 46 0, 1, 2, 3, 47 4, 5, 6, 7, 48 8, 9, 10, 11, 49 12, 13, 14, 15, 50 30, 31, 32, 16, 51 17, 18, 19, 20, 52 21, 22, 23, 24, 53 25, 29, 26 54 }; 55#define SIZEOF_TRAPFRAME (33 * 8) 56 57 /* We get everything from one section. */ 58 if (which != 0) 59 return; 60 61 regs = core_reg_sect; 62 fpregs = core_reg_sect + SIZEOF_TRAPFRAME; 63 64 if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG)) 65 { 66 warning ("Wrong size register set in core file."); 67 return; 68 } 69 70 /* Integer registers. */ 71 for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++) 72 supply_register (regno, regs + (regmap[regno] * 8)); 73 supply_register (ALPHA_ZERO_REGNUM, NULL); 74 supply_register (PC_REGNUM, regs + (28 * 8)); 75 76 /* Floating point registers. */ 77 alphabsd_supply_fpreg (fpregs, -1); 78} 79 80static void 81fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which, 82 CORE_ADDR ignore) 83{ 84 switch (which) 85 { 86 case 0: /* Integer registers. */ 87 if (core_reg_size != SIZEOF_STRUCT_REG) 88 warning ("Wrong size register set in core file."); 89 else 90 alphabsd_supply_reg (core_reg_sect, -1); 91 break; 92 93 case 2: /* Floating point registers. */ 94 if (core_reg_size != SIZEOF_STRUCT_FPREG) 95 warning ("Wrong size FP register set in core file."); 96 else 97 alphabsd_supply_fpreg (core_reg_sect, -1); 98 break; 99 100 default: 101 /* Don't know what kind of register request this is; just ignore it. */ 102 break; 103 } 104} 105 106static struct core_fns alphanbsd_core_fns = 107{ 108 bfd_target_unknown_flavour, /* core_flavour */ 109 default_check_format, /* check_format */ 110 default_core_sniffer, /* core_sniffer */ 111 fetch_core_registers, /* core_read_registers */ 112 NULL /* next */ 113}; 114 115static struct core_fns alphanbsd_elfcore_fns = 116{ 117 bfd_target_elf_flavour, /* core_flavour */ 118 default_check_format, /* check_format */ 119 default_core_sniffer, /* core_sniffer */ 120 fetch_elfcore_registers, /* core_read_registers */ 121 NULL /* next */ 122}; 123 124/* Under NetBSD/alpha, signal handler invocations can be identified by the 125 designated code sequence that is used to return from a signal handler. 126 In particular, the return address of a signal handler points to the 127 following code sequence: 128 129 ldq a0, 0(sp) 130 lda sp, 16(sp) 131 lda v0, 295(zero) # __sigreturn14 132 call_pal callsys 133 134 Each instruction has a unique encoding, so we simply attempt to match 135 the instruction the PC is pointing to with any of the above instructions. 136 If there is a hit, we know the offset to the start of the designated 137 sequence and can then check whether we really are executing in the 138 signal trampoline. If not, -1 is returned, otherwise the offset from the 139 start of the return sequence is returned. */ 140static const unsigned char sigtramp_retcode[] = 141{ 142 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */ 143 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */ 144 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */ 145 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */ 146}; 147#define RETCODE_NWORDS 4 148#define RETCODE_SIZE (RETCODE_NWORDS * 4) 149 150LONGEST 151alphanbsd_sigtramp_offset (CORE_ADDR pc) 152{ 153 unsigned char ret[RETCODE_SIZE], w[4]; 154 LONGEST off; 155 int i; 156 157 if (read_memory_nobpt (pc, (char *) w, 4) != 0) 158 return -1; 159 160 for (i = 0; i < RETCODE_NWORDS; i++) 161 { 162 if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0) 163 break; 164 } 165 if (i == RETCODE_NWORDS) 166 return (-1); 167 168 off = i * 4; 169 pc -= off; 170 171 if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0) 172 return -1; 173 174 if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0) 175 return off; 176 177 return -1; 178} 179 180static int 181alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name) 182{ 183 return (nbsd_pc_in_sigtramp (pc, func_name) 184 || alphanbsd_sigtramp_offset (pc) >= 0); 185} 186 187static CORE_ADDR 188alphanbsd_sigcontext_addr (struct frame_info *frame) 189{ 190 /* FIXME: This is not correct for all versions of NetBSD/alpha. 191 We will probably need to disassemble the trampoline to figure 192 out which trampoline frame type we have. */ 193 return get_frame_base (frame); 194} 195 196static void 197alphanbsd_init_abi (struct gdbarch_info info, 198 struct gdbarch *gdbarch) 199{ 200 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 201 202 /* Hook into the DWARF CFI frame unwinder. */ 203 alpha_dwarf2_init_abi (info, gdbarch); 204 205 /* Hook into the MDEBUG frame unwinder. */ 206 alpha_mdebug_init_abi (info, gdbarch); 207 208 set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp); 209 210 /* NetBSD/alpha does not provide single step support via ptrace(2); we 211 must use software single-stepping. */ 212 set_gdbarch_software_single_step (gdbarch, alpha_software_single_step); 213 214 set_solib_svr4_fetch_link_map_offsets (gdbarch, 215 nbsd_lp64_solib_svr4_fetch_link_map_offsets); 216 217 tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset; 218 tdep->sigcontext_addr = alphanbsd_sigcontext_addr; 219 220 tdep->jb_pc = 2; 221 tdep->jb_elt_size = 8; 222} 223 224void 225_initialize_alphanbsd_tdep (void) 226{ 227 gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF, 228 alphanbsd_init_abi); 229 gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF, 230 alphanbsd_init_abi); 231 232 add_core_fns (&alphanbsd_core_fns); 233 add_core_fns (&alphanbsd_elfcore_fns); 234} 235