Fix TARGET_CHAR_BIT/HOST_CHAR_BIT confusion in gmp-utils.c
[binutils-gdb.git] / gdb / nat / aarch64-sve-linux-ptrace.c
blob2ce90ccfd7e3c1e0fbb742508b7ee6fd96524a2b
1 /* Common target dependent for AArch64 systems.
3 Copyright (C) 2018-2020 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
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"
30 /* See nat/aarch64-sve-linux-ptrace.h. */
32 uint64_t
33 aarch64_sve_get_vq (int tid)
35 struct iovec iovec;
36 struct user_sve_header header;
38 iovec.iov_len = sizeof (header);
39 iovec.iov_base = &header;
41 /* Ptrace gives the vector length in bytes. Convert it to VQ, the number of
42 128bit chunks in a Z register. We use VQ because 128bits is the minimum
43 a Z register can increase in size. */
45 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
47 /* SVE is not supported. */
48 return 0;
51 uint64_t vq = sve_vq_from_vl (header.vl);
53 if (!sve_vl_valid (header.vl))
55 warning (_("Invalid SVE state from kernel; SVE disabled."));
56 return 0;
59 return vq;
62 /* See nat/aarch64-sve-linux-ptrace.h. */
64 bool
65 aarch64_sve_set_vq (int tid, uint64_t vq)
67 struct iovec iovec;
68 struct user_sve_header header;
70 iovec.iov_len = sizeof (header);
71 iovec.iov_base = &header;
73 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
75 /* SVE is not supported. */
76 return false;
79 header.vl = sve_vl_from_vq (vq);
81 if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
83 /* Vector length change failed. */
84 return false;
87 return true;
90 /* See nat/aarch64-sve-linux-ptrace.h. */
92 bool
93 aarch64_sve_set_vq (int tid, struct reg_buffer_common *reg_buf)
95 uint64_t reg_vg = 0;
97 /* The VG register may not be valid if we've not collected any value yet.
98 This can happen, for example, if we're restoring the regcache after an
99 inferior function call, and the VG register comes after the Z
100 registers. */
101 if (reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM) != REG_VALID)
103 /* If vg is not available yet, fetch it from ptrace. The VG value from
104 ptrace is likely the correct one. */
105 uint64_t vq = aarch64_sve_get_vq (tid);
107 /* If something went wrong, just bail out. */
108 if (vq == 0)
109 return false;
111 reg_vg = sve_vg_from_vq (vq);
113 else
114 reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &reg_vg);
116 return aarch64_sve_set_vq (tid, sve_vq_from_vg (reg_vg));
119 /* See nat/aarch64-sve-linux-ptrace.h. */
121 std::unique_ptr<gdb_byte[]>
122 aarch64_sve_get_sveregs (int tid)
124 struct iovec iovec;
125 uint64_t vq = aarch64_sve_get_vq (tid);
127 if (vq == 0)
128 perror_with_name (_("Unable to fetch SVE register header"));
130 /* A ptrace call with NT_ARM_SVE will return a header followed by either a
131 dump of all the SVE and FP registers, or an fpsimd structure (identical to
132 the one returned by NT_FPREGSET) if the kernel has not yet executed any
133 SVE code. Make sure we allocate enough space for a full SVE dump. */
135 iovec.iov_len = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
136 std::unique_ptr<gdb_byte[]> buf (new gdb_byte[iovec.iov_len]);
137 iovec.iov_base = buf.get ();
139 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
140 perror_with_name (_("Unable to fetch SVE registers"));
142 return buf;
145 /* See nat/aarch64-sve-linux-ptrace.h. */
147 void
148 aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
149 const void *buf)
151 char *base = (char *) buf;
152 struct user_sve_header *header = (struct user_sve_header *) buf;
154 uint64_t vq = sve_vq_from_vl (header->vl);
155 uint64_t vg = sve_vg_from_vl (header->vl);
157 /* Sanity check the data in the header. */
158 if (!sve_vl_valid (header->vl)
159 || SVE_PT_SIZE (vq, header->flags) != header->size)
160 error (_("Invalid SVE header from kernel."));
162 /* Update VG. Note, the registers in the regcache will already be of the
163 correct length. */
164 reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg);
166 if (HAS_SVE_STATE (*header))
168 /* The register dump contains a set of SVE registers. */
170 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
171 reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i,
172 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
174 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
175 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i,
176 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
178 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM,
179 base + SVE_PT_SVE_FFR_OFFSET (vq));
180 reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
181 base + SVE_PT_SVE_FPSR_OFFSET (vq));
182 reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
183 base + SVE_PT_SVE_FPCR_OFFSET (vq));
185 else
187 /* There is no SVE state yet - the register dump contains a fpsimd
188 structure instead. These registers still exist in the hardware, but
189 the kernel has not yet initialised them, and so they will be null. */
191 char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
192 struct user_fpsimd_state *fpsimd
193 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
195 /* Copy across the V registers from fpsimd structure to the Z registers,
196 ensuring the non overlapping state is set to null. */
198 memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
200 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
202 memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t));
203 reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
206 reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
207 reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
209 /* Clear the SVE only registers. */
211 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
212 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, zero_reg);
214 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg);
218 /* See nat/aarch64-sve-linux-ptrace.h. */
220 void
221 aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
222 void *buf)
224 struct user_sve_header *header = (struct user_sve_header *) buf;
225 char *base = (char *) buf;
226 uint64_t vq = sve_vq_from_vl (header->vl);
228 /* Sanity check the data in the header. */
229 if (!sve_vl_valid (header->vl)
230 || SVE_PT_SIZE (vq, header->flags) != header->size)
231 error (_("Invalid SVE header from kernel."));
233 if (!HAS_SVE_STATE (*header))
235 /* There is no SVE state yet - the register dump contains a fpsimd
236 structure instead. Where possible we want to write the reg_buf data
237 back to the kernel using the fpsimd structure. However, if we cannot
238 then we'll need to reformat the fpsimd into a full SVE structure,
239 resulting in the initialization of SVE state written back to the
240 kernel, which is why we try to avoid it. */
242 bool has_sve_state = false;
243 char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
244 struct user_fpsimd_state *fpsimd
245 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
247 memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
249 /* Check in the reg_buf if any of the Z registers are set after the
250 first 128 bits, or if any of the other SVE registers are set. */
252 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
254 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i,
255 zero_reg, sizeof (__int128_t));
256 if (has_sve_state)
257 break;
260 if (!has_sve_state)
261 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
263 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i,
264 zero_reg, 0);
265 if (has_sve_state)
266 break;
269 if (!has_sve_state)
270 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
271 zero_reg, 0);
273 /* If no SVE state exists, then use the existing fpsimd structure to
274 write out state and return. */
275 if (!has_sve_state)
277 /* The collects of the Z registers will overflow the size of a vreg.
278 There is enough space in the structure to allow for this, but we
279 cannot overflow into the next register as we might not be
280 collecting every register. */
282 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
284 if (REG_VALID
285 == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
287 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
288 memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t));
292 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
293 reg_buf->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
294 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
295 reg_buf->raw_collect (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
297 return;
300 /* Otherwise, reformat the fpsimd structure into a full SVE set, by
301 expanding the V registers (working backwards so we don't splat
302 registers before they are copied) and using null for everything else.
303 Note that enough space for a full SVE dump was originally allocated
304 for base. */
306 header->flags |= SVE_PT_REGS_SVE;
307 header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
309 memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
310 sizeof (uint32_t));
311 memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
312 sizeof (uint32_t));
314 for (int i = AARCH64_SVE_Z_REGS_NUM; i >= 0 ; i--)
316 memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i],
317 sizeof (__int128_t));
321 /* Replace the kernel values with those from reg_buf. */
323 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
324 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
325 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i,
326 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
328 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
329 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_P0_REGNUM + i))
330 reg_buf->raw_collect (AARCH64_SVE_P0_REGNUM + i,
331 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
333 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_FFR_REGNUM))
334 reg_buf->raw_collect (AARCH64_SVE_FFR_REGNUM,
335 base + SVE_PT_SVE_FFR_OFFSET (vq));
336 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
337 reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
338 base + SVE_PT_SVE_FPSR_OFFSET (vq));
339 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
340 reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
341 base + SVE_PT_SVE_FPCR_OFFSET (vq));