1130803Smarcel/* Target-dependent code for NetBSD/Alpha. 2130803Smarcel 3130803Smarcel Copyright 2002, 2003, 2004 Free Software Foundation, Inc. 4130803Smarcel Contributed by Wasabi Systems, Inc. 5130803Smarcel 6130803Smarcel This file is part of GDB. 7130803Smarcel 8130803Smarcel This program is free software; you can redistribute it and/or modify 9130803Smarcel it under the terms of the GNU General Public License as published by 10130803Smarcel the Free Software Foundation; either version 2 of the License, or 11130803Smarcel (at your option) any later version. 12130803Smarcel 13130803Smarcel This program is distributed in the hope that it will be useful, 14130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 15130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130803Smarcel GNU General Public License for more details. 17130803Smarcel 18130803Smarcel You should have received a copy of the GNU General Public License 19130803Smarcel along with this program; if not, write to the Free Software 20130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 21130803Smarcel Boston, MA 02111-1307, USA. */ 22130803Smarcel 23130803Smarcel#include "defs.h" 24130803Smarcel#include "gdbcore.h" 25130803Smarcel#include "frame.h" 26130803Smarcel#include "regcache.h" 27130803Smarcel#include "value.h" 28130803Smarcel#include "osabi.h" 29130803Smarcel 30130803Smarcel#include "solib-svr4.h" 31130803Smarcel 32130803Smarcel#include "alpha-tdep.h" 33130803Smarcel#include "alphabsd-tdep.h" 34130803Smarcel#include "nbsd-tdep.h" 35130803Smarcel 36130803Smarcelstatic void 37130803Smarcelfetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, 38130803Smarcel CORE_ADDR ignore) 39130803Smarcel{ 40130803Smarcel char *regs, *fpregs; 41130803Smarcel int regno; 42130803Smarcel 43130803Smarcel /* Table to map a gdb register number to a trapframe register index. */ 44130803Smarcel static const int regmap[] = 45130803Smarcel { 46130803Smarcel 0, 1, 2, 3, 47130803Smarcel 4, 5, 6, 7, 48130803Smarcel 8, 9, 10, 11, 49130803Smarcel 12, 13, 14, 15, 50130803Smarcel 30, 31, 32, 16, 51130803Smarcel 17, 18, 19, 20, 52130803Smarcel 21, 22, 23, 24, 53130803Smarcel 25, 29, 26 54130803Smarcel }; 55130803Smarcel#define SIZEOF_TRAPFRAME (33 * 8) 56130803Smarcel 57130803Smarcel /* We get everything from one section. */ 58130803Smarcel if (which != 0) 59130803Smarcel return; 60130803Smarcel 61130803Smarcel regs = core_reg_sect; 62130803Smarcel fpregs = core_reg_sect + SIZEOF_TRAPFRAME; 63130803Smarcel 64130803Smarcel if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG)) 65130803Smarcel { 66130803Smarcel warning ("Wrong size register set in core file."); 67130803Smarcel return; 68130803Smarcel } 69130803Smarcel 70130803Smarcel /* Integer registers. */ 71130803Smarcel for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++) 72130803Smarcel supply_register (regno, regs + (regmap[regno] * 8)); 73130803Smarcel supply_register (ALPHA_ZERO_REGNUM, NULL); 74130803Smarcel supply_register (PC_REGNUM, regs + (28 * 8)); 75130803Smarcel 76130803Smarcel /* Floating point registers. */ 77130803Smarcel alphabsd_supply_fpreg (fpregs, -1); 78130803Smarcel} 79130803Smarcel 80130803Smarcelstatic void 81130803Smarcelfetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which, 82130803Smarcel CORE_ADDR ignore) 83130803Smarcel{ 84130803Smarcel switch (which) 85130803Smarcel { 86130803Smarcel case 0: /* Integer registers. */ 87130803Smarcel if (core_reg_size != SIZEOF_STRUCT_REG) 88130803Smarcel warning ("Wrong size register set in core file."); 89130803Smarcel else 90130803Smarcel alphabsd_supply_reg (core_reg_sect, -1); 91130803Smarcel break; 92130803Smarcel 93130803Smarcel case 2: /* Floating point registers. */ 94130803Smarcel if (core_reg_size != SIZEOF_STRUCT_FPREG) 95130803Smarcel warning ("Wrong size FP register set in core file."); 96130803Smarcel else 97130803Smarcel alphabsd_supply_fpreg (core_reg_sect, -1); 98130803Smarcel break; 99130803Smarcel 100130803Smarcel default: 101130803Smarcel /* Don't know what kind of register request this is; just ignore it. */ 102130803Smarcel break; 103130803Smarcel } 104130803Smarcel} 105130803Smarcel 106130803Smarcelstatic struct core_fns alphanbsd_core_fns = 107130803Smarcel{ 108130803Smarcel bfd_target_unknown_flavour, /* core_flavour */ 109130803Smarcel default_check_format, /* check_format */ 110130803Smarcel default_core_sniffer, /* core_sniffer */ 111130803Smarcel fetch_core_registers, /* core_read_registers */ 112130803Smarcel NULL /* next */ 113130803Smarcel}; 114130803Smarcel 115130803Smarcelstatic struct core_fns alphanbsd_elfcore_fns = 116130803Smarcel{ 117130803Smarcel bfd_target_elf_flavour, /* core_flavour */ 118130803Smarcel default_check_format, /* check_format */ 119130803Smarcel default_core_sniffer, /* core_sniffer */ 120130803Smarcel fetch_elfcore_registers, /* core_read_registers */ 121130803Smarcel NULL /* next */ 122130803Smarcel}; 123130803Smarcel 124130803Smarcel/* Under NetBSD/alpha, signal handler invocations can be identified by the 125130803Smarcel designated code sequence that is used to return from a signal handler. 126130803Smarcel In particular, the return address of a signal handler points to the 127130803Smarcel following code sequence: 128130803Smarcel 129130803Smarcel ldq a0, 0(sp) 130130803Smarcel lda sp, 16(sp) 131130803Smarcel lda v0, 295(zero) # __sigreturn14 132130803Smarcel call_pal callsys 133130803Smarcel 134130803Smarcel Each instruction has a unique encoding, so we simply attempt to match 135130803Smarcel the instruction the PC is pointing to with any of the above instructions. 136130803Smarcel If there is a hit, we know the offset to the start of the designated 137130803Smarcel sequence and can then check whether we really are executing in the 138130803Smarcel signal trampoline. If not, -1 is returned, otherwise the offset from the 139130803Smarcel start of the return sequence is returned. */ 140130803Smarcelstatic const unsigned char sigtramp_retcode[] = 141130803Smarcel{ 142130803Smarcel 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */ 143130803Smarcel 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */ 144130803Smarcel 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */ 145130803Smarcel 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */ 146130803Smarcel}; 147130803Smarcel#define RETCODE_NWORDS 4 148130803Smarcel#define RETCODE_SIZE (RETCODE_NWORDS * 4) 149130803Smarcel 150130803SmarcelLONGEST 151130803Smarcelalphanbsd_sigtramp_offset (CORE_ADDR pc) 152130803Smarcel{ 153130803Smarcel unsigned char ret[RETCODE_SIZE], w[4]; 154130803Smarcel LONGEST off; 155130803Smarcel int i; 156130803Smarcel 157130803Smarcel if (read_memory_nobpt (pc, (char *) w, 4) != 0) 158130803Smarcel return -1; 159130803Smarcel 160130803Smarcel for (i = 0; i < RETCODE_NWORDS; i++) 161130803Smarcel { 162130803Smarcel if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0) 163130803Smarcel break; 164130803Smarcel } 165130803Smarcel if (i == RETCODE_NWORDS) 166130803Smarcel return (-1); 167130803Smarcel 168130803Smarcel off = i * 4; 169130803Smarcel pc -= off; 170130803Smarcel 171130803Smarcel if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0) 172130803Smarcel return -1; 173130803Smarcel 174130803Smarcel if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0) 175130803Smarcel return off; 176130803Smarcel 177130803Smarcel return -1; 178130803Smarcel} 179130803Smarcel 180130803Smarcelstatic int 181130803Smarcelalphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name) 182130803Smarcel{ 183130803Smarcel return (nbsd_pc_in_sigtramp (pc, func_name) 184130803Smarcel || alphanbsd_sigtramp_offset (pc) >= 0); 185130803Smarcel} 186130803Smarcel 187130803Smarcelstatic CORE_ADDR 188130803Smarcelalphanbsd_sigcontext_addr (struct frame_info *frame) 189130803Smarcel{ 190130803Smarcel /* FIXME: This is not correct for all versions of NetBSD/alpha. 191130803Smarcel We will probably need to disassemble the trampoline to figure 192130803Smarcel out which trampoline frame type we have. */ 193130803Smarcel return get_frame_base (frame); 194130803Smarcel} 195130803Smarcel 196130803Smarcelstatic void 197130803Smarcelalphanbsd_init_abi (struct gdbarch_info info, 198130803Smarcel struct gdbarch *gdbarch) 199130803Smarcel{ 200130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 201130803Smarcel 202130803Smarcel /* Hook into the DWARF CFI frame unwinder. */ 203130803Smarcel alpha_dwarf2_init_abi (info, gdbarch); 204130803Smarcel 205130803Smarcel /* Hook into the MDEBUG frame unwinder. */ 206130803Smarcel alpha_mdebug_init_abi (info, gdbarch); 207130803Smarcel 208130803Smarcel set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp); 209130803Smarcel 210130803Smarcel /* NetBSD/alpha does not provide single step support via ptrace(2); we 211130803Smarcel must use software single-stepping. */ 212130803Smarcel set_gdbarch_software_single_step (gdbarch, alpha_software_single_step); 213130803Smarcel 214130803Smarcel set_solib_svr4_fetch_link_map_offsets (gdbarch, 215130803Smarcel nbsd_lp64_solib_svr4_fetch_link_map_offsets); 216130803Smarcel 217130803Smarcel tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset; 218130803Smarcel tdep->sigcontext_addr = alphanbsd_sigcontext_addr; 219130803Smarcel 220130803Smarcel tdep->jb_pc = 2; 221130803Smarcel tdep->jb_elt_size = 8; 222130803Smarcel} 223130803Smarcel 224130803Smarcelvoid 225130803Smarcel_initialize_alphanbsd_tdep (void) 226130803Smarcel{ 227130803Smarcel gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF, 228130803Smarcel alphanbsd_init_abi); 229130803Smarcel gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF, 230130803Smarcel alphanbsd_init_abi); 231130803Smarcel 232130803Smarcel add_core_fns (&alphanbsd_core_fns); 233130803Smarcel add_core_fns (&alphanbsd_elfcore_fns); 234130803Smarcel} 235