8b162cd35a35bff243bec0a6ca41b36413fb09c3
[deliverable/binutils-gdb.git] / gdb / nat / aarch64-sve-linux-ptrace.c
1 /* Common target dependent for AArch64 systems.
2
3 Copyright (C) 2018-2021 Free Software Foundation, Inc.
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>
22 #include "gdbsupport/common-defs.h"
23 #include "elf/external.h"
24 #include "elf/common.h"
25 #include "aarch64-sve-linux-ptrace.h"
26 #include "arch/aarch64.h"
27 #include "gdbsupport/common-regcache.h"
28 #include "gdbsupport/byte-vector.h"
29 #include <endian.h>
30
31 /* See nat/aarch64-sve-linux-ptrace.h. */
32
33 uint64_t
34 aarch64_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
52 uint64_t vq = sve_vq_from_vl (header.vl);
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 }
62
63 /* See nat/aarch64-sve-linux-ptrace.h. */
64
65 bool
66 aarch64_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
93 bool
94 aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
95 {
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. */
102 if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
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);
107
108 /* If something went wrong, just bail out. */
109 if (vq == 0)
110 return false;
111
112 reg_vg = sve_vg_from_vq (vq);
113 }
114 else
115 reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
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
122 std::unique_ptr<gdb_byte[]>
123 aarch64_sve_get_sveregs (int tid)
124 {
125 struct iovec iovec;
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
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
150 static void
151 aarch64_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
164 /* See nat/aarch64-sve-linux-ptrace.h. */
165
166 void
167 aarch64_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;
172
173 uint64_t vq = sve_vq_from_vl (header->vl);
174 uint64_t vg = sve_vg_from_vl (header->vl);
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
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);
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 {
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
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
221 gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
222 struct user_fpsimd_state *fpsimd
223 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
224
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
229 /* Copy across the V registers from fpsimd structure to the Z registers,
230 ensuring the non overlapping state is set to null. */
231
232 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
233 {
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);
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. */
244 memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
245
246 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
247 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, reg);
248
249 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, reg);
250 }
251 }
252
253 /* See nat/aarch64-sve-linux-ptrace.h. */
254
255 void
256 aarch64_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;
261 uint64_t vq = sve_vq_from_vl (header->vl);
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
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;
278 gdb_byte *reg = (gdb_byte *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
279 struct user_fpsimd_state *fpsimd
280 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
281
282 memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
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,
290 reg, sizeof (__int128_t));
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,
299 reg, 0);
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,
306 reg, 0);
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 {
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
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 {
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);
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 }
This page took 0.037584 seconds and 3 git commands to generate.