1 /* Target-dependent code for OpenBSD/amd64. 2 3 Copyright 2003, 2004, 2005 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 "frame.h" 24 #include "frame-unwind.h" 25 #include "gdbcore.h" 26 #include "symtab.h" 27 #include "objfiles.h" 28 #include "osabi.h" 29 #include "regcache.h" 30 #include "regset.h" 31 #include "target.h" 32 #include "trad-frame.h" 33 34 #include "gdb_assert.h" 35 #include "gdb_string.h" 36 37 #include "amd64-tdep.h" 38 #include "i387-tdep.h" 39 #include "solib-svr4.h" 40 #include "bsd-uthread.h" 41 42 /* Support for core dumps. */ 43 44 static void 45 amd64obsd_supply_regset (const struct regset *regset, 46 struct regcache *regcache, int regnum, 47 const void *regs, size_t len) 48 { 49 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); 50 51 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE); 52 53 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset); 54 amd64_supply_fxsave (regcache, regnum, (char *)regs + tdep->sizeof_gregset); 55 } 56 57 static const struct regset * 58 amd64obsd_regset_from_core_section (struct gdbarch *gdbarch, 59 const char *sect_name, size_t sect_size) 60 { 61 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 62 63 /* OpenBSD core dumps don't use seperate register sets for the 64 general-purpose and floating-point registers. */ 65 66 if (strcmp (sect_name, ".reg") == 0 67 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE) 68 { 69 if (tdep->gregset == NULL) 70 tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL); 71 return tdep->gregset; 72 } 73 74 return NULL; 75 } 76 77 78 /* Support for signal handlers. */ 79 80 /* Default page size. */ 81 static const int amd64obsd_page_size = 4096; 82 83 /* Offset for sigreturn(2). */ 84 static const int amd64obsd_sigreturn_offset[] = { 85 9, /* OpenBSD 6.4+ */ 86 6, /* OpenBSD 5.1+ */ 87 7, /* OpenBSD 5.1+ */ 88 -1 89 }; 90 91 /* Return whether the frame preceding NEXT_FRAME corresponds to an 92 OpenBSD sigtramp routine. */ 93 94 static int 95 amd64obsd_sigtramp_p (struct frame_info *next_frame) 96 { 97 CORE_ADDR pc = frame_pc_unwind (next_frame); 98 CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1)); 99 const char sigreturn[] = 100 { 101 0x48, 0xc7, 0xc0, 102 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ 103 0x0f, 0x05 /* syscall */ 104 }; 105 char buf[sizeof sigreturn]; 106 const int *offset; 107 char *name; 108 109 /* If the function has a valid symbol name, it isn't a 110 trampoline. */ 111 find_pc_partial_function (pc, &name, NULL, NULL); 112 if (name != NULL) 113 return 0; 114 115 /* If the function lives in a valid section (even without a starting 116 point) it isn't a trampoline. */ 117 if (find_pc_section (pc) != NULL) 118 return 0; 119 120 for (offset = amd64obsd_sigreturn_offset; *offset != -1; offset++) 121 { 122 if (!safe_frame_unwind_memory (next_frame, start_pc + *offset, 123 buf, sizeof buf)) 124 continue; 125 126 /* Check for sigreturn(2). */ 127 if (memcmp (buf, sigreturn, sizeof sigreturn)) 128 continue; 129 130 return 1; 131 } 132 133 return 0; 134 } 135 136 /* Assuming NEXT_FRAME is for a frame following a BSD sigtramp 137 routine, return the address of the associated sigcontext structure. */ 138 139 static CORE_ADDR 140 amd64obsd_sigcontext_addr (struct frame_info *next_frame) 141 { 142 CORE_ADDR pc = frame_pc_unwind (next_frame); 143 ULONGEST offset = (pc & (amd64obsd_page_size - 1)); 144 145 /* The %rsp register points at `struct sigcontext' upon entry of a 146 signal trampoline. The relevant part of the trampoline is 147 148 call *%rax 149 movq %rsp, %rdi 150 pushq %rdi 151 movq $SYS_sigreturn,%rax 152 int $0x80 153 154 (see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq' 155 instruction clobbers %rsp, but its value is saved in `%rdi'. */ 156 157 if (offset > 5) 158 return frame_unwind_register_unsigned (next_frame, AMD64_RDI_REGNUM); 159 else 160 return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM); 161 } 162 163 /* OpenBSD 3.5 or later. */ 164 165 /* Mapping between the general-purpose registers in `struct reg' 166 format and GDB's register cache layout. */ 167 168 /* From <machine/reg.h>. */ 169 int amd64obsd_r_reg_offset[] = 170 { 171 14 * 8, /* %rax */ 172 13 * 8, /* %rbx */ 173 3 * 8, /* %rcx */ 174 2 * 8, /* %rdx */ 175 1 * 8, /* %rsi */ 176 0 * 8, /* %rdi */ 177 12 * 8, /* %rbp */ 178 15 * 8, /* %rsp */ 179 4 * 8, /* %r8 .. */ 180 5 * 8, 181 6 * 8, 182 7 * 8, 183 8 * 8, 184 9 * 8, 185 10 * 8, 186 11 * 8, /* ... %r15 */ 187 16 * 8, /* %rip */ 188 17 * 8, /* %eflags */ 189 18 * 8, /* %cs */ 190 19 * 8, /* %ss */ 191 20 * 8, /* %ds */ 192 21 * 8, /* %es */ 193 22 * 8, /* %fs */ 194 23 * 8 /* %gs */ 195 }; 196 197 /* From <machine/signal.h>. */ 198 static int amd64obsd_sc_reg_offset[] = 199 { 200 14 * 8, /* %rax */ 201 13 * 8, /* %rbx */ 202 3 * 8, /* %rcx */ 203 2 * 8, /* %rdx */ 204 1 * 8, /* %rsi */ 205 0 * 8, /* %rdi */ 206 12 * 8, /* %rbp */ 207 24 * 8, /* %rsp */ 208 4 * 8, /* %r8 ... */ 209 5 * 8, 210 6 * 8, 211 7 * 8, 212 8 * 8, 213 9 * 8, 214 10 * 8, 215 11 * 8, /* ... %r15 */ 216 21 * 8, /* %rip */ 217 23 * 8, /* %eflags */ 218 22 * 8, /* %cs */ 219 25 * 8, /* %ss */ 220 18 * 8, /* %ds */ 221 17 * 8, /* %es */ 222 16 * 8, /* %fs */ 223 15 * 8 /* %gs */ 224 }; 225 226 /* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c. */ 227 static int amd64obsd_uthread_reg_offset[] = 228 { 229 19 * 8, /* %rax */ 230 16 * 8, /* %rbx */ 231 18 * 8, /* %rcx */ 232 17 * 8, /* %rdx */ 233 14 * 8, /* %rsi */ 234 13 * 8, /* %rdi */ 235 15 * 8, /* %rbp */ 236 -1, /* %rsp */ 237 12 * 8, /* %r8 ... */ 238 11 * 8, 239 10 * 8, 240 9 * 8, 241 8 * 8, 242 7 * 8, 243 6 * 8, 244 5 * 8, /* ... %r15 */ 245 20 * 8, /* %rip */ 246 4 * 8, /* %eflags */ 247 21 * 8, /* %cs */ 248 -1, /* %ss */ 249 3 * 8, /* %ds */ 250 2 * 8, /* %es */ 251 1 * 8, /* %fs */ 252 0 * 8 /* %gs */ 253 }; 254 255 /* Offset within the thread structure where we can find the saved 256 stack pointer (%esp). */ 257 #define AMD64OBSD_UTHREAD_RSP_OFFSET 400 258 259 static void 260 amd64obsd_supply_uthread (struct regcache *regcache, 261 int regnum, CORE_ADDR addr, 262 int ctx_offset) 263 { 264 CORE_ADDR sp_addr = addr + ctx_offset; 265 CORE_ADDR sp = 0; 266 char buf[8]; 267 int i; 268 269 gdb_assert (regnum >= -1); 270 271 /* if ctx_offset is 0 use old fixed offset */ 272 if (ctx_offset == 0) 273 sp_addr += AMD64OBSD_UTHREAD_RSP_OFFSET; 274 275 if (regnum == -1 || regnum == AMD64_RSP_REGNUM) 276 { 277 int offset; 278 279 /* Fetch stack pointer from thread structure. */ 280 sp = read_memory_unsigned_integer (sp_addr, 8); 281 282 /* Adjust the stack pointer such that it looks as if we just 283 returned from _thread_machdep_switch. */ 284 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8; 285 store_unsigned_integer (buf, 8, sp + offset); 286 regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf); 287 } 288 289 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++) 290 { 291 if (amd64obsd_uthread_reg_offset[i] != -1 292 && (regnum == -1 || regnum == i)) 293 { 294 /* Fetch stack pointer from thread structure (if we didn't 295 do so already). */ 296 if (sp == 0) 297 sp = read_memory_unsigned_integer (sp_addr, 8); 298 299 /* Read the saved register from the stack frame. */ 300 read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8); 301 regcache_raw_supply (regcache, i, buf); 302 } 303 } 304 } 305 306 static void 307 amd64obsd_collect_uthread (const struct regcache *regcache, 308 int regnum, CORE_ADDR addr, 309 int ctx_offset) 310 { 311 CORE_ADDR sp_addr = addr + ctx_offset; 312 CORE_ADDR sp = 0; 313 char buf[8]; 314 int i; 315 316 gdb_assert (regnum >= -1); 317 318 /* if ctx_offset is 0 use old fixed offset */ 319 if (ctx_offset == 0) 320 sp_addr += AMD64OBSD_UTHREAD_RSP_OFFSET; 321 322 if (regnum == -1 || regnum == AMD64_RSP_REGNUM) 323 { 324 int offset; 325 326 /* Calculate the stack pointer (frame pointer) that will be 327 stored into the thread structure. */ 328 offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8; 329 regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf); 330 sp = extract_unsigned_integer (buf, 8) - offset; 331 332 /* Store the stack pointer. */ 333 write_memory_unsigned_integer (sp_addr, 8, sp); 334 335 /* The stack pointer was (potentially) modified. Make sure we 336 build a proper stack frame. */ 337 regnum = -1; 338 } 339 340 for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++) 341 { 342 if (amd64obsd_uthread_reg_offset[i] != -1 343 && (regnum == -1 || regnum == i)) 344 { 345 /* Fetch stack pointer from thread structure (if we didn't 346 calculate it already). */ 347 if (sp == 0) 348 sp = read_memory_unsigned_integer (sp_addr, 8); 349 350 /* Write the register into the stack frame. */ 351 regcache_raw_collect (regcache, i, buf); 352 write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8); 353 } 354 } 355 } 356 357 358 /* Kernel debugging support. */ 359 360 /* From <machine/frame.h> */ 361 static int amd64obsd_tf_reg_offset[] = 362 { 363 14 * 8, /* %rax */ 364 13 * 8, /* %rbx */ 365 3 * 8, /* %rcx */ 366 2 * 8, /* %rdx */ 367 1 * 8, /* %rsi */ 368 0 * 8, /* %rdi */ 369 16 * 8, /* %rbp */ 370 20 * 8, /* %rsp */ 371 4 * 8, /* %r8 ... */ 372 5 * 8, 373 6 * 8, 374 7 * 8, 375 8 * 8, 376 9 * 8, 377 10 * 8, 378 11 * 8, /* ... %r15 */ 379 17 * 8, /* %rip */ 380 19 * 8, /* %rflags */ 381 18 * 8, /* %cs */ 382 21 * 8, /* %ss */ 383 }; 384 385 static int amd64obsd_fromspllower_reg_offset[] = 386 { 387 -1, /* %rax */ 388 2 * 8, /* %rbx */ 389 -1, /* %rcx */ 390 -1, /* %rdx */ 391 -1, /* %rsi */ 392 -1, /* %rdi */ 393 -1, /* %rbp */ 394 -1, /* %rsp */ 395 -1, /* %r8 ... */ 396 -1, 397 -1, 398 0 * 8, 399 -1, 400 1 * 8, 401 -1, 402 -1, /* ... %r15 */ 403 3 * 8, /* %rip */ 404 -1, /* %rflags */ 405 -1, /* %cs */ 406 -1, /* %ss */ 407 }; 408 409 /* from trad-frame.c */ 410 struct trad_frame_cache 411 { 412 struct frame_info *next_frame; 413 CORE_ADDR this_base; 414 struct trad_frame_saved_reg *prev_regs; 415 struct frame_id this_id; 416 }; 417 418 static struct trad_frame_cache * 419 amd64obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache) 420 { 421 struct trad_frame_cache *cache; 422 CORE_ADDR func, sp, addr, trapcheck; 423 ULONGEST cs; 424 int i; 425 char *name = NULL; 426 427 if (*this_cache) 428 return *this_cache; 429 430 cache = trad_frame_cache_zalloc (next_frame); 431 *this_cache = cache; 432 433 func = frame_func_unwind (next_frame); 434 sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM); 435 addr = sp; 436 437 /* adhoc check: from trap/intr? or from spllower()? */ 438 /* Xspllower() pushes %rbx, %r13, %r11. 439 so, if *(sp+(8*3)) == spllower(), 440 this frame may not be trapframe, but a frame created by Xspllower(). */ 441 trapcheck = read_memory_unsigned_integer (sp+(8*3), 8); 442 find_pc_partial_function (trapcheck, &name, NULL, NULL); 443 444 if (name != NULL && (strcmp (name, "spllower") == 0)) { 445 /* from spllower(). */ 446 447 for (i = 0; i < ARRAY_SIZE (amd64obsd_fromspllower_reg_offset); i++) 448 if (amd64obsd_fromspllower_reg_offset[i] != -1) 449 trad_frame_set_reg_addr (cache, i, addr + amd64obsd_fromspllower_reg_offset[i]); 450 451 /* skip rbx,r13,r11(pushed by Xspllower()), rip(pushd by spllower()). */ 452 trad_frame_set_value (cache->prev_regs, AMD64_RSP_REGNUM, addr+(8*4)); 453 454 /* Construct the frame ID using the function start. */ 455 trad_frame_set_id (cache, frame_id_build (sp + (8*4), func)); 456 457 } else { 458 /* from trap/intr. */ 459 460 for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++) 461 if (amd64obsd_tf_reg_offset[i] != -1) 462 trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]); 463 464 /* Read %cs from trap frame. */ 465 addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM]; 466 cs = read_memory_unsigned_integer (addr, 8); 467 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 468 { 469 /* Trap from use space; terminate backtrace. */ 470 trad_frame_set_id (cache, null_frame_id); 471 } 472 else 473 { 474 /* Construct the frame ID using the function start. */ 475 trad_frame_set_id (cache, frame_id_build (sp + 16, func)); 476 } 477 478 } 479 480 return cache; 481 } 482 483 static void 484 amd64obsd_trapframe_this_id (struct frame_info *next_frame, 485 void **this_cache, struct frame_id *this_id) 486 { 487 struct trad_frame_cache *cache = 488 amd64obsd_trapframe_cache (next_frame, this_cache); 489 490 trad_frame_get_id (cache, this_id); 491 } 492 493 static void 494 amd64obsd_trapframe_prev_register (struct frame_info *next_frame, 495 void **this_cache, int regnum, 496 int *optimizedp, enum lval_type *lvalp, 497 CORE_ADDR *addrp, int *realnump, 498 void *valuep) 499 { 500 struct trad_frame_cache *cache = 501 amd64obsd_trapframe_cache (next_frame, this_cache); 502 503 trad_frame_get_register (cache, next_frame, regnum, 504 optimizedp, lvalp, addrp, realnump, valuep); 505 } 506 507 static int 508 amd64obsd_trapframe_sniffer (const struct frame_unwind *self, 509 struct frame_info *next_frame, 510 void **this_prologue_cache) 511 { 512 ULONGEST cs; 513 char *name; 514 515 cs = frame_unwind_register_unsigned (next_frame, AMD64_CS_REGNUM); 516 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 517 return 0; 518 519 find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL); 520 return (name && ((strcmp (name, "calltrap") == 0) 521 || (name[0] == 'X' && strncmp(name, "Xipi_", 5) != 0) 522 || (strcmp (name, "alltraps") == 0) 523 || (strcmp (name, "alltraps_kern") == 0) 524 || (strcmp (name, "alltraps_kern_meltdown") == 0) 525 || (strcmp (name, "intr_fast_exit") == 0) 526 || (strcmp (name, "intr_exit_recurse") == 0))); 527 } 528 529 static const struct frame_unwind amd64obsd_trapframe_unwind = { 530 /* FIXME: kettenis/20051219: This really is more like an interrupt 531 frame, but SIGTRAMP_FRAME would print <signal handler called>, 532 which really is not what we want here. */ 533 NORMAL_FRAME, 534 amd64obsd_trapframe_this_id, 535 amd64obsd_trapframe_prev_register, 536 NULL, 537 amd64obsd_trapframe_sniffer 538 }; 539 540 541 static void 542 amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 543 { 544 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 545 546 amd64_init_abi (info, gdbarch); 547 548 /* Initialize general-purpose register set details. */ 549 tdep->gregset_reg_offset = amd64obsd_r_reg_offset; 550 tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset); 551 tdep->sizeof_gregset = 24 * 8; 552 553 tdep->jb_pc_offset = 7 * 8; 554 555 tdep->sigtramp_p = amd64obsd_sigtramp_p; 556 tdep->sigcontext_addr = amd64obsd_sigcontext_addr; 557 tdep->sc_reg_offset = amd64obsd_sc_reg_offset; 558 tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset); 559 560 /* OpenBSD provides a user-level threads implementation. */ 561 bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread); 562 bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread); 563 564 /* OpenBSD uses SVR4-style shared libraries. */ 565 set_solib_svr4_fetch_link_map_offsets 566 (gdbarch, svr4_lp64_fetch_link_map_offsets); 567 568 /* Unwind kernel trap frames correctly. */ 569 frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind); 570 } 571 572 /* Traditional (a.out) NetBSD-style core dumps. */ 573 574 static void 575 amd64obsd_core_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 576 { 577 amd64obsd_init_abi (info, gdbarch); 578 579 set_gdbarch_regset_from_core_section 580 (gdbarch, amd64obsd_regset_from_core_section); 581 } 582 583 584 /* Provide a prototype to silence -Wmissing-prototypes. */ 585 void _initialize_amd64obsd_tdep (void); 586 587 void 588 _initialize_amd64obsd_tdep (void) 589 { 590 /* The OpenBSD/amd64 native dependent code makes this assumption. */ 591 gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS); 592 593 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 594 GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi); 595 596 /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */ 597 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 598 GDB_OSABI_NETBSD_AOUT, amd64obsd_core_init_abi); 599 } 600