1 /* Native-dependent code for modern i386 BSD's. 2 3 Copyright (C) 2000-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 23 #include <signal.h> 24 #include <sys/types.h> 25 #include <sys/ptrace.h> 26 #include <machine/reg.h> 27 #include <machine/frame.h> 28 29 #include "i386-tdep.h" 30 #include "i387-tdep.h" 31 #include "x86-bsd-nat.h" 32 #include "i386-bsd-nat.h" 33 #include "inf-ptrace.h" 34 35 37 static PTRACE_TYPE_RET 38 gdb_ptrace (PTRACE_TYPE_ARG1 request, ptid_t ptid, PTRACE_TYPE_ARG3 addr, 39 PTRACE_TYPE_ARG4 data) 40 { 41 #ifdef __NetBSD__ 42 gdb_assert (data == 0); 43 /* Support for NetBSD threads: unlike other ptrace implementations in this 44 file, NetBSD requires that we pass both the pid and lwp. */ 45 return ptrace (request, ptid.pid (), addr, ptid.lwp ()); 46 #else 47 pid_t pid = get_ptrace_pid (ptid); 48 return ptrace (request, pid, addr, data); 49 #endif 50 } 51 52 /* In older BSD versions we cannot get at some of the segment 53 registers. FreeBSD for example didn't support the %fs and %gs 54 registers until the 3.0 release. We have autoconf checks for their 55 presence, and deal gracefully with their absence. */ 56 57 /* Offset in `struct reg' where MEMBER is stored. */ 58 #define REG_OFFSET(member) offsetof (struct reg, member) 59 60 /* At i386bsd_reg_offset[REGNUM] you'll find the offset in `struct 61 reg' where the GDB register REGNUM is stored. Unsupported 62 registers are marked with `-1'. */ 63 static int i386bsd_r_reg_offset[] = 64 { 65 REG_OFFSET (r_eax), 66 REG_OFFSET (r_ecx), 67 REG_OFFSET (r_edx), 68 REG_OFFSET (r_ebx), 69 REG_OFFSET (r_esp), 70 REG_OFFSET (r_ebp), 71 REG_OFFSET (r_esi), 72 REG_OFFSET (r_edi), 73 REG_OFFSET (r_eip), 74 REG_OFFSET (r_eflags), 75 REG_OFFSET (r_cs), 76 REG_OFFSET (r_ss), 77 REG_OFFSET (r_ds), 78 REG_OFFSET (r_es), 79 #ifdef HAVE_STRUCT_REG_R_FS 80 REG_OFFSET (r_fs), 81 #else 82 -1, 83 #endif 84 #ifdef HAVE_STRUCT_REG_R_GS 85 REG_OFFSET (r_gs) 86 #else 87 -1 88 #endif 89 }; 90 91 /* Macro to determine if a register is fetched with PT_GETREGS. */ 92 #define GETREGS_SUPPLIES(regnum) \ 93 ((0 <= (regnum) && (regnum) <= 15)) 94 95 /* Set to 1 if the kernel supports PT_GETXMMREGS. Initialized to -1 96 so that we try PT_GETXMMREGS the first time around. */ 97 static int have_ptrace_xmmregs = -1; 98 99 101 /* Supply the general-purpose registers in GREGS, to REGCACHE. */ 102 103 static void 104 i386bsd_supply_gregset (struct regcache *regcache, const void *gregs) 105 { 106 const char *regs = (const char *) gregs; 107 int regnum; 108 109 for (regnum = 0; regnum < ARRAY_SIZE (i386bsd_r_reg_offset); regnum++) 110 { 111 int offset = i386bsd_r_reg_offset[regnum]; 112 113 if (offset != -1) 114 regcache->raw_supply (regnum, regs + offset); 115 } 116 } 117 118 /* Collect register REGNUM from REGCACHE and store its contents in 119 GREGS. If REGNUM is -1, collect and store all appropriate 120 registers. */ 121 122 static void 123 i386bsd_collect_gregset (const struct regcache *regcache, 124 void *gregs, int regnum) 125 { 126 char *regs = (char *) gregs; 127 int i; 128 129 for (i = 0; i < ARRAY_SIZE (i386bsd_r_reg_offset); i++) 130 { 131 if (regnum == -1 || regnum == i) 132 { 133 int offset = i386bsd_r_reg_offset[i]; 134 135 if (offset != -1) 136 regcache->raw_collect (i, regs + offset); 137 } 138 } 139 } 140 141 /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this 142 for all registers (including the floating point registers). */ 143 144 void 145 i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum) 146 { 147 ptid_t ptid = regcache->ptid (); 148 149 if (regnum == -1 || GETREGS_SUPPLIES (regnum)) 150 { 151 struct reg regs; 152 153 if (gdb_ptrace (PT_GETREGS, ptid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) 154 perror_with_name (_("Couldn't get registers")); 155 156 i386bsd_supply_gregset (regcache, ®s); 157 if (regnum != -1) 158 return; 159 } 160 161 if (regnum == -1 || regnum >= I386_ST0_REGNUM) 162 { 163 struct fpreg fpregs; 164 char xmmregs[512]; 165 166 if (have_ptrace_xmmregs != 0 167 && gdb_ptrace(PT_GETXMMREGS, ptid, 168 (PTRACE_TYPE_ARG3) xmmregs, 0) == 0) 169 { 170 have_ptrace_xmmregs = 1; 171 i387_supply_fxsave (regcache, -1, xmmregs); 172 } 173 else 174 { 175 have_ptrace_xmmregs = 0; 176 if (gdb_ptrace (PT_GETFPREGS, ptid, 177 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 178 perror_with_name (_("Couldn't get floating point status")); 179 180 i387_supply_fsave (regcache, -1, &fpregs); 181 } 182 } 183 } 184 185 /* Store register REGNUM back into the inferior. If REGNUM is -1, do 186 this for all registers (including the floating point registers). */ 187 188 void 189 i386bsd_store_inferior_registers (struct regcache *regcache, int regnum) 190 { 191 ptid_t ptid = regcache->ptid (); 192 193 if (regnum == -1 || GETREGS_SUPPLIES (regnum)) 194 { 195 struct reg regs; 196 197 if (gdb_ptrace (PT_GETREGS, ptid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) 198 perror_with_name (_("Couldn't get registers")); 199 200 i386bsd_collect_gregset (regcache, ®s, regnum); 201 202 if (gdb_ptrace (PT_SETREGS, ptid, (PTRACE_TYPE_ARG3) ®s, 0) == -1) 203 perror_with_name (_("Couldn't write registers")); 204 205 if (regnum != -1) 206 return; 207 } 208 209 if (regnum == -1 || regnum >= I386_ST0_REGNUM) 210 { 211 struct fpreg fpregs; 212 char xmmregs[512]; 213 214 if (have_ptrace_xmmregs != 0 215 && gdb_ptrace(PT_GETXMMREGS, ptid, 216 (PTRACE_TYPE_ARG3) xmmregs, 0) == 0) 217 { 218 have_ptrace_xmmregs = 1; 219 220 i387_collect_fxsave (regcache, regnum, xmmregs); 221 222 if (gdb_ptrace (PT_SETXMMREGS, ptid, 223 (PTRACE_TYPE_ARG3) xmmregs, 0) == -1) 224 perror_with_name (_("Couldn't write XMM registers")); 225 } 226 else 227 { 228 have_ptrace_xmmregs = 0; 229 if (gdb_ptrace (PT_GETFPREGS, ptid, 230 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 231 perror_with_name (_("Couldn't get floating point status")); 232 233 i387_collect_fsave (regcache, regnum, &fpregs); 234 235 if (gdb_ptrace (PT_SETFPREGS, ptid, 236 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 237 perror_with_name (_("Couldn't write floating point status")); 238 } 239 } 240 } 241 242 void _initialize_i386bsd_nat (); 243 void 244 _initialize_i386bsd_nat () 245 { 246 /* To support the recognition of signal handlers, i386-bsd-tdep.c 247 hardcodes some constants. Inclusion of this file means that we 248 are compiling a native debugger, which means that we can use the 249 system header files and sysctl(3) to get at the relevant 250 information. */ 251 252 #if defined (OpenBSD) 253 #define SC_REG_OFFSET i386obsd_sc_reg_offset 254 #endif 255 256 #ifdef SC_REG_OFFSET 257 258 /* We only check the program counter, stack pointer and frame 259 pointer since these members of `struct sigcontext' are essential 260 for providing backtraces. More checks could be added, but would 261 involve adding configure checks for the appropriate structure 262 members, since older BSD's don't provide all of them. */ 263 264 #define SC_PC_OFFSET SC_REG_OFFSET[I386_EIP_REGNUM] 265 #define SC_SP_OFFSET SC_REG_OFFSET[I386_ESP_REGNUM] 266 #define SC_FP_OFFSET SC_REG_OFFSET[I386_EBP_REGNUM] 267 268 /* Override the default value for the offset of the program counter 269 in the sigcontext structure. */ 270 int offset = offsetof (struct sigcontext, sc_pc); 271 272 if (SC_PC_OFFSET != offset) 273 { 274 warning (_("\ 275 offsetof (struct sigcontext, sc_pc) yields %d instead of %d.\n\ 276 Please report this to <bug-gdb (at) gnu.org>."), 277 offset, SC_PC_OFFSET); 278 } 279 280 SC_PC_OFFSET = offset; 281 282 /* Likewise for the stack pointer. */ 283 offset = offsetof (struct sigcontext, sc_sp); 284 285 if (SC_SP_OFFSET != offset) 286 { 287 warning (_("\ 288 offsetof (struct sigcontext, sc_sp) yields %d instead of %d.\n\ 289 Please report this to <bug-gdb (at) gnu.org>."), 290 offset, SC_SP_OFFSET); 291 } 292 293 SC_SP_OFFSET = offset; 294 295 /* And the frame pointer. */ 296 offset = offsetof (struct sigcontext, sc_fp); 297 298 if (SC_FP_OFFSET != offset) 299 { 300 warning (_("\ 301 offsetof (struct sigcontext, sc_fp) yields %d instead of %d.\n\ 302 Please report this to <bug-gdb (at) gnu.org>."), 303 offset, SC_FP_OFFSET); 304 } 305 306 SC_FP_OFFSET = offset; 307 308 #endif /* SC_REG_OFFSET */ 309 } 310