1/* Target-dependent code for OpenBSD/amd64. 2 3 Copyright 2003, 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 "frame.h" 24#include "gdbcore.h" 25#include "symtab.h" 26#include "objfiles.h" 27#include "osabi.h" 28#include "regset.h" 29#include "target.h" 30 31#include "gdb_assert.h" 32#include "gdb_string.h" 33 34#include "amd64-tdep.h" 35#include "i387-tdep.h" 36#include "solib-svr4.h" 37 38/* Support for core dumps. */ 39 40static void 41amd64obsd_supply_regset (const struct regset *regset, 42 struct regcache *regcache, int regnum, 43 const void *regs, size_t len) 44{ 45 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); 46 47 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE); 48 49 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset); 50 amd64_supply_fxsave (regcache, regnum, (char *)regs + tdep->sizeof_gregset); 51} 52 53static const struct regset * 54amd64obsd_regset_from_core_section (struct gdbarch *gdbarch, 55 const char *sect_name, size_t sect_size) 56{ 57 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 58 59 /* OpenBSD core dumps don't use seperate register sets for the 60 general-purpose and floating-point registers. */ 61 62 if (strcmp (sect_name, ".reg") == 0 63 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE) 64 { 65 if (tdep->gregset == NULL) 66 tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL); 67 return tdep->gregset; 68 } 69 70 return NULL; 71} 72 73 74/* Support for signal handlers. */ 75 76/* Default page size. */ 77static const int amd64obsd_page_size = 4096; 78 79/* Return whether the frame preceding NEXT_FRAME corresponds to an 80 OpenBSD sigtramp routine. */ 81 82static int 83amd64obsd_sigtramp_p (struct frame_info *next_frame) 84{ 85 CORE_ADDR pc = frame_pc_unwind (next_frame); 86 CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1)); 87 const char sigreturn[] = 88 { 89 0x48, 0xc7, 0xc0, 90 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ 91 0xcd, 0x80 /* int $0x80 */ 92 }; 93 size_t buflen = (sizeof sigreturn) + 1; 94 char *name, *buf; 95 96 /* If the function has a valid symbol name, it isn't a 97 trampoline. */ 98 find_pc_partial_function (pc, &name, NULL, NULL); 99 if (name != NULL) 100 return 0; 101 102 /* If the function lives in a valid section (even without a starting 103 point) it isn't a trampoline. */ 104 if (find_pc_section (pc) != NULL) 105 return 0; 106 107 /* If we can't read the instructions at START_PC, return zero. */ 108 buf = alloca ((sizeof sigreturn) + 1); 109 if (!safe_frame_unwind_memory (next_frame, start_pc + 6, buf, buflen)) 110 return 0; 111 112 /* Check for sigreturn(2). Depending on how the assembler encoded 113 the `movq %rsp, %rdi' instruction, the code starts at offset 6 or 114 7. */ 115 if (memcmp (buf, sigreturn, sizeof sigreturn) 116 && memcpy (buf + 1, sigreturn, sizeof sigreturn)) 117 return 0; 118 119 return 1; 120} 121 122/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp 123 routine, return the address of the associated sigcontext structure. */ 124 125static CORE_ADDR 126amd64obsd_sigcontext_addr (struct frame_info *next_frame) 127{ 128 CORE_ADDR pc = frame_pc_unwind (next_frame); 129 ULONGEST offset = (pc & (amd64obsd_page_size - 1)); 130 131 /* The %rsp register points at `struct sigcontext' upon entry of a 132 signal trampoline. The relevant part of the trampoline is 133 134 call *%rax 135 movq %rsp, %rdi 136 pushq %rdi 137 movq $SYS_sigreturn,%rax 138 int $0x80 139 140 (see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq' 141 instruction clobbers %rsp, but its value is saved in `%rdi'. */ 142 143 if (offset > 5) 144 return frame_unwind_register_unsigned (next_frame, AMD64_RDI_REGNUM); 145 else 146 return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM); 147} 148 149/* OpenBSD 3.5 or later. */ 150 151/* Mapping between the general-purpose registers in `struct reg' 152 format and GDB's register cache layout. */ 153 154/* From <machine/reg.h>. */ 155int amd64obsd_r_reg_offset[] = 156{ 157 14 * 8, /* %rax */ 158 13 * 8, /* %rbx */ 159 3 * 8, /* %rcx */ 160 2 * 8, /* %rdx */ 161 1 * 8, /* %rsi */ 162 0 * 8, /* %rdi */ 163 12 * 8, /* %rbp */ 164 15 * 8, /* %rsp */ 165 4 * 8, /* %r8 .. */ 166 5 * 8, 167 6 * 8, 168 7 * 8, 169 8 * 8, 170 9 * 8, 171 10 * 8, 172 11 * 8, /* ... %r15 */ 173 16 * 8, /* %rip */ 174 17 * 8, /* %eflags */ 175 18 * 8, /* %cs */ 176 19 * 8, /* %ss */ 177 20 * 8, /* %ds */ 178 21 * 8, /* %es */ 179 22 * 8, /* %fs */ 180 23 * 8 /* %gs */ 181}; 182 183/* From <machine/signal.h>. */ 184static int amd64obsd_sc_reg_offset[] = 185{ 186 14 * 8, /* %rax */ 187 13 * 8, /* %rbx */ 188 3 * 8, /* %rcx */ 189 2 * 8, /* %rdx */ 190 1 * 8, /* %rsi */ 191 0 * 8, /* %rdi */ 192 12 * 8, /* %rbp */ 193 24 * 8, /* %rsp */ 194 4 * 8, /* %r8 ... */ 195 5 * 8, 196 6 * 8, 197 7 * 8, 198 8 * 8, 199 9 * 8, 200 10 * 8, 201 11 * 8, /* ... %r15 */ 202 21 * 8, /* %rip */ 203 23 * 8, /* %eflags */ 204 22 * 8, /* %cs */ 205 25 * 8, /* %ss */ 206 18 * 8, /* %ds */ 207 17 * 8, /* %es */ 208 16 * 8, /* %fs */ 209 15 * 8 /* %gs */ 210}; 211 212static void 213amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 214{ 215 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 216 217 amd64_init_abi (info, gdbarch); 218 219 /* Initialize general-purpose register set details. */ 220 tdep->gregset_reg_offset = amd64obsd_r_reg_offset; 221 tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset); 222 tdep->sizeof_gregset = 24 * 8; 223 224 set_gdbarch_regset_from_core_section (gdbarch, 225 amd64obsd_regset_from_core_section); 226 227 tdep->jb_pc_offset = 7 * 8; 228 229 tdep->sigtramp_p = amd64obsd_sigtramp_p; 230 tdep->sigcontext_addr = amd64obsd_sigcontext_addr; 231 tdep->sc_reg_offset = amd64obsd_sc_reg_offset; 232 tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset); 233 234 /* OpenBSD uses SVR4-style shared libraries. */ 235 set_solib_svr4_fetch_link_map_offsets 236 (gdbarch, svr4_lp64_fetch_link_map_offsets); 237} 238 239 240/* Provide a prototype to silence -Wmissing-prototypes. */ 241void _initialize_amd64obsd_tdep (void); 242 243void 244_initialize_amd64obsd_tdep (void) 245{ 246 /* The OpenBSD/amd64 native dependent code makes this assumption. */ 247 gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS); 248 249 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 250 GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi); 251 252 /* OpenBSD uses traditional (a.out) NetBSD-style core dumps. */ 253 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 254 GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi); 255} 256