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