1 /* Target-dependent code for OpenBSD/powerpc64. 2 3 Copyright (C) 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, 20 Boston, MA 02110-1301, USA. */ 21 22 #include "defs.h" 23 #include "arch-utils.h" 24 #include "floatformat.h" 25 #include "frame.h" 26 #include "frame-unwind.h" 27 #include "osabi.h" 28 #include "regcache.h" 29 #include "regset.h" 30 #include "symtab.h" 31 #include "trad-frame.h" 32 33 #include "gdb_assert.h" 34 #include "gdb_string.h" 35 36 #include "ppc-tdep.h" 37 #include "ppc64obsd-tdep.h" 38 #include "solib-svr4.h" 39 40 /* Register offsets from <machine/reg.h>. */ 41 struct ppc_reg_offsets ppc64obsd_reg_offsets; 42 struct ppc_reg_offsets ppc64obsd_fpreg_offsets; 43 44 45 /* Register set support functions. */ 46 47 static void 48 ppc64_supply_reg (struct regcache *regcache, int regnum, 49 const char *regs, size_t offset) 50 { 51 if (regnum != -1 && offset != -1) 52 regcache_raw_supply (regcache, regnum, regs + offset); 53 } 54 55 static void 56 ppc64_collect_reg (const struct regcache *regcache, int regnum, 57 char *regs, size_t offset) 58 { 59 if (regnum != -1 && offset != -1) 60 regcache_raw_collect (regcache, regnum, regs + offset); 61 } 62 63 /* Supply register REGNUM in the general-purpose register set REGSET 64 from the buffer specified by GREGS and LEN to register cache 65 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 66 67 void 68 ppc64_supply_gregset (const struct regset *regset, struct regcache *regcache, 69 int regnum, const void *gregs, size_t len) 70 { 71 struct gdbarch *gdbarch = get_regcache_arch (regcache); 72 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 73 const struct ppc_reg_offsets *offsets = regset->descr; 74 size_t offset; 75 int i; 76 77 for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset; 78 i < tdep->ppc_gp0_regnum + ppc_num_gprs; 79 i++, offset += 8) 80 { 81 if (regnum == -1 || regnum == i) 82 ppc64_supply_reg (regcache, i, gregs, offset); 83 } 84 85 if (regnum == -1 || regnum == PC_REGNUM) 86 ppc64_supply_reg (regcache, PC_REGNUM, gregs, offsets->pc_offset); 87 if (regnum == -1 || regnum == tdep->ppc_ps_regnum) 88 ppc64_supply_reg (regcache, tdep->ppc_ps_regnum, 89 gregs, offsets->ps_offset); 90 if (regnum == -1 || regnum == tdep->ppc_cr_regnum) 91 ppc64_supply_reg (regcache, tdep->ppc_cr_regnum, 92 gregs, offsets->cr_offset); 93 if (regnum == -1 || regnum == tdep->ppc_lr_regnum) 94 ppc64_supply_reg (regcache, tdep->ppc_lr_regnum, 95 gregs, offsets->lr_offset); 96 if (regnum == -1 || regnum == tdep->ppc_ctr_regnum) 97 ppc64_supply_reg (regcache, tdep->ppc_ctr_regnum, 98 gregs, offsets->ctr_offset); 99 if (regnum == -1 || regnum == tdep->ppc_xer_regnum) 100 ppc64_supply_reg (regcache, tdep->ppc_xer_regnum, 101 gregs, offsets->cr_offset); 102 } 103 104 /* Collect register REGNUM in the general-purpose register set 105 REGSET. from register cache REGCACHE into the buffer specified by 106 GREGS and LEN. If REGNUM is -1, do this for all registers in 107 REGSET. */ 108 109 void 110 ppc64_collect_gregset (const struct regset *regset, 111 const struct regcache *regcache, 112 int regnum, void *gregs, size_t len) 113 { 114 struct gdbarch *gdbarch = get_regcache_arch (regcache); 115 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 116 const struct ppc_reg_offsets *offsets = regset->descr; 117 size_t offset; 118 int i; 119 120 offset = offsets->r0_offset; 121 for (i = tdep->ppc_gp0_regnum; 122 i < tdep->ppc_gp0_regnum + ppc_num_gprs; 123 i++, offset += 8) 124 { 125 if (regnum == -1 || regnum == i) 126 ppc64_collect_reg (regcache, i, gregs, offset); 127 } 128 129 if (regnum == -1 || regnum == PC_REGNUM) 130 ppc64_collect_reg (regcache, PC_REGNUM, gregs, offsets->pc_offset); 131 if (regnum == -1 || regnum == tdep->ppc_ps_regnum) 132 ppc64_collect_reg (regcache, tdep->ppc_ps_regnum, 133 gregs, offsets->ps_offset); 134 if (regnum == -1 || regnum == tdep->ppc_cr_regnum) 135 ppc64_collect_reg (regcache, tdep->ppc_cr_regnum, 136 gregs, offsets->cr_offset); 137 if (regnum == -1 || regnum == tdep->ppc_lr_regnum) 138 ppc64_collect_reg (regcache, tdep->ppc_lr_regnum, 139 gregs, offsets->lr_offset); 140 if (regnum == -1 || regnum == tdep->ppc_ctr_regnum) 141 ppc64_collect_reg (regcache, tdep->ppc_ctr_regnum, 142 gregs, offsets->ctr_offset); 143 if (regnum == -1 || regnum == tdep->ppc_xer_regnum) 144 ppc64_collect_reg (regcache, tdep->ppc_xer_regnum, 145 gregs, offsets->xer_offset); 146 } 147 148 /* Core file support. */ 149 150 /* Supply register REGNUM in the general-purpose register set REGSET 151 from the buffer specified by GREGS and LEN to register cache 152 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ 153 154 void 155 ppc64obsd_supply_gregset (const struct regset *regset, 156 struct regcache *regcache, int regnum, 157 const void *gregs, size_t len) 158 { 159 ppc64_supply_gregset (regset, regcache, regnum, gregs, len); 160 } 161 162 /* Collect register REGNUM in the general-purpose register set 163 REGSET. from register cache REGCACHE into the buffer specified by 164 GREGS and LEN. If REGNUM is -1, do this for all registers in 165 REGSET. */ 166 167 void 168 ppc64obsd_collect_gregset (const struct regset *regset, 169 const struct regcache *regcache, int regnum, 170 void *gregs, size_t len) 171 { 172 ppc64_collect_gregset (regset, regcache, regnum, gregs, len); 173 } 174 175 /* OpenBSD/powerpc register set. */ 176 177 struct regset ppc64obsd_gregset = 178 { 179 &ppc64obsd_reg_offsets, 180 ppc64obsd_supply_gregset 181 }; 182 183 struct regset ppc64obsd_fpregset = 184 { 185 &ppc64obsd_fpreg_offsets, 186 ppc_supply_fpregset 187 }; 188 189 /* Return the appropriate register set for the core section identified 190 by SECT_NAME and SECT_SIZE. */ 191 192 static const struct regset * 193 ppc64obsd_regset_from_core_section (struct gdbarch *gdbarch, 194 const char *sect_name, size_t sect_size) 195 { 196 if (strcmp (sect_name, ".reg") == 0 && sect_size >= 304) 197 return &ppc64obsd_gregset; 198 199 if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 1048) 200 return &ppc64obsd_fpregset; 201 202 return NULL; 203 } 204 205 206 /* Signal trampolines. */ 207 208 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page 209 in virtual memory. The randomness makes it somewhat tricky to 210 detect it, but fortunately we can rely on the fact that the start 211 of the sigtramp routine is page-aligned. We recognize the 212 trampoline by looking for the code that invokes the sigreturn 213 system call. The offset where we can find that code varies from 214 release to release. 215 216 By the way, the mapping mentioned above is read-only, so you cannot 217 place a breakpoint in the signal trampoline. */ 218 219 /* Default page size. */ 220 static const int ppc64obsd_page_size = 4096; 221 222 /* Offset for sigreturn(2). */ 223 static const int ppc64obsd_sigreturn_offset[] = { 224 0x98, /* OpenBSD 3.8 */ 225 0x0c, /* OpenBSD 3.2 */ 226 -1 227 }; 228 229 static int 230 ppc64obsd_sigtramp_p (struct frame_info *next_frame) 231 { 232 CORE_ADDR pc = frame_pc_unwind (next_frame); 233 CORE_ADDR start_pc = (pc & ~(ppc64obsd_page_size - 1)); 234 const int *offset; 235 char *name; 236 237 find_pc_partial_function (pc, &name, NULL, NULL); 238 if (name) 239 return 0; 240 241 for (offset = ppc64obsd_sigreturn_offset; *offset != -1; offset++) 242 { 243 char buf[2 * PPC_INSN_SIZE]; 244 unsigned long insn; 245 246 if (!safe_frame_unwind_memory (next_frame, start_pc + *offset, 247 buf, sizeof buf)) 248 continue; 249 250 /* Check for "li r0,SYS_sigreturn". */ 251 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE); 252 if (insn != 0x38000067) 253 continue; 254 255 /* Check for "sc". */ 256 insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE); 257 if (insn != 0x44000002) 258 continue; 259 260 return 1; 261 } 262 263 return 0; 264 } 265 266 static struct trad_frame_cache * 267 ppc64obsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) 268 { 269 struct gdbarch *gdbarch = get_frame_arch (next_frame); 270 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 271 struct trad_frame_cache *cache; 272 CORE_ADDR addr, base, func; 273 char buf[PPC_INSN_SIZE]; 274 unsigned long insn, sigcontext_offset; 275 int i; 276 277 if (*this_cache) 278 return *this_cache; 279 280 cache = trad_frame_cache_zalloc (next_frame); 281 *this_cache = cache; 282 283 func = frame_pc_unwind (next_frame); 284 func &= ~(ppc64obsd_page_size - 1); 285 if (!safe_frame_unwind_memory (next_frame, func, buf, sizeof buf)) 286 return cache; 287 288 /* Calculate the offset where we can find `struct sigcontext'. We 289 base our calculation on the amount of stack space reserved by the 290 first instruction of the signal trampoline. */ 291 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE); 292 sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8; 293 294 base = frame_unwind_register_unsigned (next_frame, SP_REGNUM); 295 addr = base + sigcontext_offset + 2 * tdep->wordsize; 296 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize) 297 { 298 int regnum = i + tdep->ppc_gp0_regnum; 299 trad_frame_set_reg_addr (cache, regnum, addr); 300 } 301 trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr); 302 addr += tdep->wordsize; 303 trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr); 304 addr += tdep->wordsize; 305 trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr); 306 addr += tdep->wordsize; 307 trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr); 308 addr += tdep->wordsize; 309 trad_frame_set_reg_addr (cache, PC_REGNUM, addr); /* SRR0? */ 310 addr += tdep->wordsize; 311 312 /* Construct the frame ID using the function start. */ 313 trad_frame_set_id (cache, frame_id_build (base, func)); 314 315 return cache; 316 } 317 318 static void 319 ppc64obsd_sigtramp_frame_this_id (struct frame_info *next_frame, 320 void **this_cache, struct frame_id *this_id) 321 { 322 struct trad_frame_cache *cache = 323 ppc64obsd_sigtramp_frame_cache (next_frame, this_cache); 324 325 trad_frame_get_id (cache, this_id); 326 } 327 328 static void 329 ppc64obsd_sigtramp_frame_prev_register (struct frame_info *next_frame, 330 void **this_cache, int regnum, 331 int *optimizedp, enum lval_type *lvalp, 332 CORE_ADDR *addrp, int *realnump, 333 char *valuep) 334 { 335 struct trad_frame_cache *cache = 336 ppc64obsd_sigtramp_frame_cache (next_frame, this_cache); 337 338 trad_frame_get_register (cache, next_frame, regnum, 339 optimizedp, lvalp, addrp, realnump, valuep); 340 } 341 342 static const struct frame_unwind ppc64obsd_sigtramp_frame_unwind = { 343 SIGTRAMP_FRAME, 344 ppc64obsd_sigtramp_frame_this_id, 345 ppc64obsd_sigtramp_frame_prev_register 346 }; 347 348 static const struct frame_unwind * 349 ppc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame) 350 { 351 if (ppc64obsd_sigtramp_p (next_frame)) 352 return &ppc64obsd_sigtramp_frame_unwind; 353 354 return NULL; 355 } 356 357 358 static void 359 ppc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 360 { 361 /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */ 362 set_gdbarch_long_double_bit (gdbarch, 64); 363 set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big); 364 365 /* OpenBSD currently uses a broken GCC. */ 366 set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value); 367 368 /* OpenBSD uses SVR4-style shared libraries. */ 369 set_solib_svr4_fetch_link_map_offsets 370 (gdbarch, svr4_lp64_fetch_link_map_offsets); 371 372 set_gdbarch_regset_from_core_section 373 (gdbarch, ppc64obsd_regset_from_core_section); 374 375 frame_unwind_append_sniffer (gdbarch, ppc64obsd_sigtramp_frame_sniffer); 376 } 377 378 379 /* OpenBSD uses uses the traditional NetBSD core file format, even for 380 ports that use ELF. */ 381 #define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF 382 383 static enum gdb_osabi 384 ppc64obsd_core_osabi_sniffer (bfd *abfd) 385 { 386 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0) 387 return GDB_OSABI_NETBSD_CORE; 388 389 return GDB_OSABI_UNKNOWN; 390 } 391 392 393 /* Provide a prototype to silence -Wmissing-prototypes. */ 394 void _initialize_ppc64obsd_tdep (void); 395 396 void 397 _initialize_ppc64obsd_tdep (void) 398 { 399 /* BFD doesn't set a flavour for NetBSD style a.out core files. */ 400 gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour, 401 ppc64obsd_core_osabi_sniffer); 402 403 #if 0 404 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF, 405 ppc64obsd_init_abi); 406 #endif 407 gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64, 408 GDB_OSABI_OPENBSD_ELF, ppc64obsd_init_abi); 409 410 /* Avoid initializing the register offsets again if they were 411 already initailized by ppc64obsd-nat.c. */ 412 if (ppc64obsd_reg_offsets.pc_offset == 0) 413 { 414 /* General-purpose registers. */ 415 ppc64obsd_reg_offsets.r0_offset = 0; 416 ppc64obsd_reg_offsets.pc_offset = 288; 417 ppc64obsd_reg_offsets.ps_offset = 296; 418 ppc64obsd_reg_offsets.cr_offset = 264; 419 ppc64obsd_reg_offsets.lr_offset = 256; 420 ppc64obsd_reg_offsets.ctr_offset = 280; 421 ppc64obsd_reg_offsets.xer_offset = 272; 422 ppc64obsd_reg_offsets.mq_offset = -1; 423 424 /* Floating-point registers. */ 425 ppc64obsd_reg_offsets.f0_offset = -1; 426 ppc64obsd_reg_offsets.fpscr_offset = -1; 427 428 /* AltiVec registers. */ 429 ppc64obsd_reg_offsets.vr0_offset = -1; 430 ppc64obsd_reg_offsets.vscr_offset = -1; 431 ppc64obsd_reg_offsets.vrsave_offset = -1; 432 } 433 434 if (ppc64obsd_fpreg_offsets.fpscr_offset == 0) 435 { 436 /* Floating-point registers. */ 437 ppc64obsd_reg_offsets.f0_offset = -1; 438 ppc64obsd_reg_offsets.fpscr_offset = -1; 439 } 440 } 441