Unify shell-finding logic
[deliverable/binutils-gdb.git] / gdb / nat / aarch64-sve-linux-ptrace.c
CommitLineData
122394f1
AH
1/* Common target dependent for AArch64 systems.
2
3 Copyright (C) 2018 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 "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"
e9902bfc
AH
27#include "common-regcache.h"
28#include "common/byte-vector.h"
29
30static bool vq_change_warned = false;
122394f1
AH
31
32/* See nat/aarch64-sve-linux-ptrace.h. */
33
39bfb937 34uint64_t
122394f1
AH
35aarch64_sve_get_vq (int tid)
36{
37 struct iovec iovec;
38 struct user_sve_header header;
39
40 iovec.iov_len = sizeof (header);
41 iovec.iov_base = &header;
42
43 /* Ptrace gives the vector length in bytes. Convert it to VQ, the number of
44 128bit chunks in a Z register. We use VQ because 128bits is the minimum
45 a Z register can increase in size. */
46
47 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
48 {
49 /* SVE is not supported. */
50 return 0;
51 }
52
e9902bfc 53 uint64_t vq = sve_vq_from_vl (header.vl);
122394f1
AH
54
55 if (!sve_vl_valid (header.vl))
56 {
57 warning (_("Invalid SVE state from kernel; SVE disabled."));
58 return 0;
59 }
60
61 return vq;
62}
e9902bfc
AH
63
64/* See nat/aarch64-sve-linux-ptrace.h. */
65
66std::unique_ptr<gdb_byte[]>
67aarch64_sve_get_sveregs (int tid)
68{
69 struct iovec iovec;
e9902bfc
AH
70 uint64_t vq = aarch64_sve_get_vq (tid);
71
72 if (vq == 0)
73 perror_with_name (_("Unable to fetch SVE register header"));
74
75 /* A ptrace call with NT_ARM_SVE will return a header followed by either a
76 dump of all the SVE and FP registers, or an fpsimd structure (identical to
77 the one returned by NT_FPREGSET) if the kernel has not yet executed any
78 SVE code. Make sure we allocate enough space for a full SVE dump. */
79
80 iovec.iov_len = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
81 std::unique_ptr<gdb_byte[]> buf (new gdb_byte[iovec.iov_len]);
82 iovec.iov_base = buf.get ();
83
84 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec) < 0)
85 perror_with_name (_("Unable to fetch SVE registers"));
86
87 return buf;
88}
89
90/* See nat/aarch64-sve-linux-ptrace.h. */
91
92void
93aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common *reg_buf,
94 const void *buf)
95{
96 char *base = (char *) buf;
97 struct user_sve_header *header = (struct user_sve_header *) buf;
98 uint64_t vq, vg_reg_buf = 0;
99
100 vq = sve_vq_from_vl (header->vl);
101
102 /* Sanity check the data in the header. */
103 if (!sve_vl_valid (header->vl)
104 || SVE_PT_SIZE (vq, header->flags) != header->size)
105 error (_("Invalid SVE header from kernel."));
106
107 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM))
108 reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &vg_reg_buf);
109
110 if (vg_reg_buf == 0)
111 {
112 /* VG has not been set. */
113 vg_reg_buf = sve_vg_from_vl (header->vl);
114 reg_buf->raw_supply (AARCH64_SVE_VG_REGNUM, &vg_reg_buf);
115 }
116 else if (vg_reg_buf != sve_vg_from_vl (header->vl) && !vq_change_warned)
117 {
118 /* Vector length on the running process has changed. GDB currently does
119 not support this and will result in GDB showing incorrect partially
120 incorrect data for the vector registers. Warn once and continue. We
121 do not expect many programs to exhibit this behaviour. To fix this
122 we need to spot the change earlier and generate a new target
123 descriptor. */
124 warning (_("SVE Vector length has changed (%ld to %d). "
125 "Vector registers may show incorrect data."),
126 vg_reg_buf, sve_vg_from_vl (header->vl));
127 vq_change_warned = true;
128 }
129
130 if (HAS_SVE_STATE (*header))
131 {
132 /* The register dump contains a set of SVE registers. */
133
134 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
135 reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i,
136 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
137
138 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
139 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i,
140 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
141
142 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM,
143 base + SVE_PT_SVE_FFR_OFFSET (vq));
144 reg_buf->raw_supply (AARCH64_FPSR_REGNUM,
145 base + SVE_PT_SVE_FPSR_OFFSET (vq));
146 reg_buf->raw_supply (AARCH64_FPCR_REGNUM,
147 base + SVE_PT_SVE_FPCR_OFFSET (vq));
148 }
149 else
150 {
151 /* There is no SVE state yet - the register dump contains a fpsimd
152 structure instead. These registers still exist in the hardware, but
153 the kernel has not yet initialised them, and so they will be null. */
154
155 char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
156 struct user_fpsimd_state *fpsimd
157 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
158
159 /* Copy across the V registers from fpsimd structure to the Z registers,
160 ensuring the non overlapping state is set to null. */
161
162 memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
163
164 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
165 {
166 memcpy (zero_reg, &fpsimd->vregs[i], sizeof (__int128_t));
167 reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
168 }
169
170 reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
171 reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
172
173 /* Clear the SVE only registers. */
174
175 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
176 reg_buf->raw_supply (AARCH64_SVE_P0_REGNUM + i, zero_reg);
177
178 reg_buf->raw_supply (AARCH64_SVE_FFR_REGNUM, zero_reg);
179 }
180}
181
182/* See nat/aarch64-sve-linux-ptrace.h. */
183
184void
185aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common *reg_buf,
186 void *buf)
187{
188 struct user_sve_header *header = (struct user_sve_header *) buf;
189 char *base = (char *) buf;
190 uint64_t vq, vg_reg_buf = 0;
191
192 vq = sve_vq_from_vl (header->vl);
193
194 /* Sanity check the data in the header. */
195 if (!sve_vl_valid (header->vl)
196 || SVE_PT_SIZE (vq, header->flags) != header->size)
197 error (_("Invalid SVE header from kernel."));
198
199 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_VG_REGNUM))
200 reg_buf->raw_collect (AARCH64_SVE_VG_REGNUM, &vg_reg_buf);
201
202 if (vg_reg_buf != 0 && vg_reg_buf != sve_vg_from_vl (header->vl))
203 {
204 /* Vector length on the running process has changed. GDB currently does
205 not support this and will result in GDB writing invalid data back to
206 the vector registers. Error and exit. We do not expect many programs
207 to exhibit this behaviour. To fix this we need to spot the change
208 earlier and generate a new target descriptor. */
209 error (_("SVE Vector length has changed (%ld to %d). "
210 "Cannot write back registers."),
211 vg_reg_buf, sve_vg_from_vl (header->vl));
212 }
213
214 if (!HAS_SVE_STATE (*header))
215 {
216 /* There is no SVE state yet - the register dump contains a fpsimd
217 structure instead. Where possible we want to write the reg_buf data
218 back to the kernel using the fpsimd structure. However, if we cannot
219 then we'll need to reformat the fpsimd into a full SVE structure,
220 resulting in the initialization of SVE state written back to the
221 kernel, which is why we try to avoid it. */
222
223 bool has_sve_state = false;
224 char *zero_reg = (char *) alloca (SVE_PT_SVE_ZREG_SIZE (vq));
225 struct user_fpsimd_state *fpsimd
226 = (struct user_fpsimd_state *)(base + SVE_PT_FPSIMD_OFFSET);
227
228 memset (zero_reg, 0, SVE_PT_SVE_ZREG_SIZE (vq));
229
230 /* Check in the reg_buf if any of the Z registers are set after the
231 first 128 bits, or if any of the other SVE registers are set. */
232
233 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
234 {
235 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_Z0_REGNUM + i,
236 zero_reg, sizeof (__int128_t));
237 if (has_sve_state)
238 break;
239 }
240
241 if (!has_sve_state)
242 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
243 {
244 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_P0_REGNUM + i,
245 zero_reg, 0);
246 if (has_sve_state)
247 break;
248 }
249
250 if (!has_sve_state)
251 has_sve_state |= reg_buf->raw_compare (AARCH64_SVE_FFR_REGNUM,
252 zero_reg, 0);
253
254 /* If no SVE state exists, then use the existing fpsimd structure to
255 write out state and return. */
256 if (!has_sve_state)
257 {
258 /* The collects of the Z registers will overflow the size of a vreg.
259 There is enough space in the structure to allow for this, but we
260 cannot overflow into the next register as we might not be
261 collecting every register. */
262
263 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
264 {
265 if (REG_VALID
266 == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
267 {
268 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i, zero_reg);
269 memcpy (&fpsimd->vregs[i], zero_reg, sizeof (__int128_t));
270 }
271 }
272
273 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
274 reg_buf->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr);
275 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
276 reg_buf->raw_collect (AARCH64_FPCR_REGNUM, &fpsimd->fpcr);
277
278 return;
279 }
280
281 /* Otherwise, reformat the fpsimd structure into a full SVE set, by
282 expanding the V registers (working backwards so we don't splat
283 registers before they are copied) and using null for everything else.
284 Note that enough space for a full SVE dump was originally allocated
285 for base. */
286
287 header->flags |= SVE_PT_REGS_SVE;
288 header->size = SVE_PT_SIZE (vq, SVE_PT_REGS_SVE);
289
290 memcpy (base + SVE_PT_SVE_FPSR_OFFSET (vq), &fpsimd->fpsr,
291 sizeof (uint32_t));
292 memcpy (base + SVE_PT_SVE_FPCR_OFFSET (vq), &fpsimd->fpcr,
293 sizeof (uint32_t));
294
295 for (int i = AARCH64_SVE_Z_REGS_NUM; i >= 0 ; i--)
296 {
297 memcpy (base + SVE_PT_SVE_ZREG_OFFSET (vq, i), &fpsimd->vregs[i],
298 sizeof (__int128_t));
299 }
300 }
301
302 /* Replace the kernel values with those from reg_buf. */
303
304 for (int i = 0; i < AARCH64_SVE_Z_REGS_NUM; i++)
305 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_Z0_REGNUM + i))
306 reg_buf->raw_collect (AARCH64_SVE_Z0_REGNUM + i,
307 base + SVE_PT_SVE_ZREG_OFFSET (vq, i));
308
309 for (int i = 0; i < AARCH64_SVE_P_REGS_NUM; i++)
310 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_P0_REGNUM + i))
311 reg_buf->raw_collect (AARCH64_SVE_P0_REGNUM + i,
312 base + SVE_PT_SVE_PREG_OFFSET (vq, i));
313
314 if (REG_VALID == reg_buf->get_register_status (AARCH64_SVE_FFR_REGNUM))
315 reg_buf->raw_collect (AARCH64_SVE_FFR_REGNUM,
316 base + SVE_PT_SVE_FFR_OFFSET (vq));
317 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM))
318 reg_buf->raw_collect (AARCH64_FPSR_REGNUM,
319 base + SVE_PT_SVE_FPSR_OFFSET (vq));
320 if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM))
321 reg_buf->raw_collect (AARCH64_FPCR_REGNUM,
322 base + SVE_PT_SVE_FPCR_OFFSET (vq));
323
324}
This page took 0.076736 seconds and 4 git commands to generate.