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