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