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