1 /* Target-dependent code for OpenBSD/mips64. 2 3 Copyright 2004 Free Software Foundation, 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 "osabi.h" 25 #include "regcache.h" 26 #include "regset.h" 27 #include "trad-frame.h" 28 #include "tramp-frame.h" 29 30 #include "gdb_assert.h" 31 #include "gdb_string.h" 32 33 #include "mips-tdep.h" 34 #include "obsd-tdep.h" 35 #include "solib-svr4.h" 36 37 #define MIPS64OBSD_NUM_REGS 73 38 39 /* Core file support. */ 40 41 /* Supply register REGNUM from the buffer specified by GREGS and LEN 42 in the general-purpose register set REGSET to register cache 43 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 44 45 static void 46 mips64obsd_supply_gregset (const struct regset *regset, 47 struct regcache *regcache, int regnum, 48 const void *gregs, size_t len) 49 { 50 const char *regs = gregs; 51 int i; 52 53 for (i = 0; i < MIPS64OBSD_NUM_REGS; i++) 54 { 55 if (regnum == i || regnum == -1) 56 regcache_raw_supply (regcache, i, regs + i * 8); 57 } 58 } 59 60 /* OpenBSD/mips64 register set. */ 61 62 static struct regset mips64obsd_gregset = 63 { 64 NULL, 65 mips64obsd_supply_gregset 66 }; 67 68 /* Return the appropriate register set for the core section identified 69 by SECT_NAME and SECT_SIZE. */ 70 71 static const struct regset * 72 mips64obsd_regset_from_core_section (struct gdbarch *gdbarch, 73 const char *sect_name, size_t sect_size) 74 { 75 if (strcmp (sect_name, ".reg") == 0 && sect_size >= MIPS64OBSD_NUM_REGS * 8) 76 return &mips64obsd_gregset; 77 78 return NULL; 79 } 80 81 82 /* Signal trampolines. */ 83 84 static void 85 mips64obsd_sigframe_init (const struct tramp_frame *self, 86 struct frame_info *next_frame, 87 struct trad_frame_cache *cache, 88 CORE_ADDR func) 89 { 90 struct gdbarch *gdbarch = get_frame_arch (next_frame); 91 CORE_ADDR sp, sigcontext_addr, addr; 92 int regnum; 93 94 /* We find the appropriate instance of `struct sigcontext' at a 95 fixed offset in the signal frame. */ 96 sp = frame_unwind_register_signed (next_frame, MIPS_SP_REGNUM + NUM_REGS); 97 sigcontext_addr = sp + 32; 98 99 /* PC. */ 100 regnum = mips_regnum (gdbarch)->pc; 101 trad_frame_set_reg_addr (cache, regnum + NUM_REGS, sigcontext_addr + 16); 102 103 /* GPRs. */ 104 for (regnum = MIPS_AT_REGNUM, addr = sigcontext_addr + 32; 105 regnum <= MIPS_RA_REGNUM; regnum++, addr += 8) 106 trad_frame_set_reg_addr (cache, regnum + NUM_REGS, addr); 107 108 /* HI and LO. */ 109 regnum = mips_regnum (gdbarch)->lo; 110 trad_frame_set_reg_addr (cache, regnum + NUM_REGS, sigcontext_addr + 280); 111 regnum = mips_regnum (gdbarch)->hi; 112 trad_frame_set_reg_addr (cache, regnum + NUM_REGS, sigcontext_addr + 288); 113 114 /* TODO: Handle the floating-point registers. */ 115 116 trad_frame_set_id (cache, frame_id_build (sp, func)); 117 } 118 119 static const struct tramp_frame mips64obsd_sigframe = 120 { 121 SIGTRAMP_FRAME, 122 MIPS_INSN32_SIZE, 123 { 124 { 0x67a40020, -1 }, /* daddiu a0,sp,32 */ 125 { 0x24020067, -1 }, /* li v0,103 */ 126 { 0x0000000c, -1 }, /* syscall */ 127 { 0x0000000d, -1 }, /* break */ 128 { TRAMP_SENTINEL_INSN, -1 } 129 }, 130 mips64obsd_sigframe_init 131 }; 132 133 134 /* Check the code at PC for a dynamic linker lazy resolution stub. Because 135 they aren't in the .plt section, we pattern-match on the code generated 136 by GNU ld. They look like this: 137 138 ld t9,0x8010(gp) 139 daddu t7,ra 140 jalr t9,ra 141 daddiu t8,zero,INDEX 142 143 Also return the dynamic symbol index used in the last instruction. */ 144 145 static int 146 mips64obsd_in_dynsym_stub (CORE_ADDR pc, char *name) 147 { 148 unsigned char buf[28], *p; 149 ULONGEST insn; 150 151 read_memory (pc - 12, buf, 28); 152 153 p = buf + 12; 154 while (p >= buf) 155 { 156 insn = extract_unsigned_integer (p, 4); 157 /* ld t9,0x8010(gp) */ 158 if (insn == 0xdf998010) 159 break; 160 p -= 4; 161 } 162 if (p < buf) 163 return 0; 164 165 insn = extract_unsigned_integer (p + 4, 4); 166 /* daddu t7,ra */ 167 if (insn != 0x03e0782d) 168 return 0; 169 170 insn = extract_unsigned_integer (p + 8, 4); 171 /* jalr t9,ra */ 172 if (insn != 0x0320f809) 173 return 0; 174 175 insn = extract_unsigned_integer (p + 12, 4); 176 /* daddiu t8,zero,0 */ 177 if ((insn & 0xffff0000) != 0x64180000) 178 return 0; 179 180 return (insn & 0xffff); 181 } 182 183 /* Return non-zero iff PC belongs to the dynamic linker resolution code 184 or to a stub. */ 185 186 int 187 mips64obsd_in_dynsym_resolve_code (CORE_ADDR pc) 188 { 189 /* Check whether PC is in the dynamic linker. This also checks whether 190 it is in the .plt section, which MIPS does not use. */ 191 if (in_solib_dynsym_resolve_code (pc)) 192 return 1; 193 194 /* Pattern match for the stub. It would be nice if there were a more 195 efficient way to avoid this check. */ 196 if (mips64obsd_in_dynsym_stub (pc, NULL)) 197 return 1; 198 199 return 0; 200 } 201 202 203 static void 204 mips64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 205 { 206 /* OpenBSD/mips64 only supports the n64 ABI, but the braindamaged 207 way GDB works, forces us to pretend we can handle them all. */ 208 209 set_gdbarch_regset_from_core_section 210 (gdbarch, mips64obsd_regset_from_core_section); 211 212 tramp_frame_prepend_unwinder (gdbarch, &mips64obsd_sigframe); 213 214 #if 0 215 set_gdbarch_software_single_step (gdbarch, mips_software_single_step); 216 #endif 217 218 /* OpenBSD/mips64 has SVR4-style shared libraries. */ 219 set_gdbarch_in_solib_call_trampoline (gdbarch, mips64obsd_in_dynsym_stub); 220 set_solib_svr4_fetch_link_map_offsets 221 (gdbarch, svr4_lp64_fetch_link_map_offsets); 222 set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver); 223 } 224 225 226 /* Provide a prototype to silence -Wmissing-prototypes. */ 227 void _initialize_mips64obsd_tdep (void); 228 229 void 230 _initialize_mips64obsd_tdep (void) 231 { 232 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_OPENBSD_ELF, 233 mips64obsd_init_abi); 234 } 235