]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/amd64-fbsd-nat.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / amd64-fbsd-nat.c
CommitLineData
68cc0bfb 1/* Native-dependent code for FreeBSD/amd64.
2a6d284d 2
213516ef 3 Copyright (C) 2003-2023 Free Software Foundation, Inc.
68cc0bfb
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
68cc0bfb
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/>. */
68cc0bfb
MK
19
20#include "defs.h"
4de283e4
TT
21#include "inferior.h"
22#include "regcache.h"
23#include "target.h"
68cc0bfb 24
68cc0bfb 25#include <signal.h>
4de283e4 26#include <sys/types.h>
68cc0bfb
MK
27#include <sys/ptrace.h>
28#include <sys/sysctl.h>
cf424aef 29#include <sys/user.h>
4de283e4 30#include <machine/reg.h>
68cc0bfb 31
4de283e4 32#include "amd64-tdep.h"
00d7af04 33#include "amd64-fbsd-tdep.h"
4de283e4 34#include "amd64-nat.h"
d55e5aa6 35#include "x86-nat.h"
268a13a5 36#include "gdbsupport/x86-xstate.h"
a49ce729 37#include "x86-fbsd-nat.h"
68cc0bfb 38
a49ce729 39class amd64_fbsd_nat_target final : public x86_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
48static amd64_fbsd_nat_target the_amd64_fbsd_nat_target;
49
00d7af04
JB
50#ifdef PT_GETXSTATE_INFO
51static size_t xsave_len;
52#endif
53
54/* This is a layout of the amd64 'struct reg' but with i386
55 registers. */
68cc0bfb 56
00d7af04 57static const struct regcache_map_entry amd64_fbsd32_gregmap[] =
68cc0bfb 58{
00d7af04
JB
59 { 8, REGCACHE_MAP_SKIP, 8 },
60 { 1, I386_EDI_REGNUM, 8 },
61 { 1, I386_ESI_REGNUM, 8 },
62 { 1, I386_EBP_REGNUM, 8 },
63 { 1, I386_EBX_REGNUM, 8 },
64 { 1, I386_EDX_REGNUM, 8 },
65 { 1, I386_ECX_REGNUM, 8 },
66 { 1, I386_EAX_REGNUM, 8 },
67 { 1, REGCACHE_MAP_SKIP, 4 }, /* trapno */
68 { 1, I386_FS_REGNUM, 2 },
69 { 1, I386_GS_REGNUM, 2 },
70 { 1, REGCACHE_MAP_SKIP, 4 }, /* err */
71 { 1, I386_ES_REGNUM, 2 },
72 { 1, I386_DS_REGNUM, 2 },
73 { 1, I386_EIP_REGNUM, 8 },
74 { 1, I386_CS_REGNUM, 8 },
75 { 1, I386_EFLAGS_REGNUM, 8 },
76 { 1, I386_ESP_REGNUM, 0 },
77 { 1, I386_SS_REGNUM, 8 },
78 { 0 }
68cc0bfb 79};
2a6d284d 80
00d7af04
JB
81static const struct regset amd64_fbsd32_gregset =
82{
83 amd64_fbsd32_gregmap, regcache_supply_regset, regcache_collect_regset
84};
68cc0bfb 85
00d7af04 86/* Return the regset to use for 'struct reg' for the GDBARCH. */
68cc0bfb 87
00d7af04
JB
88static const struct regset *
89find_gregset (struct gdbarch *gdbarch)
2a6d284d 90{
00d7af04
JB
91 if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
92 return &amd64_fbsd32_gregset;
93 else
94 return &amd64_fbsd_gregset;
95}
96
97/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
98 for all registers. */
99
100void
101amd64_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
102{
103 struct gdbarch *gdbarch = regcache->arch ();
104#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
08106042 105 const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
00d7af04
JB
106#endif
107 pid_t pid = get_ptrace_pid (regcache->ptid ());
108 const struct regset *gregset = find_gregset (gdbarch);
109
110 if (fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS, gregset))
111 {
112 if (regnum != -1)
113 return;
114 }
115
116#ifdef PT_GETFSBASE
117 if (regnum == -1 || regnum == tdep->fsbase_regnum)
118 {
119 register_t base;
120
121 if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
122 perror_with_name (_("Couldn't get segment register fs_base"));
123
124 regcache->raw_supply (tdep->fsbase_regnum, &base);
125 if (regnum != -1)
126 return;
127 }
128#endif
129#ifdef PT_GETGSBASE
130 if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
131 {
132 register_t base;
133
134 if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
135 perror_with_name (_("Couldn't get segment register gs_base"));
136
137 regcache->raw_supply (tdep->fsbase_regnum + 1, &base);
138 if (regnum != -1)
139 return;
140 }
141#endif
142
143 /* There is no amd64_fxsave_supplies or amd64_xsave_supplies.
144 Instead, the earlier register sets return early if the request
145 was for a specific register that was already satisified to avoid
146 fetching the FPU/XSAVE state unnecessarily. */
147
148#ifdef PT_GETXSTATE_INFO
149 if (xsave_len != 0)
150 {
151 void *xstateregs = alloca (xsave_len);
152
153 if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
154 perror_with_name (_("Couldn't get extended state status"));
155
156 amd64_supply_xsave (regcache, regnum, xstateregs);
157 return;
158 }
159#endif
160
161 struct fpreg fpregs;
162
163 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
164 perror_with_name (_("Couldn't get floating point status"));
165
166 amd64_supply_fxsave (regcache, regnum, &fpregs);
167}
168
169/* Store register REGNUM back into the inferior. If REGNUM is -1, do
170 this for all registers. */
171
172void
173amd64_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum)
174{
175 struct gdbarch *gdbarch = regcache->arch ();
176#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
08106042 177 const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
00d7af04
JB
178#endif
179 pid_t pid = get_ptrace_pid (regcache->ptid ());
180 const struct regset *gregset = find_gregset (gdbarch);
181
182 if (store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS,
183 gregset))
184 {
185 if (regnum != -1)
186 return;
187 }
188
189#ifdef PT_SETFSBASE
190 if (regnum == -1 || regnum == tdep->fsbase_regnum)
191 {
192 register_t base;
193
194 /* Clear the full base value to support 32-bit targets. */
195 base = 0;
196 regcache->raw_collect (tdep->fsbase_regnum, &base);
197
198 if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
199 perror_with_name (_("Couldn't write segment register fs_base"));
200 if (regnum != -1)
201 return;
202 }
203#endif
204#ifdef PT_SETGSBASE
205 if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
206 {
207 register_t base;
208
209 /* Clear the full base value to support 32-bit targets. */
210 base = 0;
211 regcache->raw_collect (tdep->fsbase_regnum + 1, &base);
212
213 if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
214 perror_with_name (_("Couldn't write segment register gs_base"));
215 if (regnum != -1)
216 return;
217 }
218#endif
219
220 /* There is no amd64_fxsave_supplies or amd64_xsave_supplies.
221 Instead, the earlier register sets return early if the request
222 was for a specific register that was already satisified to avoid
223 fetching the FPU/XSAVE state unnecessarily. */
224
225#ifdef PT_GETXSTATE_INFO
226 if (xsave_len != 0)
227 {
228 void *xstateregs = alloca (xsave_len);
229
230 if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
231 perror_with_name (_("Couldn't get extended state status"));
232
233 amd64_collect_xsave (regcache, regnum, xstateregs, 0);
234
235 if (ptrace (PT_SETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs,
236 xsave_len) == -1)
237 perror_with_name (_("Couldn't write extended state status"));
238 return;
239 }
240#endif
241
242 struct fpreg fpregs;
243
244 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
245 perror_with_name (_("Couldn't get floating point status"));
246
247 amd64_collect_fxsave (regcache, regnum, &fpregs);
248
249 if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
250 perror_with_name (_("Couldn't write floating point status"));
251}
68cc0bfb 252
315c4276
MK
253/* Support for debugging kernel virtual memory images. */
254
315c4276 255#include <machine/pcb.h>
1f596238 256#include <osreldate.h>
315c4276
MK
257
258#include "bsd-kvm.h"
259
260static int
261amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
262{
263 /* The following is true for FreeBSD 5.2:
264
265 The pcb contains %rip, %rbx, %rsp, %rbp, %r12, %r13, %r14, %r15,
266 %ds, %es, %fs and %gs. This accounts for all callee-saved
267 registers specified by the psABI and then some. Here %esp
268 contains the stack pointer at the point just after the call to
269 cpu_switch(). From this information we reconstruct the register
270 state as it would like when we just returned from cpu_switch(). */
271
272 /* The stack pointer shouldn't be zero. */
273 if (pcb->pcb_rsp == 0)
274 return 0;
275
276 pcb->pcb_rsp += 8;
73e1c03f
SM
277 regcache->raw_supply (AMD64_RIP_REGNUM, &pcb->pcb_rip);
278 regcache->raw_supply (AMD64_RBX_REGNUM, &pcb->pcb_rbx);
279 regcache->raw_supply (AMD64_RSP_REGNUM, &pcb->pcb_rsp);
280 regcache->raw_supply (AMD64_RBP_REGNUM, &pcb->pcb_rbp);
281 regcache->raw_supply (12, &pcb->pcb_r12);
282 regcache->raw_supply (13, &pcb->pcb_r13);
283 regcache->raw_supply (14, &pcb->pcb_r14);
284 regcache->raw_supply (15, &pcb->pcb_r15);
c1dec97b 285#if (__FreeBSD_version < 800075) && (__FreeBSD_kernel_version < 800075)
ffeecffa
JB
286 /* struct pcb provides the pcb_ds/pcb_es/pcb_fs/pcb_gs fields only
287 up until __FreeBSD_version 800074: The removal of these fields
288 occurred on 2009-04-01 while the __FreeBSD_version number was
289 bumped to 800075 on 2009-04-06. So 800075 is the closest version
290 number where we should not try to access these fields. */
73e1c03f
SM
291 regcache->raw_supply (AMD64_DS_REGNUM, &pcb->pcb_ds);
292 regcache->raw_supply (AMD64_ES_REGNUM, &pcb->pcb_es);
293 regcache->raw_supply (AMD64_FS_REGNUM, &pcb->pcb_fs);
294 regcache->raw_supply (AMD64_GS_REGNUM, &pcb->pcb_gs);
1f596238 295#endif
315c4276
MK
296
297 return 1;
298}
299\f
300
f6ac5f3d 301/* Implement the read_description method. */
97de3545 302
f6ac5f3d
PA
303const struct target_desc *
304amd64_fbsd_nat_target::read_description ()
97de3545
JB
305{
306#ifdef PT_GETXSTATE_INFO
307 static int xsave_probed;
308 static uint64_t xcr0;
309#endif
310 struct reg regs;
311 int is64;
312
e99b03dc 313 if (ptrace (PT_GETREGS, inferior_ptid.pid (),
97de3545
JB
314 (PTRACE_TYPE_ARG3) &regs, 0) == -1)
315 perror_with_name (_("Couldn't get registers"));
316 is64 = (regs.r_cs == GSEL (GUCODE_SEL, SEL_UPL));
317#ifdef PT_GETXSTATE_INFO
318 if (!xsave_probed)
319 {
320 struct ptrace_xstate_info info;
321
e99b03dc 322 if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (),
97de3545
JB
323 (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
324 {
00d7af04 325 xsave_len = info.xsave_len;
97de3545
JB
326 xcr0 = info.xsave_mask;
327 }
328 xsave_probed = 1;
329 }
330
00d7af04 331 if (xsave_len != 0)
97de3545
JB
332 {
333 if (is64)
41206e32 334 return amd64_target_description (xcr0, true);
97de3545 335 else
dd6876c9 336 return i386_target_description (xcr0, true);
97de3545
JB
337 }
338#endif
339 if (is64)
41206e32 340 return amd64_target_description (X86_XSTATE_SSE_MASK, true);
97de3545 341 else
dd6876c9 342 return i386_target_description (X86_XSTATE_SSE_MASK, true);
97de3545
JB
343}
344
6c265988 345void _initialize_amd64fbsd_nat ();
68cc0bfb 346void
6c265988 347_initialize_amd64fbsd_nat ()
68cc0bfb 348{
d9f719f1 349 add_inf_child_target (&the_amd64_fbsd_nat_target);
6a5c78a3
MK
350
351 /* Support debugging kernel virtual memory images. */
352 bsd_kvm_add_target (amd64fbsd_supply_pcb);
68cc0bfb 353}