]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/nat/aarch64-sve-linux-ptrace.c
Automatic Copyright Year update after running gdb/copyright.py
[thirdparty/binutils-gdb.git] / gdb / nat / aarch64-sve-linux-ptrace.c
CommitLineData
122394f1
AH
1/* Common target dependent for AArch64 systems.
2
4a94e368 3 Copyright (C) 2018-2022 Free Software Foundation, Inc.
122394f1
AH
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
9 the Free Software Foundation; either version 3 of the License, or
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
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include <sys/utsname.h>
21#include <sys/uio.h>
268a13a5 22#include "gdbsupport/common-defs.h"
122394f1
AH
23#include "elf/external.h"
24#include "elf/common.h"
25#include "aarch64-sve-linux-ptrace.h"
26#include "arch/aarch64.h"
268a13a5
TT
27#include "gdbsupport/common-regcache.h"
28#include "gdbsupport/byte-vector.h"
6afcd2d4 29#include <endian.h>
e9902bfc 30
122394f1
AH
31/* See nat/aarch64-sve-linux-ptrace.h. */
32
39bfb937 33uint64_t
122394f1
AH
34aarch64_sve_get_vq (int tid)
35{
36 struct iovec iovec;
37 struct user_sve_header header;
38
39 iovec.iov_len = sizeof (header);
40 iovec.iov_base = &header;
41
42 /* Ptrace gives the vector length in bytes. Convert it to VQ, the number of
43 128bit chunks in a Z register. We use VQ because 128bits is the minimum
44 a Z register can increase in size. */
45
46 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
47 {
48 /* SVE is not supported. */
49 return 0;
50 }
51
e9902bfc 52 uint64_t vq = sve_vq_from_vl (header.vl);
122394f1
AH
53
54 if (!sve_vl_valid (header.vl))
55 {
56 warning (_("Invalid SVE state from kernel; SVE disabled."));
57 return 0;
58 }
59
60 return vq;
61}
e9902bfc
AH
62
63/* See nat/aarch64-sve-linux-ptrace.h. */
64
48574d91
AH
65bool
66aarch64_sve_set_vq (int tid, uint64_t vq)
67{
68 struct iovec iovec;
69 struct user_sve_header header;
70
71 iovec.iov_len = sizeof (header);
72 iovec.iov_base = &header;
73
74 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
75 {
76 /* SVE is not supported. */
77 return false;
78 }
79
80 header.vl = sve_vl_from_vq (vq);
81
82 if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
83 {
84 /* Vector length change failed. */
85 return false;
86 }
87
88 return true;
89}
90
91/* See nat/aarch64-sve-linux-ptrace.h. */
92
93bool
94aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
95{
2d07da27
LM
96 uint64_t reg_vg = 0;
97
98 /* The VG register may not be valid if we've not collected any value yet.
99 This can happen, for example, if we're restoring the regcache after an
100 inferior function call, and the VG register comes after the Z
101 registers. */
48574d91 102 if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
01add95b
SM
103 {
104 /* If vg is not available yet, fetch it from ptrace. The VG value from
105 ptrace is likely the correct one. */
106 uint64_t vq = aarch64_sve_get_vq (tid);
48574d91 107
01add95b
SM
108 /* If something went wrong, just bail out. */
109 if (vq == 0)
110 return false;
2d07da27 111
01add95b
SM
112 reg_vg = sve_vg_from_vq (vq);
113 }
2d07da27
LM
114 else
115 reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
48574d91
AH
116
117 return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg));
118}
119
120/* See nat/aarch64-sve-linux-ptrace.h. */
121
e9902bfc
AH
122std::unique_ptr<gdb_byte[]>
123aarch64_sve_get_sveregs (int tid)
124{
125 struct iovec iovec;
e9902bfc
AH
126 uint64_t vq = aarch64_sve_get_vq (tid);
127
128 if (vq == 0)
129 perror_with_name (_("Unable to fetch SVE register header"));
130
131 /* A ptrace call with NT_ARM_SVE will return a header followed by either a
132 dump of all the SVE and FP registers, or an fpsimd structure (identical to
133 the one returned by NT_FPREGSET) if the kernel has not yet executed any
134 SVE code. Make sure we allocate enough space for a full SVE dump. */
135
136 iovec.iov_len = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
137 std::unique_ptr<gdb_byte[]> buf (new gdb_byte[iovec.iov_len]);
138 iovec.iov_base = buf.get ();
139
140 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
141 perror_with_name (_("Unable to fetch SVE registers"));
142
143 return buf;
144}
145
6afcd2d4
LM
146/* If we are running in BE mode, byteswap the contents
147 of SRC to DST for SIZE bytes. Other, just copy the contents
148 from SRC to DST. */
149
150static void
151aarch64_maybe_swab128 (gdb_byte *dst, const gdb_byte *src, size_t size)
152{
153 gdb_assert (src != nullptr && dst != nullptr);
154 gdb_assert (size > 1);
155
156#if (__BYTE_ORDER == __BIG_ENDIAN)
157 for (int i = 0; i < size - 1; i++)
158 dst[i] = src[size - i];
159#else
160 memcpy (dst, src, size);
161#endif
162}
163
e9902bfc
AH
164/* See nat/aarch64-sve-linux-ptrace.h. */
165
166void
167aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
168 const void *buf)
169{
170 char *base = (char *) buf;
171 struct user_sve_header *header = (struct user_sve_header *) buf;
e9902bfc 172
48574d91
AH
173 uint64_t vq = sve_vq_from_vl (header->vl);
174 uint64_t vg = sve_vg_from_vl (header->vl);
e9902bfc
AH
175
176 /* Sanity check the data in the header. */
177 if (!sve_vl_valid (header->vl)
178 || SVE_PT_SIZE (vq, header->flags) != header->size)
179 error (_("Invalid SVE header from kernel."));
180
48574d91
AH
181 /* Update VG. Note, the registers in the regcache will already be of the
182 correct length. */
183 reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg);
e9902bfc
AH
184
185 if (HAS_SVE_STATE (*header))
186 {
187 /* The register dump contains a set of SVE registers. */
188
189 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
190 reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i,
191 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
192
193 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
194 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i,
195 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
196
197 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM,
198 base + SVE_PT_SVE_FFR_OFFSET (vq));
199 reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
200 base + SVE_PT_SVE_FPSR_OFFSET (vq));
201 reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
202 base + SVE_PT_SVE_FPCR_OFFSET (vq));
203 }
204 else
205 {
6afcd2d4
LM
206 /* WARNING: SIMD state is laid out in memory in target-endian format,
207 while SVE state is laid out in an endianness-independent format (LE).
208
209 So we have a couple cases to consider:
210
211 1 - If the target is big endian, then SIMD state is big endian,
212 requiring a byteswap.
213
214 2 - If the target is little endian, then SIMD state is little endian,
215 which matches the SVE format, so no byteswap is needed. */
216
e9902bfc
AH
217 /* There is no SVE state yet - the register dump contains a fpsimd
218 structure instead. These registers still exist in the hardware, but
219 the kernel has not yet initialised them, and so they will be null. */
220
6afcd2d4 221 gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
e9902bfc
AH
222 struct user_fpsimd_state *fpsimd
223 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
224
6afcd2d4
LM
225 /* Make sure we have a zeroed register buffer. We will need the zero
226 padding below. */
227 memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
228
e9902bfc
AH
229 /* Copy across the V registers from fpsimd structure to the Z registers,
230 ensuring the non overlapping state is set to null. */
231
e9902bfc
AH
232 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
233 {
6afcd2d4
LM
234 /* Handle big endian/little endian SIMD/SVE conversion. */
235 aarch64_maybe_swab128 (reg, (const gdb_byte *) &fpsimd->vregs[i],
236 V_REGISTER_SIZE);
237 reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg);
e9902bfc
AH
238 }
239
240 reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
241 reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
242
243 /* Clear the SVE only registers. */
6afcd2d4 244 memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
e9902bfc
AH
245
246 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
6afcd2d4 247 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg);
e9902bfc 248
6afcd2d4 249 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg);
e9902bfc
AH
250 }
251}
252
253/* See nat/aarch64-sve-linux-ptrace.h. */
254
255void
256aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
257 void *buf)
258{
259 struct user_sve_header *header = (struct user_sve_header *) buf;
260 char *base = (char *) buf;
48574d91 261 uint64_t vq = sve_vq_from_vl (header->vl);
e9902bfc
AH
262
263 /* Sanity check the data in the header. */
264 if (!sve_vl_valid (header->vl)
265 || SVE_PT_SIZE (vq, header->flags) != header->size)
266 error (_("Invalid SVE header from kernel."));
267
e9902bfc
AH
268 if (!HAS_SVE_STATE (*header))
269 {
270 /* There is no SVE state yet - the register dump contains a fpsimd
271 structure instead. Where possible we want to write the reg_buf data
272 back to the kernel using the fpsimd structure. However, if we cannot
273 then we'll need to reformat the fpsimd into a full SVE structure,
274 resulting in the initialization of SVE state written back to the
275 kernel, which is why we try to avoid it. */
276
277 bool has_sve_state = false;
6afcd2d4 278 gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
e9902bfc
AH
279 struct user_fpsimd_state *fpsimd
280 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
281
6afcd2d4 282 memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
e9902bfc
AH
283
284 /* Check in the reg_buf if any of the Z registers are set after the
285 first 128 bits, or if any of the other SVE registers are set. */
286
287 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
288 {
289 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i,
6afcd2d4 290 reg, sizeof (__int128_t));
e9902bfc
AH
291 if (has_sve_state)
292 break;
293 }
294
295 if (!has_sve_state)
296 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
297 {
298 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i,
6afcd2d4 299 reg, 0);
e9902bfc
AH
300 if (has_sve_state)
301 break;
302 }
303
304 if (!has_sve_state)
305 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
6afcd2d4 306 reg, 0);
e9902bfc
AH
307
308 /* If no SVE state exists, then use the existing fpsimd structure to
309 write out state and return. */
310 if (!has_sve_state)
311 {
6afcd2d4
LM
312 /* WARNING: SIMD state is laid out in memory in target-endian format,
313 while SVE state is laid out in an endianness-independent format
314 (LE).
315
316 So we have a couple cases to consider:
317
318 1 - If the target is big endian, then SIMD state is big endian,
319 requiring a byteswap.
320
321 2 - If the target is little endian, then SIMD state is little
322 endian, which matches the SVE format, so no byteswap is needed. */
323
e9902bfc
AH
324 /* The collects of the Z registers will overflow the size of a vreg.
325 There is enough space in the structure to allow for this, but we
326 cannot overflow into the next register as we might not be
327 collecting every register. */
328
329 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
330 {
331 if (REG_VALID
332 == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
333 {
6afcd2d4
LM
334 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, reg);
335 /* Handle big endian/little endian SIMD/SVE conversion. */
336 aarch64_maybe_swab128 ((gdb_byte *) &fpsimd->vregs[i], reg,
337 V_REGISTER_SIZE);
e9902bfc
AH
338 }
339 }
340
341 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
342 reg_buf->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
343 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
344 reg_buf->raw_collect (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
345
346 return;
347 }
348
349 /* Otherwise, reformat the fpsimd structure into a full SVE set, by
350 expanding the V registers (working backwards so we don't splat
351 registers before they are copied) and using null for everything else.
352 Note that enough space for a full SVE dump was originally allocated
353 for base. */
354
355 header->flags |= SVE_PT_REGS_SVE;
356 header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
357
358 memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
359 sizeof (uint32_t));
360 memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
361 sizeof (uint32_t));
362
363 for (int i = AARCH64_SVE_Z_REGS_NUM; i >= 0 ; i--)
364 {
365 memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i],
366 sizeof (__int128_t));
367 }
368 }
369
370 /* Replace the kernel values with those from reg_buf. */
371
372 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
373 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
374 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i,
375 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
376
377 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
378 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_P0_REGNUM + i))
379 reg_buf->raw_collect (AARCH64_SVE_P0_REGNUM + i,
380 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
381
382 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_FFR_REGNUM))
383 reg_buf->raw_collect (AARCH64_SVE_FFR_REGNUM,
384 base + SVE_PT_SVE_FFR_OFFSET (vq));
385 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
386 reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
387 base + SVE_PT_SVE_FPSR_OFFSET (vq));
388 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
389 reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
390 base + SVE_PT_SVE_FPCR_OFFSET (vq));
391
392}