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 386 static struct trad_frame_cache * 387 amd64obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache) 388 { 389 struct trad_frame_cache *cache; 390 CORE_ADDR func, sp, addr; 391 ULONGEST cs; 392 int i; 393 394 if (*this_cache) 395 return *this_cache; 396 397 cache = trad_frame_cache_zalloc (next_frame); 398 *this_cache = cache; 399 400 func = frame_func_unwind (next_frame); 401 sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM); 402 addr = sp; 403 404 for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++) 405 if (amd64obsd_tf_reg_offset[i] != -1) 406 trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]); 407 408 /* Read %cs from trap frame. */ 409 addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM]; 410 cs = read_memory_unsigned_integer (addr, 8); 411 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 412 { 413 /* Trap from use space; terminate backtrace. */ 414 trad_frame_set_id (cache, null_frame_id); 415 } 416 else 417 { 418 /* Construct the frame ID using the function start. */ 419 trad_frame_set_id (cache, frame_id_build (sp + 16, func)); 420 } 421 422 return cache; 423 } 424 425 static void 426 amd64obsd_trapframe_this_id (struct frame_info *next_frame, 427 void **this_cache, struct frame_id *this_id) 428 { 429 struct trad_frame_cache *cache = 430 amd64obsd_trapframe_cache (next_frame, this_cache); 431 432 trad_frame_get_id (cache, this_id); 433 } 434 435 static void 436 amd64obsd_trapframe_prev_register (struct frame_info *next_frame, 437 void **this_cache, int regnum, 438 int *optimizedp, enum lval_type *lvalp, 439 CORE_ADDR *addrp, int *realnump, 440 void *valuep) 441 { 442 struct trad_frame_cache *cache = 443 amd64obsd_trapframe_cache (next_frame, this_cache); 444 445 trad_frame_get_register (cache, next_frame, regnum, 446 optimizedp, lvalp, addrp, realnump, valuep); 447 } 448 449 static int 450 amd64obsd_trapframe_sniffer (const struct frame_unwind *self, 451 struct frame_info *next_frame, 452 void **this_prologue_cache) 453 { 454 ULONGEST cs; 455 char *name; 456 457 cs = frame_unwind_register_unsigned (next_frame, AMD64_CS_REGNUM); 458 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 459 return 0; 460 461 find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL); 462 return (name && ((strcmp (name, "calltrap") == 0) 463 || (name[0] == 'X' && strncmp(name, "Xipi_", 5) != 0) 464 || (strcmp (name, "alltraps") == 0) 465 || (strcmp (name, "alltraps_kern") == 0) 466 || (strcmp (name, "alltraps_kern_meltdown") == 0) 467 || (strcmp (name, "intr_fast_exit") == 0) 468 || (strcmp (name, "intr_exit_recurse") == 0))); 469 } 470 471 static const struct frame_unwind amd64obsd_trapframe_unwind = { 472 /* FIXME: kettenis/20051219: This really is more like an interrupt 473 frame, but SIGTRAMP_FRAME would print <signal handler called>, 474 which really is not what we want here. */ 475 NORMAL_FRAME, 476 amd64obsd_trapframe_this_id, 477 amd64obsd_trapframe_prev_register, 478 NULL, 479 amd64obsd_trapframe_sniffer 480 }; 481 482 483 static void 484 amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 485 { 486 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 487 488 amd64_init_abi (info, gdbarch); 489 490 /* Initialize general-purpose register set details. */ 491 tdep->gregset_reg_offset = amd64obsd_r_reg_offset; 492 tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset); 493 tdep->sizeof_gregset = 24 * 8; 494 495 tdep->jb_pc_offset = 7 * 8; 496 497 tdep->sigtramp_p = amd64obsd_sigtramp_p; 498 tdep->sigcontext_addr = amd64obsd_sigcontext_addr; 499 tdep->sc_reg_offset = amd64obsd_sc_reg_offset; 500 tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset); 501 502 /* OpenBSD provides a user-level threads implementation. */ 503 bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread); 504 bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread); 505 506 /* OpenBSD uses SVR4-style shared libraries. */ 507 set_solib_svr4_fetch_link_map_offsets 508 (gdbarch, svr4_lp64_fetch_link_map_offsets); 509 510 /* Unwind kernel trap frames correctly. */ 511 frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind); 512 } 513 514 /* Traditional (a.out) NetBSD-style core dumps. */ 515 516 static void 517 amd64obsd_core_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 518 { 519 amd64obsd_init_abi (info, gdbarch); 520 521 set_gdbarch_regset_from_core_section 522 (gdbarch, amd64obsd_regset_from_core_section); 523 } 524 525 526 /* Provide a prototype to silence -Wmissing-prototypes. */ 527 void _initialize_amd64obsd_tdep (void); 528 529 void 530 _initialize_amd64obsd_tdep (void) 531 { 532 /* The OpenBSD/amd64 native dependent code makes this assumption. */ 533 gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS); 534 535 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 536 GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi); 537 538 /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */ 539 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 540 GDB_OSABI_NETBSD_AOUT, amd64obsd_core_init_abi); 541 } 542