1 /* Native-dependent code for FreeBSD/i386. 2 3 Copyright (C) 2001-2024 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 "inferior.h" 21 #include "regcache.h" 22 #include "target.h" 23 24 #include <sys/types.h> 25 #include <sys/ptrace.h> 26 #include <sys/sysctl.h> 27 #include <sys/user.h> 28 29 #include "i386-tdep.h" 30 #include "i386-fbsd-tdep.h" 31 #include "i387-tdep.h" 32 #include "x86-nat.h" 33 #include "x86-fbsd-nat.h" 34 35 class i386_fbsd_nat_target final : public x86_fbsd_nat_target 36 { 37 public: 38 void fetch_registers (struct regcache *, int) override; 39 void store_registers (struct regcache *, int) override; 40 41 const struct target_desc *read_description () override; 42 43 void resume (ptid_t, int, enum gdb_signal) override; 44 }; 45 46 static i386_fbsd_nat_target the_i386_fbsd_nat_target; 47 48 static int have_ptrace_xmmregs; 49 50 /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this 51 for all registers. */ 52 53 void 54 i386_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum) 55 { 56 struct gdbarch *gdbarch = regcache->arch (); 57 pid_t pid = get_ptrace_pid (regcache->ptid ()); 58 59 if (fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS, 60 &i386_fbsd_gregset)) 61 { 62 if (regnum != -1) 63 return; 64 } 65 66 #ifdef PT_GETFSBASE 67 if (regnum == -1 || regnum == I386_FSBASE_REGNUM) 68 { 69 register_t base; 70 71 if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 72 perror_with_name (_("Couldn't get segment register fs_base")); 73 74 regcache->raw_supply (I386_FSBASE_REGNUM, &base); 75 if (regnum != -1) 76 return; 77 } 78 #endif 79 #ifdef PT_GETGSBASE 80 if (regnum == -1 || regnum == I386_GSBASE_REGNUM) 81 { 82 register_t base; 83 84 if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 85 perror_with_name (_("Couldn't get segment register gs_base")); 86 87 regcache->raw_supply (I386_GSBASE_REGNUM, &base); 88 if (regnum != -1) 89 return; 90 } 91 #endif 92 93 /* There is no i386_fxsave_supplies or i386_xsave_supplies. 94 Instead, the earlier register sets return early if the request 95 was for a specific register that was already satisified to avoid 96 fetching the FPU/XSAVE state unnecessarily. */ 97 98 #ifdef PT_GETXSTATE_INFO 99 if (m_xsave_info.xsave_len != 0) 100 { 101 void *xstateregs = alloca (m_xsave_info.xsave_len); 102 103 if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) 104 perror_with_name (_("Couldn't get extended state status")); 105 106 i387_supply_xsave (regcache, regnum, xstateregs); 107 return; 108 } 109 #endif 110 if (have_ptrace_xmmregs != 0) 111 { 112 char xmmregs[I387_SIZEOF_FXSAVE]; 113 114 if (ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) 115 perror_with_name (_("Couldn't get XMM registers")); 116 117 i387_supply_fxsave (regcache, regnum, xmmregs); 118 return; 119 } 120 121 struct fpreg fpregs; 122 123 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 124 perror_with_name (_("Couldn't get floating point status")); 125 126 i387_supply_fsave (regcache, regnum, &fpregs); 127 } 128 129 /* Store register REGNUM back into the inferior. If REGNUM is -1, do 130 this for all registers. */ 131 132 void 133 i386_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum) 134 { 135 struct gdbarch *gdbarch = regcache->arch (); 136 pid_t pid = get_ptrace_pid (regcache->ptid ()); 137 138 if (store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS, 139 &i386_fbsd_gregset)) 140 { 141 if (regnum != -1) 142 return; 143 } 144 145 #ifdef PT_SETFSBASE 146 if (regnum == -1 || regnum == I386_FSBASE_REGNUM) 147 { 148 register_t base; 149 150 regcache->raw_collect (I386_FSBASE_REGNUM, &base); 151 152 if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 153 perror_with_name (_("Couldn't write segment register fs_base")); 154 if (regnum != -1) 155 return; 156 } 157 #endif 158 #ifdef PT_SETGSBASE 159 if (regnum == -1 || regnum == I386_GSBASE_REGNUM) 160 { 161 register_t base; 162 163 regcache->raw_collect (I386_GSBASE_REGNUM, &base); 164 165 if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1) 166 perror_with_name (_("Couldn't write segment register gs_base")); 167 if (regnum != -1) 168 return; 169 } 170 #endif 171 172 /* There is no i386_fxsave_supplies or i386_xsave_supplies. 173 Instead, the earlier register sets return early if the request 174 was for a specific register that was already satisified to avoid 175 fetching the FPU/XSAVE state unnecessarily. */ 176 177 #ifdef PT_GETXSTATE_INFO 178 if (m_xsave_info.xsave_len != 0) 179 { 180 void *xstateregs = alloca (m_xsave_info.xsave_len); 181 182 if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1) 183 perror_with_name (_("Couldn't get extended state status")); 184 185 i387_collect_xsave (regcache, regnum, xstateregs, 0); 186 187 if (ptrace (PT_SETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 188 m_xsave_info.xsave_len) == -1) 189 perror_with_name (_("Couldn't write extended state status")); 190 return; 191 } 192 #endif 193 if (have_ptrace_xmmregs != 0) 194 { 195 char xmmregs[I387_SIZEOF_FXSAVE]; 196 197 if (ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) 198 perror_with_name (_("Couldn't get XMM registers")); 199 200 i387_collect_fxsave (regcache, regnum, xmmregs); 201 202 if (ptrace (PT_SETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) 203 perror_with_name (_("Couldn't write XMM registers")); 204 return; 205 } 206 207 struct fpreg fpregs; 208 209 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 210 perror_with_name (_("Couldn't get floating point status")); 211 212 i387_collect_fsave (regcache, regnum, &fpregs); 213 214 if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 215 perror_with_name (_("Couldn't write floating point status")); 216 } 217 218 /* Resume execution of the inferior process. If STEP is nonzero, 219 single-step it. If SIGNAL is nonzero, give it that signal. */ 220 221 void 222 i386_fbsd_nat_target::resume (ptid_t ptid, int step, enum gdb_signal signal) 223 { 224 pid_t pid = ptid.pid (); 225 int request = PT_STEP; 226 227 if (pid == -1) 228 /* Resume all threads. This only gets used in the non-threaded 229 case, where "resume all threads" and "resume inferior_ptid" are 230 the same. */ 231 pid = inferior_ptid.pid (); 232 233 if (!step) 234 { 235 regcache *regcache = get_thread_regcache (inferior_thread ()); 236 ULONGEST eflags; 237 238 /* Workaround for a bug in FreeBSD. Make sure that the trace 239 flag is off when doing a continue. There is a code path 240 through the kernel which leaves the flag set when it should 241 have been cleared. If a process has a signal pending (such 242 as SIGALRM) and we do a PT_STEP, the process never really has 243 a chance to run because the kernel needs to notify the 244 debugger that a signal is being sent. Therefore, the process 245 never goes through the kernel's trap() function which would 246 normally clear it. */ 247 248 regcache_cooked_read_unsigned (regcache, I386_EFLAGS_REGNUM, 249 &eflags); 250 if (eflags & 0x0100) 251 regcache_cooked_write_unsigned (regcache, I386_EFLAGS_REGNUM, 252 eflags & ~0x0100); 253 254 request = PT_CONTINUE; 255 } 256 257 /* An addres of (caddr_t) 1 tells ptrace to continue from where it 258 was. (If GDB wanted it to start some other way, we have already 259 written a new PC value to the child.) */ 260 if (ptrace (request, pid, (caddr_t) 1, 261 gdb_signal_to_host (signal)) == -1) 262 perror_with_name (("ptrace")); 263 } 264 265 266 /* Support for debugging kernel virtual memory images. */ 267 268 #include <machine/pcb.h> 269 270 #include "bsd-kvm.h" 271 272 static int 273 i386fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) 274 { 275 /* The following is true for FreeBSD 4.7: 276 277 The pcb contains %eip, %ebx, %esp, %ebp, %esi, %edi and %gs. 278 This accounts for all callee-saved registers specified by the 279 psABI and then some. Here %esp contains the stack pointer at the 280 point just after the call to cpu_switch(). From this information 281 we reconstruct the register state as it would look when we just 282 returned from cpu_switch(). */ 283 284 /* The stack pointer shouldn't be zero. */ 285 if (pcb->pcb_esp == 0) 286 return 0; 287 288 pcb->pcb_esp += 4; 289 regcache->raw_supply (I386_EDI_REGNUM, &pcb->pcb_edi); 290 regcache->raw_supply (I386_ESI_REGNUM, &pcb->pcb_esi); 291 regcache->raw_supply (I386_EBP_REGNUM, &pcb->pcb_ebp); 292 regcache->raw_supply (I386_ESP_REGNUM, &pcb->pcb_esp); 293 regcache->raw_supply (I386_EBX_REGNUM, &pcb->pcb_ebx); 294 regcache->raw_supply (I386_EIP_REGNUM, &pcb->pcb_eip); 295 regcache->raw_supply (I386_GS_REGNUM, &pcb->pcb_gs); 296 297 return 1; 298 } 299 300 301 /* Implement the read_description method. */ 302 303 const struct target_desc * 304 i386_fbsd_nat_target::read_description () 305 { 306 static int xmm_probed; 307 308 if (inferior_ptid == null_ptid) 309 return this->beneath ()->read_description (); 310 311 #ifdef PT_GETXSTATE_INFO 312 probe_xsave_layout (inferior_ptid.pid ()); 313 if (m_xsave_info.xsave_len != 0) 314 return i386_target_description (m_xsave_info.xsave_mask, true); 315 #endif 316 317 if (!xmm_probed) 318 { 319 char xmmregs[I387_SIZEOF_FXSAVE]; 320 321 if (ptrace (PT_GETXMMREGS, inferior_ptid.pid (), 322 (PTRACE_TYPE_ARG3) xmmregs, 0) == 0) 323 have_ptrace_xmmregs = 1; 324 xmm_probed = 1; 325 } 326 327 if (have_ptrace_xmmregs) 328 return i386_target_description (X86_XSTATE_SSE_MASK, true); 329 330 return i386_target_description (X86_XSTATE_X87_MASK, true); 331 } 332 333 void _initialize_i386fbsd_nat (); 334 void 335 _initialize_i386fbsd_nat () 336 { 337 add_inf_child_target (&the_i386_fbsd_nat_target); 338 339 /* Support debugging kernel virtual memory images. */ 340 bsd_kvm_add_target (i386fbsd_supply_pcb); 341 } 342