1 /* Common target dependent for AArch64 systems.
3 Copyright (C) 2018-2019 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>
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"
27 #include "common-regcache.h"
28 #include "common/byte-vector.h"
30 static bool vq_change_warned
= false;
32 /* See nat/aarch64-sve-linux-ptrace.h. */
35 aarch64_sve_get_vq (int tid
)
38 struct user_sve_header header
;
40 iovec
.iov_len
= sizeof (header
);
41 iovec
.iov_base
= &header
;
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. */
47 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
49 /* SVE is not supported. */
53 uint64_t vq
= sve_vq_from_vl (header
.vl
);
55 if (!sve_vl_valid (header
.vl
))
57 warning (_("Invalid SVE state from kernel; SVE disabled."));
64 /* See nat/aarch64-sve-linux-ptrace.h. */
66 std::unique_ptr
<gdb_byte
[]>
67 aarch64_sve_get_sveregs (int tid
)
70 uint64_t vq
= aarch64_sve_get_vq (tid
);
73 perror_with_name (_("Unable to fetch SVE register header"));
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. */
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 ();
84 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_SVE
, &iovec
) < 0)
85 perror_with_name (_("Unable to fetch SVE registers"));
90 /* See nat/aarch64-sve-linux-ptrace.h. */
93 aarch64_sve_regs_copy_to_reg_buf (struct reg_buffer_common
*reg_buf
,
96 char *base
= (char *) buf
;
97 struct user_sve_header
*header
= (struct user_sve_header
*) buf
;
98 uint64_t vq
, vg_reg_buf
= 0;
100 vq
= sve_vq_from_vl (header
->vl
);
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."));
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
);
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
);
116 else if (vg_reg_buf
!= sve_vg_from_vl (header
->vl
) && !vq_change_warned
)
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
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;
130 if (HAS_SVE_STATE (*header
))
132 /* The register dump contains a set of SVE registers. */
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
));
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
));
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
));
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. */
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
);
159 /* Copy across the V registers from fpsimd structure to the Z registers,
160 ensuring the non overlapping state is set to null. */
162 memset (zero_reg
, 0, SVE_PT_SVE_ZREG_SIZE (vq
));
164 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
166 memcpy (zero_reg
, &fpsimd
->vregs
[i
], sizeof (__int128_t
));
167 reg_buf
->raw_supply (AARCH64_SVE_Z0_REGNUM
+ i
, zero_reg
);
170 reg_buf
->raw_supply (AARCH64_FPSR_REGNUM
, &fpsimd
->fpsr
);
171 reg_buf
->raw_supply (AARCH64_FPCR_REGNUM
, &fpsimd
->fpcr
);
173 /* Clear the SVE only registers. */
175 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
176 reg_buf
->raw_supply (AARCH64_SVE_P0_REGNUM
+ i
, zero_reg
);
178 reg_buf
->raw_supply (AARCH64_SVE_FFR_REGNUM
, zero_reg
);
182 /* See nat/aarch64-sve-linux-ptrace.h. */
185 aarch64_sve_regs_copy_from_reg_buf (const struct reg_buffer_common
*reg_buf
,
188 struct user_sve_header
*header
= (struct user_sve_header
*) buf
;
189 char *base
= (char *) buf
;
190 uint64_t vq
, vg_reg_buf
= 0;
192 vq
= sve_vq_from_vl (header
->vl
);
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."));
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
);
202 if (vg_reg_buf
!= 0 && vg_reg_buf
!= sve_vg_from_vl (header
->vl
))
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
));
214 if (!HAS_SVE_STATE (*header
))
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. */
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
);
228 memset (zero_reg
, 0, SVE_PT_SVE_ZREG_SIZE (vq
));
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. */
233 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
235 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_Z0_REGNUM
+ i
,
236 zero_reg
, sizeof (__int128_t
));
242 for (int i
= 0; i
< AARCH64_SVE_P_REGS_NUM
; i
++)
244 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_P0_REGNUM
+ i
,
251 has_sve_state
|= reg_buf
->raw_compare (AARCH64_SVE_FFR_REGNUM
,
254 /* If no SVE state exists, then use the existing fpsimd structure to
255 write out state and return. */
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. */
263 for (int i
= 0; i
< AARCH64_SVE_Z_REGS_NUM
; i
++)
266 == reg_buf
->get_register_status (AARCH64_SVE_Z0_REGNUM
+ i
))
268 reg_buf
->raw_collect (AARCH64_SVE_Z0_REGNUM
+ i
, zero_reg
);
269 memcpy (&fpsimd
->vregs
[i
], zero_reg
, sizeof (__int128_t
));
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
);
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
287 header
->flags
|= SVE_PT_REGS_SVE
;
288 header
->size
= SVE_PT_SIZE (vq
, SVE_PT_REGS_SVE
);
290 memcpy (base
+ SVE_PT_SVE_FPSR_OFFSET (vq
), &fpsimd
->fpsr
,
292 memcpy (base
+ SVE_PT_SVE_FPCR_OFFSET (vq
), &fpsimd
->fpcr
,
295 for (int i
= AARCH64_SVE_Z_REGS_NUM
; i
>= 0 ; i
--)
297 memcpy (base
+ SVE_PT_SVE_ZREG_OFFSET (vq
, i
), &fpsimd
->vregs
[i
],
298 sizeof (__int128_t
));
302 /* Replace the kernel values with those from reg_buf. */
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
));
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
));
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
));
This page took 0.03706 seconds and 4 git commands to generate.