1130803Smarcel/* Target-dependent code for MIPS systems running NetBSD. 2130803Smarcel Copyright 2002, 2003 Free Software Foundation, Inc. 3130803Smarcel Contributed by Wasabi Systems, Inc. 4130803Smarcel 5130803Smarcel This file is part of GDB. 6130803Smarcel 7130803Smarcel This program is free software; you can redistribute it and/or modify 8130803Smarcel it under the terms of the GNU General Public License as published by 9130803Smarcel the Free Software Foundation; either version 2 of the License, or 10130803Smarcel (at your option) any later version. 11130803Smarcel 12130803Smarcel This program is distributed in the hope that it will be useful, 13130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 14130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15130803Smarcel GNU General Public License for more details. 16130803Smarcel 17130803Smarcel You should have received a copy of the GNU General Public License 18130803Smarcel along with this program; if not, write to the Free Software 19130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 20130803Smarcel Boston, MA 02111-1307, USA. */ 21130803Smarcel 22130803Smarcel#include "defs.h" 23130803Smarcel#include "gdbcore.h" 24130803Smarcel#include "regcache.h" 25130803Smarcel#include "target.h" 26130803Smarcel#include "value.h" 27130803Smarcel#include "osabi.h" 28130803Smarcel 29130803Smarcel#include "nbsd-tdep.h" 30130803Smarcel#include "mipsnbsd-tdep.h" 31130803Smarcel 32130803Smarcel#include "solib-svr4.h" 33130803Smarcel 34130803Smarcel/* Conveniently, GDB uses the same register numbering as the 35130803Smarcel ptrace register structure used by NetBSD/mips. */ 36130803Smarcel 37130803Smarcelvoid 38130803Smarcelmipsnbsd_supply_reg (char *regs, int regno) 39130803Smarcel{ 40130803Smarcel int i; 41130803Smarcel 42130803Smarcel for (i = 0; i <= PC_REGNUM; i++) 43130803Smarcel { 44130803Smarcel if (regno == i || regno == -1) 45130803Smarcel { 46130803Smarcel if (CANNOT_FETCH_REGISTER (i)) 47130803Smarcel supply_register (i, NULL); 48130803Smarcel else 49130803Smarcel supply_register (i, regs + (i * mips_regsize (current_gdbarch))); 50130803Smarcel } 51130803Smarcel } 52130803Smarcel} 53130803Smarcel 54130803Smarcelvoid 55130803Smarcelmipsnbsd_fill_reg (char *regs, int regno) 56130803Smarcel{ 57130803Smarcel int i; 58130803Smarcel 59130803Smarcel for (i = 0; i <= PC_REGNUM; i++) 60130803Smarcel if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i)) 61130803Smarcel regcache_collect (i, regs + (i * mips_regsize (current_gdbarch))); 62130803Smarcel} 63130803Smarcel 64130803Smarcelvoid 65130803Smarcelmipsnbsd_supply_fpreg (char *fpregs, int regno) 66130803Smarcel{ 67130803Smarcel int i; 68130803Smarcel 69130803Smarcel for (i = FP0_REGNUM; 70130803Smarcel i <= mips_regnum (current_gdbarch)->fp_implementation_revision; 71130803Smarcel i++) 72130803Smarcel { 73130803Smarcel if (regno == i || regno == -1) 74130803Smarcel { 75130803Smarcel if (CANNOT_FETCH_REGISTER (i)) 76130803Smarcel supply_register (i, NULL); 77130803Smarcel else 78130803Smarcel supply_register (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch))); 79130803Smarcel } 80130803Smarcel } 81130803Smarcel} 82130803Smarcel 83130803Smarcelvoid 84130803Smarcelmipsnbsd_fill_fpreg (char *fpregs, int regno) 85130803Smarcel{ 86130803Smarcel int i; 87130803Smarcel 88130803Smarcel for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status; 89130803Smarcel i++) 90130803Smarcel if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i)) 91130803Smarcel regcache_collect (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch))); 92130803Smarcel} 93130803Smarcel 94130803Smarcelstatic void 95130803Smarcelfetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, 96130803Smarcel CORE_ADDR ignore) 97130803Smarcel{ 98130803Smarcel char *regs, *fpregs; 99130803Smarcel 100130803Smarcel /* We get everything from one section. */ 101130803Smarcel if (which != 0) 102130803Smarcel return; 103130803Smarcel 104130803Smarcel regs = core_reg_sect; 105130803Smarcel fpregs = core_reg_sect + SIZEOF_STRUCT_REG; 106130803Smarcel 107130803Smarcel /* Integer registers. */ 108130803Smarcel mipsnbsd_supply_reg (regs, -1); 109130803Smarcel 110130803Smarcel /* Floating point registers. */ 111130803Smarcel mipsnbsd_supply_fpreg (fpregs, -1); 112130803Smarcel} 113130803Smarcel 114130803Smarcelstatic void 115130803Smarcelfetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which, 116130803Smarcel CORE_ADDR ignore) 117130803Smarcel{ 118130803Smarcel switch (which) 119130803Smarcel { 120130803Smarcel case 0: /* Integer registers. */ 121130803Smarcel if (core_reg_size != SIZEOF_STRUCT_REG) 122130803Smarcel warning ("Wrong size register set in core file."); 123130803Smarcel else 124130803Smarcel mipsnbsd_supply_reg (core_reg_sect, -1); 125130803Smarcel break; 126130803Smarcel 127130803Smarcel case 2: /* Floating point registers. */ 128130803Smarcel if (core_reg_size != SIZEOF_STRUCT_FPREG) 129130803Smarcel warning ("Wrong size register set in core file."); 130130803Smarcel else 131130803Smarcel mipsnbsd_supply_fpreg (core_reg_sect, -1); 132130803Smarcel break; 133130803Smarcel 134130803Smarcel default: 135130803Smarcel /* Don't know what kind of register request this is; just ignore it. */ 136130803Smarcel break; 137130803Smarcel } 138130803Smarcel} 139130803Smarcel 140130803Smarcelstatic struct core_fns mipsnbsd_core_fns = 141130803Smarcel{ 142130803Smarcel bfd_target_unknown_flavour, /* core_flavour */ 143130803Smarcel default_check_format, /* check_format */ 144130803Smarcel default_core_sniffer, /* core_sniffer */ 145130803Smarcel fetch_core_registers, /* core_read_registers */ 146130803Smarcel NULL /* next */ 147130803Smarcel}; 148130803Smarcel 149130803Smarcelstatic struct core_fns mipsnbsd_elfcore_fns = 150130803Smarcel{ 151130803Smarcel bfd_target_elf_flavour, /* core_flavour */ 152130803Smarcel default_check_format, /* check_format */ 153130803Smarcel default_core_sniffer, /* core_sniffer */ 154130803Smarcel fetch_elfcore_registers, /* core_read_registers */ 155130803Smarcel NULL /* next */ 156130803Smarcel}; 157130803Smarcel 158130803Smarcel/* Under NetBSD/mips, signal handler invocations can be identified by the 159130803Smarcel designated code sequence that is used to return from a signal handler. 160130803Smarcel In particular, the return address of a signal handler points to the 161130803Smarcel following code sequence: 162130803Smarcel 163130803Smarcel addu a0, sp, 16 164130803Smarcel li v0, 295 # __sigreturn14 165130803Smarcel syscall 166130803Smarcel 167130803Smarcel Each instruction has a unique encoding, so we simply attempt to match 168130803Smarcel the instruction the PC is pointing to with any of the above instructions. 169130803Smarcel If there is a hit, we know the offset to the start of the designated 170130803Smarcel sequence and can then check whether we really are executing in the 171130803Smarcel signal trampoline. If not, -1 is returned, otherwise the offset from the 172130803Smarcel start of the return sequence is returned. */ 173130803Smarcel 174130803Smarcel#define RETCODE_NWORDS 3 175130803Smarcel#define RETCODE_SIZE (RETCODE_NWORDS * 4) 176130803Smarcel 177130803Smarcelstatic const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] = 178130803Smarcel{ 179130803Smarcel 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */ 180130803Smarcel 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */ 181130803Smarcel 0x0c, 0x00, 0x00, 0x00, /* syscall */ 182130803Smarcel}; 183130803Smarcel 184130803Smarcelstatic const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] = 185130803Smarcel{ 186130803Smarcel 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */ 187130803Smarcel 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */ 188130803Smarcel 0x00, 0x00, 0x00, 0x0c, /* syscall */ 189130803Smarcel}; 190130803Smarcel 191130803Smarcelstatic LONGEST 192130803Smarcelmipsnbsd_sigtramp_offset (CORE_ADDR pc) 193130803Smarcel{ 194130803Smarcel const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG 195130803Smarcel ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel; 196130803Smarcel unsigned char ret[RETCODE_SIZE], w[4]; 197130803Smarcel LONGEST off; 198130803Smarcel int i; 199130803Smarcel 200130803Smarcel if (read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0) 201130803Smarcel return -1; 202130803Smarcel 203130803Smarcel for (i = 0; i < RETCODE_NWORDS; i++) 204130803Smarcel { 205130803Smarcel if (memcmp (w, retcode + (i * 4), 4) == 0) 206130803Smarcel break; 207130803Smarcel } 208130803Smarcel if (i == RETCODE_NWORDS) 209130803Smarcel return -1; 210130803Smarcel 211130803Smarcel off = i * 4; 212130803Smarcel pc -= off; 213130803Smarcel 214130803Smarcel if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0) 215130803Smarcel return -1; 216130803Smarcel 217130803Smarcel if (memcmp (ret, retcode, RETCODE_SIZE) == 0) 218130803Smarcel return off; 219130803Smarcel 220130803Smarcel return -1; 221130803Smarcel} 222130803Smarcel 223130803Smarcelstatic int 224130803Smarcelmipsnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name) 225130803Smarcel{ 226130803Smarcel return (nbsd_pc_in_sigtramp (pc, func_name) 227130803Smarcel || mipsnbsd_sigtramp_offset (pc) >= 0); 228130803Smarcel} 229130803Smarcel 230130803Smarcel/* Figure out where the longjmp will land. We expect that we have 231130803Smarcel just entered longjmp and haven't yet setup the stack frame, so 232130803Smarcel the args are still in the argument regs. A0_REGNUM points at the 233130803Smarcel jmp_buf structure from which we extract the PC that we will land 234130803Smarcel at. The PC is copied into *pc. This routine returns true on 235130803Smarcel success. */ 236130803Smarcel 237130803Smarcel#define NBSD_MIPS_JB_PC (2 * 4) 238130803Smarcel#define NBSD_MIPS_JB_ELEMENT_SIZE mips_regsize (current_gdbarch) 239130803Smarcel#define NBSD_MIPS_JB_OFFSET (NBSD_MIPS_JB_PC * \ 240130803Smarcel NBSD_MIPS_JB_ELEMENT_SIZE) 241130803Smarcel 242130803Smarcelstatic int 243130803Smarcelmipsnbsd_get_longjmp_target (CORE_ADDR *pc) 244130803Smarcel{ 245130803Smarcel CORE_ADDR jb_addr; 246130803Smarcel char *buf; 247130803Smarcel 248130803Smarcel buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE); 249130803Smarcel 250130803Smarcel jb_addr = read_register (A0_REGNUM); 251130803Smarcel 252130803Smarcel if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf, 253130803Smarcel NBSD_MIPS_JB_ELEMENT_SIZE)) 254130803Smarcel return 0; 255130803Smarcel 256130803Smarcel *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE); 257130803Smarcel 258130803Smarcel return 1; 259130803Smarcel} 260130803Smarcel 261130803Smarcelstatic int 262130803Smarcelmipsnbsd_cannot_fetch_register (int regno) 263130803Smarcel{ 264130803Smarcel return (regno == ZERO_REGNUM 265130803Smarcel || regno == mips_regnum (current_gdbarch)->fp_implementation_revision); 266130803Smarcel} 267130803Smarcel 268130803Smarcelstatic int 269130803Smarcelmipsnbsd_cannot_store_register (int regno) 270130803Smarcel{ 271130803Smarcel return (regno == ZERO_REGNUM 272130803Smarcel || regno == mips_regnum (current_gdbarch)->fp_implementation_revision); 273130803Smarcel} 274130803Smarcel 275130803Smarcel/* NetBSD/mips uses a slightly different link_map structure from the 276130803Smarcel other NetBSD platforms. */ 277130803Smarcelstatic struct link_map_offsets * 278130803Smarcelmipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void) 279130803Smarcel{ 280130803Smarcel static struct link_map_offsets lmo; 281130803Smarcel static struct link_map_offsets *lmp = NULL; 282130803Smarcel 283130803Smarcel if (lmp == NULL) 284130803Smarcel { 285130803Smarcel lmp = &lmo; 286130803Smarcel 287130803Smarcel lmo.r_debug_size = 16; 288130803Smarcel 289130803Smarcel lmo.r_map_offset = 4; 290130803Smarcel lmo.r_map_size = 4; 291130803Smarcel 292130803Smarcel lmo.link_map_size = 24; 293130803Smarcel 294130803Smarcel lmo.l_addr_offset = 0; 295130803Smarcel lmo.l_addr_size = 4; 296130803Smarcel 297130803Smarcel lmo.l_name_offset = 8; 298130803Smarcel lmo.l_name_size = 4; 299130803Smarcel 300130803Smarcel lmo.l_next_offset = 16; 301130803Smarcel lmo.l_next_size = 4; 302130803Smarcel 303130803Smarcel lmo.l_prev_offset = 20; 304130803Smarcel lmo.l_prev_size = 4; 305130803Smarcel } 306130803Smarcel 307130803Smarcel return lmp; 308130803Smarcel} 309130803Smarcel 310130803Smarcelstatic struct link_map_offsets * 311130803Smarcelmipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void) 312130803Smarcel{ 313130803Smarcel static struct link_map_offsets lmo; 314130803Smarcel static struct link_map_offsets *lmp = NULL; 315130803Smarcel 316130803Smarcel if (lmp == NULL) 317130803Smarcel { 318130803Smarcel lmp = &lmo; 319130803Smarcel 320130803Smarcel lmo.r_debug_size = 32; 321130803Smarcel 322130803Smarcel lmo.r_map_offset = 8; 323130803Smarcel lmo.r_map_size = 8; 324130803Smarcel 325130803Smarcel lmo.link_map_size = 48; 326130803Smarcel 327130803Smarcel lmo.l_addr_offset = 0; 328130803Smarcel lmo.l_addr_size = 8; 329130803Smarcel 330130803Smarcel lmo.l_name_offset = 16; 331130803Smarcel lmo.l_name_size = 8; 332130803Smarcel 333130803Smarcel lmo.l_next_offset = 32; 334130803Smarcel lmo.l_next_size = 8; 335130803Smarcel 336130803Smarcel lmo.l_prev_offset = 40; 337130803Smarcel lmo.l_prev_size = 8; 338130803Smarcel } 339130803Smarcel 340130803Smarcel return lmp; 341130803Smarcel} 342130803Smarcel 343130803Smarcelstatic void 344130803Smarcelmipsnbsd_init_abi (struct gdbarch_info info, 345130803Smarcel struct gdbarch *gdbarch) 346130803Smarcel{ 347130803Smarcel set_gdbarch_pc_in_sigtramp (gdbarch, mipsnbsd_pc_in_sigtramp); 348130803Smarcel 349130803Smarcel set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target); 350130803Smarcel 351130803Smarcel set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register); 352130803Smarcel set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register); 353130803Smarcel 354130803Smarcel set_gdbarch_software_single_step (gdbarch, mips_software_single_step); 355130803Smarcel 356130803Smarcel set_solib_svr4_fetch_link_map_offsets (gdbarch, 357130803Smarcel gdbarch_ptr_bit (gdbarch) == 32 ? 358130803Smarcel mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets : 359130803Smarcel mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets); 360130803Smarcel} 361130803Smarcel 362130803Smarcelvoid 363130803Smarcel_initialize_mipsnbsd_tdep (void) 364130803Smarcel{ 365130803Smarcel gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF, 366130803Smarcel mipsnbsd_init_abi); 367130803Smarcel 368130803Smarcel add_core_fns (&mipsnbsd_core_fns); 369130803Smarcel add_core_fns (&mipsnbsd_elfcore_fns); 370130803Smarcel} 371