1/* Target-dependent code for MIPS systems running NetBSD. 2 Copyright 2002, 2003 Free Software Foundation, Inc. 3 Contributed by Wasabi Systems, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place - Suite 330, 20 Boston, MA 02111-1307, USA. */ 21 22#include "defs.h" 23#include "gdbcore.h" 24#include "regcache.h" 25#include "target.h" 26#include "value.h" 27#include "osabi.h" 28 29#include "nbsd-tdep.h" 30#include "mipsnbsd-tdep.h" 31 32#include "solib-svr4.h" 33 34/* Conveniently, GDB uses the same register numbering as the 35 ptrace register structure used by NetBSD/mips. */ 36 37void 38mipsnbsd_supply_reg (char *regs, int regno) 39{ 40 int i; 41 42 for (i = 0; i <= PC_REGNUM; i++) 43 { 44 if (regno == i || regno == -1) 45 { 46 if (CANNOT_FETCH_REGISTER (i)) 47 supply_register (i, NULL); 48 else 49 supply_register (i, regs + (i * mips_regsize (current_gdbarch))); 50 } 51 } 52} 53 54void 55mipsnbsd_fill_reg (char *regs, int regno) 56{ 57 int i; 58 59 for (i = 0; i <= PC_REGNUM; i++) 60 if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i)) 61 regcache_collect (i, regs + (i * mips_regsize (current_gdbarch))); 62} 63 64void 65mipsnbsd_supply_fpreg (char *fpregs, int regno) 66{ 67 int i; 68 69 for (i = FP0_REGNUM; 70 i <= mips_regnum (current_gdbarch)->fp_implementation_revision; 71 i++) 72 { 73 if (regno == i || regno == -1) 74 { 75 if (CANNOT_FETCH_REGISTER (i)) 76 supply_register (i, NULL); 77 else 78 supply_register (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch))); 79 } 80 } 81} 82 83void 84mipsnbsd_fill_fpreg (char *fpregs, int regno) 85{ 86 int i; 87 88 for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status; 89 i++) 90 if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i)) 91 regcache_collect (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch))); 92} 93 94static void 95fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, 96 CORE_ADDR ignore) 97{ 98 char *regs, *fpregs; 99 100 /* We get everything from one section. */ 101 if (which != 0) 102 return; 103 104 regs = core_reg_sect; 105 fpregs = core_reg_sect + SIZEOF_STRUCT_REG; 106 107 /* Integer registers. */ 108 mipsnbsd_supply_reg (regs, -1); 109 110 /* Floating point registers. */ 111 mipsnbsd_supply_fpreg (fpregs, -1); 112} 113 114static void 115fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which, 116 CORE_ADDR ignore) 117{ 118 switch (which) 119 { 120 case 0: /* Integer registers. */ 121 if (core_reg_size != SIZEOF_STRUCT_REG) 122 warning ("Wrong size register set in core file."); 123 else 124 mipsnbsd_supply_reg (core_reg_sect, -1); 125 break; 126 127 case 2: /* Floating point registers. */ 128 if (core_reg_size != SIZEOF_STRUCT_FPREG) 129 warning ("Wrong size register set in core file."); 130 else 131 mipsnbsd_supply_fpreg (core_reg_sect, -1); 132 break; 133 134 default: 135 /* Don't know what kind of register request this is; just ignore it. */ 136 break; 137 } 138} 139 140static struct core_fns mipsnbsd_core_fns = 141{ 142 bfd_target_unknown_flavour, /* core_flavour */ 143 default_check_format, /* check_format */ 144 default_core_sniffer, /* core_sniffer */ 145 fetch_core_registers, /* core_read_registers */ 146 NULL /* next */ 147}; 148 149static struct core_fns mipsnbsd_elfcore_fns = 150{ 151 bfd_target_elf_flavour, /* core_flavour */ 152 default_check_format, /* check_format */ 153 default_core_sniffer, /* core_sniffer */ 154 fetch_elfcore_registers, /* core_read_registers */ 155 NULL /* next */ 156}; 157 158/* Under NetBSD/mips, signal handler invocations can be identified by the 159 designated code sequence that is used to return from a signal handler. 160 In particular, the return address of a signal handler points to the 161 following code sequence: 162 163 addu a0, sp, 16 164 li v0, 295 # __sigreturn14 165 syscall 166 167 Each instruction has a unique encoding, so we simply attempt to match 168 the instruction the PC is pointing to with any of the above instructions. 169 If there is a hit, we know the offset to the start of the designated 170 sequence and can then check whether we really are executing in the 171 signal trampoline. If not, -1 is returned, otherwise the offset from the 172 start of the return sequence is returned. */ 173 174#define RETCODE_NWORDS 3 175#define RETCODE_SIZE (RETCODE_NWORDS * 4) 176 177static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] = 178{ 179 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */ 180 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */ 181 0x0c, 0x00, 0x00, 0x00, /* syscall */ 182}; 183 184static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] = 185{ 186 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */ 187 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */ 188 0x00, 0x00, 0x00, 0x0c, /* syscall */ 189}; 190 191static LONGEST 192mipsnbsd_sigtramp_offset (CORE_ADDR pc) 193{ 194 const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG 195 ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel; 196 unsigned char ret[RETCODE_SIZE], w[4]; 197 LONGEST off; 198 int i; 199 200 if (read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0) 201 return -1; 202 203 for (i = 0; i < RETCODE_NWORDS; i++) 204 { 205 if (memcmp (w, retcode + (i * 4), 4) == 0) 206 break; 207 } 208 if (i == RETCODE_NWORDS) 209 return -1; 210 211 off = i * 4; 212 pc -= off; 213 214 if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0) 215 return -1; 216 217 if (memcmp (ret, retcode, RETCODE_SIZE) == 0) 218 return off; 219 220 return -1; 221} 222 223static int 224mipsnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name) 225{ 226 return (nbsd_pc_in_sigtramp (pc, func_name) 227 || mipsnbsd_sigtramp_offset (pc) >= 0); 228} 229 230/* Figure out where the longjmp will land. We expect that we have 231 just entered longjmp and haven't yet setup the stack frame, so 232 the args are still in the argument regs. A0_REGNUM points at the 233 jmp_buf structure from which we extract the PC that we will land 234 at. The PC is copied into *pc. This routine returns true on 235 success. */ 236 237#define NBSD_MIPS_JB_PC (2 * 4) 238#define NBSD_MIPS_JB_ELEMENT_SIZE mips_regsize (current_gdbarch) 239#define NBSD_MIPS_JB_OFFSET (NBSD_MIPS_JB_PC * \ 240 NBSD_MIPS_JB_ELEMENT_SIZE) 241 242static int 243mipsnbsd_get_longjmp_target (CORE_ADDR *pc) 244{ 245 CORE_ADDR jb_addr; 246 char *buf; 247 248 buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE); 249 250 jb_addr = read_register (A0_REGNUM); 251 252 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf, 253 NBSD_MIPS_JB_ELEMENT_SIZE)) 254 return 0; 255 256 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE); 257 258 return 1; 259} 260 261static int 262mipsnbsd_cannot_fetch_register (int regno) 263{ 264 return (regno == ZERO_REGNUM 265 || regno == mips_regnum (current_gdbarch)->fp_implementation_revision); 266} 267 268static int 269mipsnbsd_cannot_store_register (int regno) 270{ 271 return (regno == ZERO_REGNUM 272 || regno == mips_regnum (current_gdbarch)->fp_implementation_revision); 273} 274 275/* NetBSD/mips uses a slightly different link_map structure from the 276 other NetBSD platforms. */ 277static struct link_map_offsets * 278mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void) 279{ 280 static struct link_map_offsets lmo; 281 static struct link_map_offsets *lmp = NULL; 282 283 if (lmp == NULL) 284 { 285 lmp = &lmo; 286 287 lmo.r_debug_size = 16; 288 289 lmo.r_map_offset = 4; 290 lmo.r_map_size = 4; 291 292 lmo.link_map_size = 24; 293 294 lmo.l_addr_offset = 0; 295 lmo.l_addr_size = 4; 296 297 lmo.l_name_offset = 8; 298 lmo.l_name_size = 4; 299 300 lmo.l_next_offset = 16; 301 lmo.l_next_size = 4; 302 303 lmo.l_prev_offset = 20; 304 lmo.l_prev_size = 4; 305 } 306 307 return lmp; 308} 309 310static struct link_map_offsets * 311mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void) 312{ 313 static struct link_map_offsets lmo; 314 static struct link_map_offsets *lmp = NULL; 315 316 if (lmp == NULL) 317 { 318 lmp = &lmo; 319 320 lmo.r_debug_size = 32; 321 322 lmo.r_map_offset = 8; 323 lmo.r_map_size = 8; 324 325 lmo.link_map_size = 48; 326 327 lmo.l_addr_offset = 0; 328 lmo.l_addr_size = 8; 329 330 lmo.l_name_offset = 16; 331 lmo.l_name_size = 8; 332 333 lmo.l_next_offset = 32; 334 lmo.l_next_size = 8; 335 336 lmo.l_prev_offset = 40; 337 lmo.l_prev_size = 8; 338 } 339 340 return lmp; 341} 342 343static void 344mipsnbsd_init_abi (struct gdbarch_info info, 345 struct gdbarch *gdbarch) 346{ 347 set_gdbarch_pc_in_sigtramp (gdbarch, mipsnbsd_pc_in_sigtramp); 348 349 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target); 350 351 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register); 352 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register); 353 354 set_gdbarch_software_single_step (gdbarch, mips_software_single_step); 355 356 set_solib_svr4_fetch_link_map_offsets (gdbarch, 357 gdbarch_ptr_bit (gdbarch) == 32 ? 358 mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets : 359 mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets); 360} 361 362void 363_initialize_mipsnbsd_tdep (void) 364{ 365 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF, 366 mipsnbsd_init_abi); 367 368 add_core_fns (&mipsnbsd_core_fns); 369 add_core_fns (&mipsnbsd_elfcore_fns); 370} 371