1 /* Native-dependent code for FreeBSD/amd64. 2 3 Copyright (C) 2003-2023 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 25 #include <signal.h> 26 #include <sys/types.h> 27 #include <sys/ptrace.h> 28 #include <sys/sysctl.h> 29 #include <sys/user.h> 30 #include <machine/reg.h> 31 32 #include "amd64-tdep.h" 33 #include "amd64-fbsd-tdep.h" 34 #include "amd64-nat.h" 35 #include "x86-nat.h" 36 #include "gdbsupport/x86-xstate.h" 37 #include "x86-fbsd-nat.h" 38 39 class amd64_fbsd_nat_target final : public x86_fbsd_nat_target 40 { 41 public: 42 void fetch_registers (struct regcache *, int) override; 43 void store_registers (struct regcache *, int) override; 44 45 const struct target_desc *read_description () override; 46 }; 47 48 static amd64_fbsd_nat_target the_amd64_fbsd_nat_target; 49 50 #ifdef PT_GETXSTATE_INFO 51 static size_t xsave_len; 52 #endif 53 54 /* This is a layout of the amd64 'struct reg' but with i386 55 registers. */ 56 57 static const struct regcache_map_entry amd64_fbsd32_gregmap[] = 58 { 59 { 8, REGCACHE_MAP_SKIP, 8 }, 60 { 1, I386_EDI_REGNUM, 8 }, 61 { 1, I386_ESI_REGNUM, 8 }, 62 { 1, I386_EBP_REGNUM, 8 }, 63 { 1, I386_EBX_REGNUM, 8 }, 64 { 1, I386_EDX_REGNUM, 8 }, 65 { 1, I386_ECX_REGNUM, 8 }, 66 { 1, I386_EAX_REGNUM, 8 }, 67 { 1, REGCACHE_MAP_SKIP, 4 }, /* trapno */ 68 { 1, I386_FS_REGNUM, 2 }, 69 { 1, I386_GS_REGNUM, 2 }, 70 { 1, REGCACHE_MAP_SKIP, 4 }, /* err */ 71 { 1, I386_ES_REGNUM, 2 }, 72 { 1, I386_DS_REGNUM, 2 }, 73 { 1, I386_EIP_REGNUM, 8 }, 74 { 1, I386_CS_REGNUM, 8 }, 75 { 1, I386_EFLAGS_REGNUM, 8 }, 76 { 1, I386_ESP_REGNUM, 0 }, 77 { 1, I386_SS_REGNUM, 8 }, 78 { 0 } 79 }; 80 81 static const struct regset amd64_fbsd32_gregset = 82 { 83 amd64_fbsd32_gregmap, regcache_supply_regset, regcache_collect_regset 84 }; 85 86 /* Return the regset to use for 'struct reg' for the GDBARCH. */ 87 88 static const struct regset * 89 find_gregset (struct gdbarch *gdbarch) 90 { 91 if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) 92 return &amd64_fbsd32_gregset; 93 else 94 return &amd64_fbsd_gregset; 95 } 96 97 /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this 98 for all registers. */ 99 100 void 101 amd64_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum) 102 { 103 struct gdbarch *gdbarch = regcache->arch (); 104 #if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) 105 const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); 106 #endif 107 pid_t pid = get_ptrace_pid (regcache->ptid ()); 108 const struct regset *gregset = find_gregset (gdbarch); 109 110 if (fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS, gregset)) 111 { 112 if (regnum != -1) 113 return; 114 } 115 116 #ifdef PT_GETFSBASE 117 if (regnum == -1 || regnum == tdep->fsbase_regnum) 118 { 119 register_t base; 120 121 if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 122 perror_with_name (_("Couldn't get segment register fs_base")); 123 124 regcache->raw_supply (tdep->fsbase_regnum, &base); 125 if (regnum != -1) 126 return; 127 } 128 #endif 129 #ifdef PT_GETGSBASE 130 if (regnum == -1 || regnum == tdep->fsbase_regnum + 1) 131 { 132 register_t base; 133 134 if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 135 perror_with_name (_("Couldn't get segment register gs_base")); 136 137 regcache->raw_supply (tdep->fsbase_regnum + 1, &base); 138 if (regnum != -1) 139 return; 140 } 141 #endif 142 143 /* There is no amd64_fxsave_supplies or amd64_xsave_supplies. 144 Instead, the earlier register sets return early if the request 145 was for a specific register that was already satisified to avoid 146 fetching the FPU/XSAVE state unnecessarily. */ 147 148 #ifdef PT_GETXSTATE_INFO 149 if (xsave_len != 0) 150 { 151 void *xstateregs = alloca (xsave_len); 152 153 if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) 154 perror_with_name (_("Couldn't get extended state status")); 155 156 amd64_supply_xsave (regcache, regnum, xstateregs); 157 return; 158 } 159 #endif 160 161 struct fpreg fpregs; 162 163 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 164 perror_with_name (_("Couldn't get floating point status")); 165 166 amd64_supply_fxsave (regcache, regnum, &fpregs); 167 } 168 169 /* Store register REGNUM back into the inferior. If REGNUM is -1, do 170 this for all registers. */ 171 172 void 173 amd64_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum) 174 { 175 struct gdbarch *gdbarch = regcache->arch (); 176 #if defined(PT_GETFSBASE) || defined(PT_GETGSBASE) 177 const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); 178 #endif 179 pid_t pid = get_ptrace_pid (regcache->ptid ()); 180 const struct regset *gregset = find_gregset (gdbarch); 181 182 if (store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS, 183 gregset)) 184 { 185 if (regnum != -1) 186 return; 187 } 188 189 #ifdef PT_SETFSBASE 190 if (regnum == -1 || regnum == tdep->fsbase_regnum) 191 { 192 register_t base; 193 194 /* Clear the full base value to support 32-bit targets. */ 195 base = 0; 196 regcache->raw_collect (tdep->fsbase_regnum, &base); 197 198 if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 199 perror_with_name (_("Couldn't write segment register fs_base")); 200 if (regnum != -1) 201 return; 202 } 203 #endif 204 #ifdef PT_SETGSBASE 205 if (regnum == -1 || regnum == tdep->fsbase_regnum + 1) 206 { 207 register_t base; 208 209 /* Clear the full base value to support 32-bit targets. */ 210 base = 0; 211 regcache->raw_collect (tdep->fsbase_regnum + 1, &base); 212 213 if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 214 perror_with_name (_("Couldn't write segment register gs_base")); 215 if (regnum != -1) 216 return; 217 } 218 #endif 219 220 /* There is no amd64_fxsave_supplies or amd64_xsave_supplies. 221 Instead, the earlier register sets return early if the request 222 was for a specific register that was already satisified to avoid 223 fetching the FPU/XSAVE state unnecessarily. */ 224 225 #ifdef PT_GETXSTATE_INFO 226 if (xsave_len != 0) 227 { 228 void *xstateregs = alloca (xsave_len); 229 230 if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) 231 perror_with_name (_("Couldn't get extended state status")); 232 233 amd64_collect_xsave (regcache, regnum, xstateregs, 0); 234 235 if (ptrace (PT_SETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 236 xsave_len) == -1) 237 perror_with_name (_("Couldn't write extended state status")); 238 return; 239 } 240 #endif 241 242 struct fpreg fpregs; 243 244 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 245 perror_with_name (_("Couldn't get floating point status")); 246 247 amd64_collect_fxsave (regcache, regnum, &fpregs); 248 249 if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 250 perror_with_name (_("Couldn't write floating point status")); 251 } 252 253 /* Support for debugging kernel virtual memory images. */ 254 255 #include <machine/pcb.h> 256 #include <osreldate.h> 257 258 #include "bsd-kvm.h" 259 260 static int 261 amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) 262 { 263 /* The following is true for FreeBSD 5.2: 264 265 The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15, 266 %ds, %es, %fs and %gs. This accounts for all callee-saved 267 registers specified by the psABI and then some. Here %esp 268 contains the stack pointer at the point just after the call to 269 cpu_switch(). From this information we reconstruct the register 270 state as it would like when we just returned from cpu_switch(). */ 271 272 /* The stack pointer shouldn't be zero. */ 273 if (pcb->pcb_rsp == 0) 274 return 0; 275 276 pcb->pcb_rsp += 8; 277 regcache->raw_supply (AMD64_RIP_REGNUM, &pcb->pcb_rip); 278 regcache->raw_supply (AMD64_RBX_REGNUM, &pcb->pcb_rbx); 279 regcache->raw_supply (AMD64_RSP_REGNUM, &pcb->pcb_rsp); 280 regcache->raw_supply (AMD64_RBP_REGNUM, &pcb->pcb_rbp); 281 regcache->raw_supply (12, &pcb->pcb_r12); 282 regcache->raw_supply (13, &pcb->pcb_r13); 283 regcache->raw_supply (14, &pcb->pcb_r14); 284 regcache->raw_supply (15, &pcb->pcb_r15); 285 #if (__FreeBSD_version < 800075) && (__FreeBSD_kernel_version < 800075) 286 /* struct pcb provides the pcb_ds/pcb_es/pcb_fs/pcb_gs fields only 287 up until __FreeBSD_version 800074: The removal of these fields 288 occurred on 2009-04-01 while the __FreeBSD_version number was 289 bumped to 800075 on 2009-04-06. So 800075 is the closest version 290 number where we should not try to access these fields. */ 291 regcache->raw_supply (AMD64_DS_REGNUM, &pcb->pcb_ds); 292 regcache->raw_supply (AMD64_ES_REGNUM, &pcb->pcb_es); 293 regcache->raw_supply (AMD64_FS_REGNUM, &pcb->pcb_fs); 294 regcache->raw_supply (AMD64_GS_REGNUM, &pcb->pcb_gs); 295 #endif 296 297 return 1; 298 } 299 300 301 /* Implement the read_description method. */ 302 303 const struct target_desc * 304 amd64_fbsd_nat_target::read_description () 305 { 306 #ifdef PT_GETXSTATE_INFO 307 static int xsave_probed; 308 static uint64_t xcr0; 309 #endif 310 struct reg regs; 311 int is64; 312 313 if (ptrace (PT_GETREGS, inferior_ptid.pid (), 314 (PTRACE_TYPE_ARG3) ®s, 0) == -1) 315 perror_with_name (_("Couldn't get registers")); 316 is64 = (regs.r_cs == GSEL (GUCODE_SEL, SEL_UPL)); 317 #ifdef PT_GETXSTATE_INFO 318 if (!xsave_probed) 319 { 320 struct ptrace_xstate_info info; 321 322 if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (), 323 (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0) 324 { 325 xsave_len = info.xsave_len; 326 xcr0 = info.xsave_mask; 327 } 328 xsave_probed = 1; 329 } 330 331 if (xsave_len != 0) 332 { 333 if (is64) 334 return amd64_target_description (xcr0, true); 335 else 336 return i386_target_description (xcr0, true); 337 } 338 #endif 339 if (is64) 340 return amd64_target_description (X86_XSTATE_SSE_MASK, true); 341 else 342 return i386_target_description (X86_XSTATE_SSE_MASK, true); 343 } 344 345 void _initialize_amd64fbsd_nat (); 346 void 347 _initialize_amd64fbsd_nat () 348 { 349 add_inf_child_target (&the_amd64_fbsd_nat_target); 350 351 /* Support debugging kernel virtual memory images. */ 352 bsd_kvm_add_target (amd64fbsd_supply_pcb); 353 } 354