1 /* Native-dependent code for DragonFly/amd64. 2 3 Copyright (C) 2003-2013 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 3 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, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "inferior.h" 22 #include "regcache.h" 23 #include "target.h" 24 #include "gregset.h" 25 26 #include "gdb_assert.h" 27 #include <signal.h> 28 #include <stddef.h> 29 #include <sys/types.h> 30 #include <sys/procfs.h> 31 #include <sys/ptrace.h> 32 #include <sys/sysctl.h> 33 #include <machine/reg.h> 34 35 #include "fbsd-nat.h" 36 #include "amd64-tdep.h" 37 #include "amd64-nat.h" 38 #include "amd64bsd-nat.h" 39 #include "i386-nat.h" 40 41 /* Offset in `struct reg' where MEMBER is stored. */ 42 #define REG_OFFSET(member) offsetof (struct reg, member) 43 44 /* At amd64dfly64_r_reg_offset[REGNUM] you'll find the offset in 45 `struct reg' location where the GDB register REGNUM is stored. 46 Unsupported registers are marked with `-1'. */ 47 static int amd64dfly64_r_reg_offset[] = 48 { 49 REG_OFFSET(r_rax), 50 REG_OFFSET(r_rbx), 51 REG_OFFSET(r_rcx), 52 REG_OFFSET(r_rdx), 53 REG_OFFSET(r_rsi), 54 REG_OFFSET(r_rdi), 55 REG_OFFSET(r_rbp), 56 REG_OFFSET(r_rsp), 57 REG_OFFSET(r_r8), 58 REG_OFFSET(r_r9), 59 REG_OFFSET(r_r10), 60 REG_OFFSET(r_r11), 61 REG_OFFSET(r_r12), 62 REG_OFFSET(r_r13), 63 REG_OFFSET(r_r14), 64 REG_OFFSET(r_r15), 65 REG_OFFSET(r_rip), 66 REG_OFFSET(r_rflags), 67 REG_OFFSET(r_cs), 68 REG_OFFSET(r_ss), 69 -1, 70 -1, 71 -1, 72 -1 73 }; 74 75 /* Mapping between the general-purpose registers in DragonFly/amd64 76 `struct reg' format and GDB's register cache layout for 77 DragonFly/i386. 78 79 Note that most DragonFly/amd64 registers are 64-bit, while the 80 DragonFly/i386 registers are all 32-bit, but since we're 81 little-endian we get away with that. */ 82 83 /* From <machine/reg.h>. */ 84 static int amd64dfly32_r_reg_offset[I386_NUM_GREGS] = 85 { 86 14 * 8, 13 * 8, /* %eax, %ecx */ 87 12 * 8, 11 * 8, /* %edx, %ebx */ 88 20 * 8, 10 * 8, /* %esp, %ebp */ 89 9 * 8, 8 * 8, /* %esi, %edi */ 90 17 * 8, 19 * 8, /* %eip, %eflags */ 91 18 * 8, 21 * 8, /* %cs, %ss */ 92 -1, -1, -1, -1 /* %ds, %es, %fs, %gs */ 93 }; 94 95 #ifdef DFLY_PCB_SUPPLY 96 /* Transfering the registers between GDB, inferiors and core files. */ 97 98 /* Fill GDB's register array with the general-purpose register values 99 in *GREGSETP. */ 100 101 void 102 supply_gregset(struct regcache *regcache, const gregset_t * gregsetp) 103 { 104 amd64_supply_native_gregset(regcache, gregsetp, -1); 105 } 106 107 /* Fill register REGNUM (if it is a general-purpose register) in 108 *GREGSETPS with the value in GDB's register array. If REGNUM is -1, 109 do this for all registers. */ 110 111 void 112 fill_gregset(const struct regcache *regcache, gdb_gregset_t * gregsetp, int regnum) 113 { 114 amd64_collect_native_gregset(regcache, gregsetp, regnum); 115 } 116 117 /* Fill GDB's register array with the floating-point register values 118 in *FPREGSETP. */ 119 120 void 121 supply_fpregset(struct regcache *regcache, const fpregset_t * fpregsetp) 122 { 123 amd64_supply_fxsave(regcache, -1, fpregsetp); 124 } 125 126 /* Fill register REGNUM (if it is a floating-point register) in 127 *FPREGSETP with the value in GDB's register array. If REGNUM is -1, 128 do this for all registers. */ 129 130 void 131 fill_fpregset(const struct regcache *regcache, gdb_fpregset_t * fpregsetp, int regnum) 132 { 133 amd64_collect_fxsave(regcache, regnum, fpregsetp); 134 } 135 136 /* Support for debugging kernel virtual memory images. */ 137 138 #include <sys/types.h> 139 #include <machine/pcb.h> 140 #include <osreldate.h> 141 142 #include "bsd-kvm.h" 143 144 static int 145 amd64dfly_supply_pcb(struct regcache *regcache, struct pcb *pcb) 146 { 147 /* The following is true for FreeBSD 5.2: 148 * 149 * The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15, %ds, 150 * %es, %fs and %gs. This accounts for all callee-saved registers 151 * specified by the psABI and then some. Here %esp contains the stack 152 * pointer at the point just after the call to cpu_switch(). From 153 * this information we reconstruct the register state as it would like 154 * when we just returned from cpu_switch(). */ 155 156 /* The stack pointer shouldn't be zero. */ 157 if (pcb->pcb_rsp == 0) 158 return 0; 159 160 pcb->pcb_rsp += 8; 161 regcache_raw_supply(regcache, AMD64_RIP_REGNUM, &pcb->pcb_rip); 162 regcache_raw_supply(regcache, AMD64_RBX_REGNUM, &pcb->pcb_rbx); 163 regcache_raw_supply(regcache, AMD64_RSP_REGNUM, &pcb->pcb_rsp); 164 regcache_raw_supply(regcache, AMD64_RBP_REGNUM, &pcb->pcb_rbp); 165 regcache_raw_supply(regcache, 12, &pcb->pcb_r12); 166 regcache_raw_supply(regcache, 13, &pcb->pcb_r13); 167 regcache_raw_supply(regcache, 14, &pcb->pcb_r14); 168 regcache_raw_supply(regcache, 15, &pcb->pcb_r15); 169 170 return 1; 171 } 172 #endif /* DFLY_PCB_SUPPLY */ 173 174 static void (*super_mourn_inferior) (struct target_ops *ops); 175 176 static void 177 amd64dfly_mourn_inferior(struct target_ops *ops) 178 { 179 #ifdef HAVE_PT_GETDBREGS 180 i386_cleanup_dregs(); 181 #endif 182 super_mourn_inferior(ops); 183 } 184 185 /* Provide a prototype to silence -Wmissing-prototypes. */ 186 void _initialize_amd64dfly_nat(void); 187 188 void 189 _initialize_amd64dfly_nat(void) 190 { 191 struct target_ops *t; 192 int offset; 193 194 amd64_native_gregset32_reg_offset = amd64dfly32_r_reg_offset; 195 amd64_native_gregset64_reg_offset = amd64dfly64_r_reg_offset; 196 197 /* Add some extra features to the common *BSD/i386 target. */ 198 t = amd64bsd_target(); 199 200 #ifdef HAVE_PT_GETDBREGS 201 202 i386_use_watchpoints(t); 203 204 i386_dr_low.set_control = amd64bsd_dr_set_control; 205 i386_dr_low.set_addr = amd64bsd_dr_set_addr; 206 i386_dr_low.get_addr = amd64bsd_dr_get_addr; 207 i386_dr_low.get_status = amd64bsd_dr_get_status; 208 i386_dr_low.get_control = amd64bsd_dr_get_control; 209 i386_set_debug_register_length(8); 210 211 #endif /* HAVE_PT_GETDBREGS */ 212 213 super_mourn_inferior = t->to_mourn_inferior; 214 t->to_mourn_inferior = amd64dfly_mourn_inferior; 215 216 t->to_pid_to_exec_file = fbsd_pid_to_exec_file; 217 t->to_find_memory_regions = fbsd_find_memory_regions; 218 t->to_make_corefile_notes = fbsd_make_corefile_notes; 219 add_target(t); 220 221 #ifdef DFLY_PCB_SUPPLY 222 /* Support debugging kernel virtual memory images. */ 223 bsd_kvm_add_target(amd64dfly_supply_pcb); 224 #endif 225 226 /* To support the recognition of signal handlers, i386bsd-tdep.c 227 * hardcodes some constants. Inclusion of this file means that we are 228 * compiling a native debugger, which means that we can use the system 229 * header files and sysctl(3) to get at the relevant information. */ 230 231 #define SC_REG_OFFSET amd64dfly_sc_reg_offset 232 233 /* We only check the program counter, stack pointer and frame pointer 234 * since these members of `struct sigcontext' are essential for 235 * providing backtraces. */ 236 237 #define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM] 238 #define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM] 239 #define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM] 240 241 /* Override the default value for the offset of the program counter in 242 * the sigcontext structure. */ 243 offset = offsetof(struct sigcontext, sc_rip); 244 245 if (SC_RIP_OFFSET != offset) { 246 warning(_("\ 247 offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\ 248 Please report this to <bug-gdb@gnu.org>."), 249 offset, SC_RIP_OFFSET); 250 } 251 SC_RIP_OFFSET = offset; 252 253 /* Likewise for the stack pointer. */ 254 offset = offsetof(struct sigcontext, sc_rsp); 255 256 if (SC_RSP_OFFSET != offset) { 257 warning(_("\ 258 offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\ 259 Please report this to <bug-gdb@gnu.org>."), 260 offset, SC_RSP_OFFSET); 261 } 262 SC_RSP_OFFSET = offset; 263 264 /* And the frame pointer. */ 265 offset = offsetof(struct sigcontext, sc_rbp); 266 267 if (SC_RBP_OFFSET != offset) { 268 warning(_("\ 269 offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\ 270 Please report this to <bug-gdb@gnu.org>."), 271 offset, SC_RBP_OFFSET); 272 } 273 SC_RBP_OFFSET = offset; 274 275 /* DragonFly provides a kern.ps_strings sysctl that we can use to 276 * locate the sigtramp. That way we can still recognize a sigtramp if 277 * its location is changed in a new kernel. Of course this is still 278 * based on the assumption that the sigtramp is placed directly under 279 * the location where the program arguments and environment can be 280 * found. */ 281 { 282 int mib[2]; 283 long ps_strings; 284 size_t len; 285 286 mib[0] = CTL_KERN; 287 mib[1] = KERN_PS_STRINGS; 288 len = sizeof(ps_strings); 289 if (sysctl(mib, 2, &ps_strings, &len, NULL, 0) == 0) { 290 amd64dfly_sigtramp_start_addr = ps_strings - 32; 291 amd64dfly_sigtramp_end_addr = ps_strings; 292 } 293 } 294 } 295