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