]>
Commit | Line | Data |
---|---|---|
9d19df75 MS |
1 | /* Native-dependent code for GNU/Linux AArch64. |
2 | ||
4a94e368 | 3 | Copyright (C) 2011-2022 Free Software Foundation, Inc. |
9d19df75 MS |
4 | Contributed by ARM Ltd. |
5 | ||
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | #include "defs.h" | |
22 | ||
d55e5aa6 | 23 | #include "inferior.h" |
4de283e4 TT |
24 | #include "gdbcore.h" |
25 | #include "regcache.h" | |
d55e5aa6 | 26 | #include "linux-nat.h" |
4de283e4 TT |
27 | #include "target-descriptions.h" |
28 | #include "auxv.h" | |
29 | #include "gdbcmd.h" | |
1570c37c | 30 | #include "aarch64-nat.h" |
4de283e4 TT |
31 | #include "aarch64-tdep.h" |
32 | #include "aarch64-linux-tdep.h" | |
33 | #include "aarch32-linux-nat.h" | |
d105cce5 | 34 | #include "aarch32-tdep.h" |
350fab54 | 35 | #include "arch/arm.h" |
d55e5aa6 | 36 | #include "nat/aarch64-linux.h" |
4de283e4 | 37 | #include "nat/aarch64-linux-hw-point.h" |
ba2d2bb2 | 38 | #include "nat/aarch64-sve-linux-ptrace.h" |
4de283e4 TT |
39 | |
40 | #include "elf/external.h" | |
41 | #include "elf/common.h" | |
42 | ||
5826e159 | 43 | #include "nat/gdb_ptrace.h" |
4de283e4 TT |
44 | #include <sys/utsname.h> |
45 | #include <asm/ptrace.h> | |
46 | ||
47 | #include "gregset.h" | |
48 | #include "linux-tdep.h" | |
9d19df75 | 49 | |
9d19df75 MS |
50 | /* Defines ps_err_e, struct ps_prochandle. */ |
51 | #include "gdb_proc_service.h" | |
4da037ef | 52 | #include "arch-utils.h" |
9d19df75 | 53 | |
04245125 LM |
54 | #include "arch/aarch64-mte-linux.h" |
55 | ||
4601818e LM |
56 | #include "nat/aarch64-mte-linux-ptrace.h" |
57 | ||
9d19df75 MS |
58 | #ifndef TRAP_HWBKPT |
59 | #define TRAP_HWBKPT 0x0004 | |
60 | #endif | |
61 | ||
1570c37c JB |
62 | class aarch64_linux_nat_target final |
63 | : public aarch64_nat_target<linux_nat_target> | |
f6ac5f3d PA |
64 | { |
65 | public: | |
66 | /* Add our register access methods. */ | |
67 | void fetch_registers (struct regcache *, int) override; | |
68 | void store_registers (struct regcache *, int) override; | |
69 | ||
70 | const struct target_desc *read_description () override; | |
71 | ||
72 | /* Add our hardware breakpoint and watchpoint implementation. */ | |
57810aa7 PA |
73 | bool stopped_by_watchpoint () override; |
74 | bool stopped_data_address (CORE_ADDR *) override; | |
f6ac5f3d PA |
75 | |
76 | int can_do_single_step () override; | |
77 | ||
78 | /* Override the GNU/Linux inferior startup hook. */ | |
79 | void post_startup_inferior (ptid_t) override; | |
135340af | 80 | |
8363f9d5 RB |
81 | /* Override the GNU/Linux post attach hook. */ |
82 | void post_attach (int pid) override; | |
83 | ||
135340af PA |
84 | /* These three defer to common nat/ code. */ |
85 | void low_new_thread (struct lwp_info *lp) override | |
86 | { aarch64_linux_new_thread (lp); } | |
87 | void low_delete_thread (struct arch_lwp_info *lp) override | |
88 | { aarch64_linux_delete_thread (lp); } | |
89 | void low_prepare_to_resume (struct lwp_info *lp) override | |
90 | { aarch64_linux_prepare_to_resume (lp); } | |
91 | ||
92 | void low_new_fork (struct lwp_info *parent, pid_t child_pid) override; | |
93 | void low_forget_process (pid_t pid) override; | |
94 | ||
95 | /* Add our siginfo layout converter. */ | |
96 | bool low_siginfo_fixup (siginfo_t *ptrace, gdb_byte *inf, int direction) | |
97 | override; | |
4da037ef AH |
98 | |
99 | struct gdbarch *thread_architecture (ptid_t) override; | |
4601818e LM |
100 | |
101 | bool supports_memory_tagging () override; | |
102 | ||
103 | /* Read memory allocation tags from memory via PTRACE. */ | |
104 | bool fetch_memtags (CORE_ADDR address, size_t len, | |
105 | gdb::byte_vector &tags, int type) override; | |
106 | ||
107 | /* Write allocation tags to memory via PTRACE. */ | |
108 | bool store_memtags (CORE_ADDR address, size_t len, | |
109 | const gdb::byte_vector &tags, int type) override; | |
f6ac5f3d PA |
110 | }; |
111 | ||
112 | static aarch64_linux_nat_target the_aarch64_linux_nat_target; | |
113 | ||
d6c44983 YZ |
114 | /* Called whenever GDB is no longer debugging process PID. It deletes |
115 | data structures that keep track of debug register state. */ | |
9d19df75 | 116 | |
135340af PA |
117 | void |
118 | aarch64_linux_nat_target::low_forget_process (pid_t pid) | |
9d19df75 | 119 | { |
1570c37c | 120 | aarch64_remove_debug_reg_state (pid); |
9d19df75 MS |
121 | } |
122 | ||
9d19df75 MS |
123 | /* Fill GDB's register array with the general-purpose register values |
124 | from the current thread. */ | |
125 | ||
126 | static void | |
127 | fetch_gregs_from_thread (struct regcache *regcache) | |
128 | { | |
607685ec | 129 | int ret, tid; |
ac7936df | 130 | struct gdbarch *gdbarch = regcache->arch (); |
9d19df75 MS |
131 | elf_gregset_t regs; |
132 | struct iovec iovec; | |
133 | ||
607685ec YQ |
134 | /* Make sure REGS can hold all registers contents on both aarch64 |
135 | and arm. */ | |
136 | gdb_static_assert (sizeof (regs) >= 18 * 4); | |
137 | ||
e38504b3 | 138 | tid = regcache->ptid ().lwp (); |
9d19df75 MS |
139 | |
140 | iovec.iov_base = ®s; | |
607685ec YQ |
141 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) |
142 | iovec.iov_len = 18 * 4; | |
143 | else | |
144 | iovec.iov_len = sizeof (regs); | |
9d19df75 MS |
145 | |
146 | ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec); | |
147 | if (ret < 0) | |
148 | perror_with_name (_("Unable to fetch general registers.")); | |
149 | ||
607685ec YQ |
150 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) |
151 | aarch32_gp_regcache_supply (regcache, (uint32_t *) regs, 1); | |
152 | else | |
153 | { | |
154 | int regno; | |
155 | ||
156 | for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++) | |
73e1c03f | 157 | regcache->raw_supply (regno, ®s[regno - AARCH64_X0_REGNUM]); |
607685ec | 158 | } |
9d19df75 MS |
159 | } |
160 | ||
161 | /* Store to the current thread the valid general-purpose register | |
162 | values in the GDB's register array. */ | |
163 | ||
164 | static void | |
165 | store_gregs_to_thread (const struct regcache *regcache) | |
166 | { | |
607685ec | 167 | int ret, tid; |
9d19df75 MS |
168 | elf_gregset_t regs; |
169 | struct iovec iovec; | |
ac7936df | 170 | struct gdbarch *gdbarch = regcache->arch (); |
9d19df75 | 171 | |
607685ec YQ |
172 | /* Make sure REGS can hold all registers contents on both aarch64 |
173 | and arm. */ | |
174 | gdb_static_assert (sizeof (regs) >= 18 * 4); | |
e38504b3 | 175 | tid = regcache->ptid ().lwp (); |
9d19df75 MS |
176 | |
177 | iovec.iov_base = ®s; | |
607685ec YQ |
178 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) |
179 | iovec.iov_len = 18 * 4; | |
180 | else | |
181 | iovec.iov_len = sizeof (regs); | |
9d19df75 MS |
182 | |
183 | ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec); | |
184 | if (ret < 0) | |
185 | perror_with_name (_("Unable to fetch general registers.")); | |
186 | ||
607685ec YQ |
187 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) |
188 | aarch32_gp_regcache_collect (regcache, (uint32_t *) regs, 1); | |
189 | else | |
190 | { | |
191 | int regno; | |
192 | ||
193 | for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++) | |
0ec9f114 | 194 | if (REG_VALID == regcache->get_register_status (regno)) |
34a79281 | 195 | regcache->raw_collect (regno, ®s[regno - AARCH64_X0_REGNUM]); |
607685ec | 196 | } |
9d19df75 MS |
197 | |
198 | ret = ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, &iovec); | |
199 | if (ret < 0) | |
200 | perror_with_name (_("Unable to store general registers.")); | |
201 | } | |
202 | ||
203 | /* Fill GDB's register array with the fp/simd register values | |
204 | from the current thread. */ | |
205 | ||
206 | static void | |
207 | fetch_fpregs_from_thread (struct regcache *regcache) | |
208 | { | |
607685ec | 209 | int ret, tid; |
9d19df75 MS |
210 | elf_fpregset_t regs; |
211 | struct iovec iovec; | |
ac7936df | 212 | struct gdbarch *gdbarch = regcache->arch (); |
607685ec YQ |
213 | |
214 | /* Make sure REGS can hold all VFP registers contents on both aarch64 | |
215 | and arm. */ | |
350fab54 | 216 | gdb_static_assert (sizeof regs >= ARM_VFP3_REGS_SIZE); |
9d19df75 | 217 | |
e38504b3 | 218 | tid = regcache->ptid ().lwp (); |
9d19df75 MS |
219 | |
220 | iovec.iov_base = ®s; | |
9d19df75 | 221 | |
607685ec YQ |
222 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) |
223 | { | |
350fab54 | 224 | iovec.iov_len = ARM_VFP3_REGS_SIZE; |
607685ec YQ |
225 | |
226 | ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec); | |
227 | if (ret < 0) | |
228 | perror_with_name (_("Unable to fetch VFP registers.")); | |
229 | ||
230 | aarch32_vfp_regcache_supply (regcache, (gdb_byte *) ®s, 32); | |
231 | } | |
232 | else | |
233 | { | |
234 | int regno; | |
235 | ||
236 | iovec.iov_len = sizeof (regs); | |
9d19df75 | 237 | |
607685ec YQ |
238 | ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec); |
239 | if (ret < 0) | |
240 | perror_with_name (_("Unable to fetch vFP/SIMD registers.")); | |
9d19df75 | 241 | |
607685ec | 242 | for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++) |
73e1c03f | 243 | regcache->raw_supply (regno, ®s.vregs[regno - AARCH64_V0_REGNUM]); |
607685ec | 244 | |
73e1c03f SM |
245 | regcache->raw_supply (AARCH64_FPSR_REGNUM, ®s.fpsr); |
246 | regcache->raw_supply (AARCH64_FPCR_REGNUM, ®s.fpcr); | |
607685ec | 247 | } |
9d19df75 MS |
248 | } |
249 | ||
250 | /* Store to the current thread the valid fp/simd register | |
251 | values in the GDB's register array. */ | |
252 | ||
253 | static void | |
254 | store_fpregs_to_thread (const struct regcache *regcache) | |
255 | { | |
607685ec | 256 | int ret, tid; |
9d19df75 MS |
257 | elf_fpregset_t regs; |
258 | struct iovec iovec; | |
ac7936df | 259 | struct gdbarch *gdbarch = regcache->arch (); |
9d19df75 | 260 | |
607685ec YQ |
261 | /* Make sure REGS can hold all VFP registers contents on both aarch64 |
262 | and arm. */ | |
350fab54 | 263 | gdb_static_assert (sizeof regs >= ARM_VFP3_REGS_SIZE); |
e38504b3 | 264 | tid = regcache->ptid ().lwp (); |
9d19df75 MS |
265 | |
266 | iovec.iov_base = ®s; | |
9d19df75 | 267 | |
607685ec YQ |
268 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) |
269 | { | |
350fab54 | 270 | iovec.iov_len = ARM_VFP3_REGS_SIZE; |
9d19df75 | 271 | |
607685ec YQ |
272 | ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec); |
273 | if (ret < 0) | |
274 | perror_with_name (_("Unable to fetch VFP registers.")); | |
9d19df75 | 275 | |
607685ec YQ |
276 | aarch32_vfp_regcache_collect (regcache, (gdb_byte *) ®s, 32); |
277 | } | |
278 | else | |
279 | { | |
280 | int regno; | |
9d19df75 | 281 | |
607685ec YQ |
282 | iovec.iov_len = sizeof (regs); |
283 | ||
284 | ret = ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec); | |
285 | if (ret < 0) | |
286 | perror_with_name (_("Unable to fetch FP/SIMD registers.")); | |
287 | ||
288 | for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++) | |
0ec9f114 | 289 | if (REG_VALID == regcache->get_register_status (regno)) |
34a79281 SM |
290 | regcache->raw_collect |
291 | (regno, (char *) ®s.vregs[regno - AARCH64_V0_REGNUM]); | |
607685ec | 292 | |
0ec9f114 | 293 | if (REG_VALID == regcache->get_register_status (AARCH64_FPSR_REGNUM)) |
34a79281 | 294 | regcache->raw_collect (AARCH64_FPSR_REGNUM, (char *) ®s.fpsr); |
0ec9f114 | 295 | if (REG_VALID == regcache->get_register_status (AARCH64_FPCR_REGNUM)) |
34a79281 | 296 | regcache->raw_collect (AARCH64_FPCR_REGNUM, (char *) ®s.fpcr); |
607685ec YQ |
297 | } |
298 | ||
299 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) | |
300 | { | |
301 | ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_VFP, &iovec); | |
302 | if (ret < 0) | |
303 | perror_with_name (_("Unable to store VFP registers.")); | |
304 | } | |
305 | else | |
306 | { | |
307 | ret = ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, &iovec); | |
308 | if (ret < 0) | |
309 | perror_with_name (_("Unable to store FP/SIMD registers.")); | |
310 | } | |
9d19df75 MS |
311 | } |
312 | ||
e9902bfc AH |
313 | /* Fill GDB's register array with the sve register values |
314 | from the current thread. */ | |
315 | ||
316 | static void | |
317 | fetch_sveregs_from_thread (struct regcache *regcache) | |
318 | { | |
319 | std::unique_ptr<gdb_byte[]> base | |
e38504b3 | 320 | = aarch64_sve_get_sveregs (regcache->ptid ().lwp ()); |
e9902bfc AH |
321 | aarch64_sve_regs_copy_to_reg_buf (regcache, base.get ()); |
322 | } | |
323 | ||
324 | /* Store to the current thread the valid sve register | |
325 | values in the GDB's register array. */ | |
326 | ||
327 | static void | |
328 | store_sveregs_to_thread (struct regcache *regcache) | |
329 | { | |
330 | int ret; | |
331 | struct iovec iovec; | |
e38504b3 | 332 | int tid = regcache->ptid ().lwp (); |
e9902bfc | 333 | |
48574d91 AH |
334 | /* First store vector length to the thread. This is done first to ensure the |
335 | ptrace buffers read from the kernel are the correct size. */ | |
336 | if (!aarch64_sve_set_vq (tid, regcache)) | |
337 | perror_with_name (_("Unable to set VG register.")); | |
338 | ||
e9902bfc AH |
339 | /* Obtain a dump of SVE registers from ptrace. */ |
340 | std::unique_ptr<gdb_byte[]> base = aarch64_sve_get_sveregs (tid); | |
341 | ||
342 | /* Overwrite with regcache state. */ | |
343 | aarch64_sve_regs_copy_from_reg_buf (regcache, base.get ()); | |
344 | ||
345 | /* Write back to the kernel. */ | |
346 | iovec.iov_base = base.get (); | |
347 | iovec.iov_len = ((struct user_sve_header *) base.get ())->size; | |
348 | ret = ptrace (PTRACE_SETREGSET, tid, NT_ARM_SVE, &iovec); | |
349 | ||
350 | if (ret < 0) | |
351 | perror_with_name (_("Unable to store sve registers")); | |
352 | } | |
353 | ||
76bed0fd AH |
354 | /* Fill GDB's register array with the pointer authentication mask values from |
355 | the current thread. */ | |
356 | ||
357 | static void | |
358 | fetch_pauth_masks_from_thread (struct regcache *regcache) | |
359 | { | |
aa70a99e SM |
360 | aarch64_gdbarch_tdep *tdep |
361 | = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); | |
76bed0fd AH |
362 | int ret; |
363 | struct iovec iovec; | |
364 | uint64_t pauth_regset[2] = {0, 0}; | |
365 | int tid = regcache->ptid ().lwp (); | |
366 | ||
367 | iovec.iov_base = &pauth_regset; | |
368 | iovec.iov_len = sizeof (pauth_regset); | |
369 | ||
370 | ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_PAC_MASK, &iovec); | |
371 | if (ret != 0) | |
372 | perror_with_name (_("unable to fetch pauth registers.")); | |
373 | ||
374 | regcache->raw_supply (AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base), | |
375 | &pauth_regset[0]); | |
376 | regcache->raw_supply (AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base), | |
377 | &pauth_regset[1]); | |
378 | } | |
379 | ||
5e984dbf LM |
380 | /* Fill GDB's register array with the MTE register values from |
381 | the current thread. */ | |
382 | ||
383 | static void | |
384 | fetch_mteregs_from_thread (struct regcache *regcache) | |
385 | { | |
aa70a99e SM |
386 | aarch64_gdbarch_tdep *tdep |
387 | = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); | |
5e984dbf LM |
388 | int regno = tdep->mte_reg_base; |
389 | ||
390 | gdb_assert (regno != -1); | |
391 | ||
392 | uint64_t tag_ctl = 0; | |
393 | struct iovec iovec; | |
394 | ||
395 | iovec.iov_base = &tag_ctl; | |
396 | iovec.iov_len = sizeof (tag_ctl); | |
397 | ||
398 | int tid = get_ptrace_pid (regcache->ptid ()); | |
399 | if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL, &iovec) != 0) | |
400 | perror_with_name (_("unable to fetch MTE registers.")); | |
401 | ||
402 | regcache->raw_supply (regno, &tag_ctl); | |
403 | } | |
404 | ||
405 | /* Store to the current thread the valid MTE register set in the GDB's | |
406 | register array. */ | |
407 | ||
408 | static void | |
409 | store_mteregs_to_thread (struct regcache *regcache) | |
410 | { | |
aa70a99e SM |
411 | aarch64_gdbarch_tdep *tdep |
412 | = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); | |
5e984dbf LM |
413 | int regno = tdep->mte_reg_base; |
414 | ||
415 | gdb_assert (regno != -1); | |
416 | ||
417 | uint64_t tag_ctl = 0; | |
418 | ||
419 | if (REG_VALID != regcache->get_register_status (regno)) | |
420 | return; | |
421 | ||
422 | regcache->raw_collect (regno, (char *) &tag_ctl); | |
423 | ||
424 | struct iovec iovec; | |
425 | ||
426 | iovec.iov_base = &tag_ctl; | |
427 | iovec.iov_len = sizeof (tag_ctl); | |
428 | ||
429 | int tid = get_ptrace_pid (regcache->ptid ()); | |
430 | if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_TAGGED_ADDR_CTRL, &iovec) != 0) | |
431 | perror_with_name (_("unable to store MTE registers.")); | |
432 | } | |
433 | ||
f6ac5f3d | 434 | /* Implement the "fetch_registers" target_ops method. */ |
9d19df75 | 435 | |
f6ac5f3d PA |
436 | void |
437 | aarch64_linux_nat_target::fetch_registers (struct regcache *regcache, | |
438 | int regno) | |
9d19df75 | 439 | { |
aa70a99e SM |
440 | aarch64_gdbarch_tdep *tdep |
441 | = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); | |
e9902bfc | 442 | |
9d19df75 MS |
443 | if (regno == -1) |
444 | { | |
445 | fetch_gregs_from_thread (regcache); | |
e9902bfc AH |
446 | if (tdep->has_sve ()) |
447 | fetch_sveregs_from_thread (regcache); | |
448 | else | |
449 | fetch_fpregs_from_thread (regcache); | |
76bed0fd AH |
450 | |
451 | if (tdep->has_pauth ()) | |
452 | fetch_pauth_masks_from_thread (regcache); | |
5e984dbf LM |
453 | |
454 | if (tdep->has_mte ()) | |
455 | fetch_mteregs_from_thread (regcache); | |
9d19df75 MS |
456 | } |
457 | else if (regno < AARCH64_V0_REGNUM) | |
458 | fetch_gregs_from_thread (regcache); | |
e9902bfc AH |
459 | else if (tdep->has_sve ()) |
460 | fetch_sveregs_from_thread (regcache); | |
9d19df75 MS |
461 | else |
462 | fetch_fpregs_from_thread (regcache); | |
76bed0fd AH |
463 | |
464 | if (tdep->has_pauth ()) | |
465 | { | |
466 | if (regno == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base) | |
467 | || regno == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base)) | |
468 | fetch_pauth_masks_from_thread (regcache); | |
469 | } | |
5e984dbf LM |
470 | |
471 | /* Fetch individual MTE registers. */ | |
472 | if (tdep->has_mte () | |
473 | && (regno == tdep->mte_reg_base)) | |
474 | fetch_mteregs_from_thread (regcache); | |
9d19df75 MS |
475 | } |
476 | ||
f6ac5f3d | 477 | /* Implement the "store_registers" target_ops method. */ |
9d19df75 | 478 | |
f6ac5f3d PA |
479 | void |
480 | aarch64_linux_nat_target::store_registers (struct regcache *regcache, | |
481 | int regno) | |
9d19df75 | 482 | { |
aa70a99e SM |
483 | aarch64_gdbarch_tdep *tdep |
484 | = (aarch64_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); | |
e9902bfc | 485 | |
9d19df75 MS |
486 | if (regno == -1) |
487 | { | |
488 | store_gregs_to_thread (regcache); | |
e9902bfc AH |
489 | if (tdep->has_sve ()) |
490 | store_sveregs_to_thread (regcache); | |
491 | else | |
492 | store_fpregs_to_thread (regcache); | |
5e984dbf LM |
493 | |
494 | if (tdep->has_mte ()) | |
495 | store_mteregs_to_thread (regcache); | |
9d19df75 MS |
496 | } |
497 | else if (regno < AARCH64_V0_REGNUM) | |
498 | store_gregs_to_thread (regcache); | |
e9902bfc AH |
499 | else if (tdep->has_sve ()) |
500 | store_sveregs_to_thread (regcache); | |
9d19df75 MS |
501 | else |
502 | store_fpregs_to_thread (regcache); | |
5e984dbf LM |
503 | |
504 | /* Store MTE registers. */ | |
505 | if (tdep->has_mte () | |
506 | && (regno == tdep->mte_reg_base)) | |
507 | store_mteregs_to_thread (regcache); | |
9d19df75 MS |
508 | } |
509 | ||
510 | /* Fill register REGNO (if it is a general-purpose register) in | |
511 | *GREGSETPS with the value in GDB's register array. If REGNO is -1, | |
512 | do this for all registers. */ | |
513 | ||
514 | void | |
515 | fill_gregset (const struct regcache *regcache, | |
516 | gdb_gregset_t *gregsetp, int regno) | |
517 | { | |
d4d793bf AA |
518 | regcache_collect_regset (&aarch64_linux_gregset, regcache, |
519 | regno, (gdb_byte *) gregsetp, | |
520 | AARCH64_LINUX_SIZEOF_GREGSET); | |
9d19df75 MS |
521 | } |
522 | ||
523 | /* Fill GDB's register array with the general-purpose register values | |
524 | in *GREGSETP. */ | |
525 | ||
526 | void | |
527 | supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp) | |
528 | { | |
d4d793bf AA |
529 | regcache_supply_regset (&aarch64_linux_gregset, regcache, -1, |
530 | (const gdb_byte *) gregsetp, | |
531 | AARCH64_LINUX_SIZEOF_GREGSET); | |
9d19df75 MS |
532 | } |
533 | ||
534 | /* Fill register REGNO (if it is a floating-point register) in | |
535 | *FPREGSETP with the value in GDB's register array. If REGNO is -1, | |
536 | do this for all registers. */ | |
537 | ||
538 | void | |
539 | fill_fpregset (const struct regcache *regcache, | |
540 | gdb_fpregset_t *fpregsetp, int regno) | |
541 | { | |
d4d793bf AA |
542 | regcache_collect_regset (&aarch64_linux_fpregset, regcache, |
543 | regno, (gdb_byte *) fpregsetp, | |
544 | AARCH64_LINUX_SIZEOF_FPREGSET); | |
9d19df75 MS |
545 | } |
546 | ||
547 | /* Fill GDB's register array with the floating-point register values | |
548 | in *FPREGSETP. */ | |
549 | ||
550 | void | |
551 | supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp) | |
552 | { | |
d4d793bf AA |
553 | regcache_supply_regset (&aarch64_linux_fpregset, regcache, -1, |
554 | (const gdb_byte *) fpregsetp, | |
555 | AARCH64_LINUX_SIZEOF_FPREGSET); | |
9d19df75 MS |
556 | } |
557 | ||
d6c44983 YZ |
558 | /* linux_nat_new_fork hook. */ |
559 | ||
135340af PA |
560 | void |
561 | aarch64_linux_nat_target::low_new_fork (struct lwp_info *parent, | |
562 | pid_t child_pid) | |
d6c44983 YZ |
563 | { |
564 | pid_t parent_pid; | |
565 | struct aarch64_debug_reg_state *parent_state; | |
566 | struct aarch64_debug_reg_state *child_state; | |
567 | ||
568 | /* NULL means no watchpoint has ever been set in the parent. In | |
569 | that case, there's nothing to do. */ | |
570 | if (parent->arch_private == NULL) | |
571 | return; | |
572 | ||
573 | /* GDB core assumes the child inherits the watchpoints/hw | |
574 | breakpoints of the parent, and will remove them all from the | |
575 | forked off process. Copy the debug registers mirrors into the | |
576 | new process so that all breakpoints and watchpoints can be | |
577 | removed together. */ | |
578 | ||
e99b03dc | 579 | parent_pid = parent->ptid.pid (); |
d6c44983 YZ |
580 | parent_state = aarch64_get_debug_reg_state (parent_pid); |
581 | child_state = aarch64_get_debug_reg_state (child_pid); | |
582 | *child_state = *parent_state; | |
583 | } | |
9d19df75 MS |
584 | \f |
585 | ||
586 | /* Called by libthread_db. Returns a pointer to the thread local | |
587 | storage (or its descriptor). */ | |
588 | ||
589 | ps_err_e | |
754653a7 | 590 | ps_get_thread_area (struct ps_prochandle *ph, |
9d19df75 MS |
591 | lwpid_t lwpid, int idx, void **base) |
592 | { | |
a0cc84cd YQ |
593 | int is_64bit_p |
594 | = (gdbarch_bfd_arch_info (target_gdbarch ())->bits_per_word == 64); | |
9d19df75 | 595 | |
a0cc84cd | 596 | return aarch64_ps_get_thread_area (ph, lwpid, idx, base, is_64bit_p); |
9d19df75 MS |
597 | } |
598 | \f | |
599 | ||
200fd287 | 600 | /* Implement the virtual inf_ptrace_target::post_startup_inferior method. */ |
9d19df75 | 601 | |
f6ac5f3d PA |
602 | void |
603 | aarch64_linux_nat_target::post_startup_inferior (ptid_t ptid) | |
9d19df75 | 604 | { |
e99b03dc TT |
605 | low_forget_process (ptid.pid ()); |
606 | aarch64_linux_get_debug_reg_capacity (ptid.pid ()); | |
f6ac5f3d | 607 | linux_nat_target::post_startup_inferior (ptid); |
9d19df75 MS |
608 | } |
609 | ||
8363f9d5 RB |
610 | /* Implement the "post_attach" target_ops method. */ |
611 | ||
612 | void | |
613 | aarch64_linux_nat_target::post_attach (int pid) | |
614 | { | |
615 | low_forget_process (pid); | |
616 | /* Set the hardware debug register capacity. If | |
617 | aarch64_linux_get_debug_reg_capacity is not called | |
618 | (as it is in aarch64_linux_child_post_startup_inferior) then | |
619 | software watchpoints will be used instead of hardware | |
620 | watchpoints when attaching to a target. */ | |
621 | aarch64_linux_get_debug_reg_capacity (pid); | |
622 | linux_nat_target::post_attach (pid); | |
623 | } | |
624 | ||
f6ac5f3d | 625 | /* Implement the "read_description" target_ops method. */ |
9d19df75 | 626 | |
f6ac5f3d PA |
627 | const struct target_desc * |
628 | aarch64_linux_nat_target::read_description () | |
9d19df75 | 629 | { |
6f67973b | 630 | int ret, tid; |
350fab54 | 631 | gdb_byte regbuf[ARM_VFP3_REGS_SIZE]; |
6f67973b | 632 | struct iovec iovec; |
607685ec | 633 | |
fbf3c4b9 | 634 | tid = inferior_ptid.pid (); |
607685ec | 635 | |
6f67973b | 636 | iovec.iov_base = regbuf; |
350fab54 | 637 | iovec.iov_len = ARM_VFP3_REGS_SIZE; |
607685ec | 638 | |
6f67973b YQ |
639 | ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_VFP, &iovec); |
640 | if (ret == 0) | |
d105cce5 | 641 | return aarch32_read_description (); |
6dc0ebde | 642 | |
0f83012e | 643 | CORE_ADDR hwcap = linux_get_hwcap (this); |
c1bd443b | 644 | CORE_ADDR hwcap2 = linux_get_hwcap2 (this); |
ee4fbcfa | 645 | |
c1bd443b LM |
646 | bool pauth_p = hwcap & AARCH64_HWCAP_PACA; |
647 | bool mte_p = hwcap2 & HWCAP2_MTE; | |
648 | ||
649 | return aarch64_read_description (aarch64_sve_get_vq (tid), pauth_p, mte_p); | |
9d19df75 MS |
650 | } |
651 | ||
ade90bde YQ |
652 | /* Convert a native/host siginfo object, into/from the siginfo in the |
653 | layout of the inferiors' architecture. Returns true if any | |
654 | conversion was done; false otherwise. If DIRECTION is 1, then copy | |
655 | from INF to NATIVE. If DIRECTION is 0, copy from NATIVE to | |
656 | INF. */ | |
657 | ||
135340af PA |
658 | bool |
659 | aarch64_linux_nat_target::low_siginfo_fixup (siginfo_t *native, gdb_byte *inf, | |
660 | int direction) | |
ade90bde YQ |
661 | { |
662 | struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); | |
663 | ||
664 | /* Is the inferior 32-bit? If so, then do fixup the siginfo | |
665 | object. */ | |
666 | if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) | |
667 | { | |
668 | if (direction == 0) | |
669 | aarch64_compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, | |
670 | native); | |
671 | else | |
672 | aarch64_siginfo_from_compat_siginfo (native, | |
673 | (struct compat_siginfo *) inf); | |
674 | ||
135340af | 675 | return true; |
ade90bde YQ |
676 | } |
677 | ||
135340af | 678 | return false; |
ade90bde YQ |
679 | } |
680 | ||
f6ac5f3d | 681 | /* Implement the "stopped_data_address" target_ops method. */ |
9d19df75 | 682 | |
57810aa7 | 683 | bool |
f6ac5f3d | 684 | aarch64_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p) |
9d19df75 MS |
685 | { |
686 | siginfo_t siginfo; | |
9d19df75 MS |
687 | struct aarch64_debug_reg_state *state; |
688 | ||
689 | if (!linux_nat_get_siginfo (inferior_ptid, &siginfo)) | |
57810aa7 | 690 | return false; |
9d19df75 MS |
691 | |
692 | /* This must be a hardware breakpoint. */ | |
693 | if (siginfo.si_signo != SIGTRAP | |
694 | || (siginfo.si_code & 0xffff) != TRAP_HWBKPT) | |
57810aa7 | 695 | return false; |
9d19df75 | 696 | |
19007d95 LM |
697 | /* Make sure to ignore the top byte, otherwise we may not recognize a |
698 | hardware watchpoint hit. The stopped data addresses coming from the | |
699 | kernel can potentially be tagged addresses. */ | |
700 | struct gdbarch *gdbarch = thread_architecture (inferior_ptid); | |
701 | const CORE_ADDR addr_trap | |
702 | = address_significant (gdbarch, (CORE_ADDR) siginfo.si_addr); | |
703 | ||
9d19df75 | 704 | /* Check if the address matches any watched address. */ |
e99b03dc | 705 | state = aarch64_get_debug_reg_state (inferior_ptid.pid ()); |
1570c37c | 706 | return aarch64_stopped_data_address (state, addr_trap, addr_p); |
9d19df75 MS |
707 | } |
708 | ||
f6ac5f3d | 709 | /* Implement the "stopped_by_watchpoint" target_ops method. */ |
9d19df75 | 710 | |
57810aa7 | 711 | bool |
f6ac5f3d | 712 | aarch64_linux_nat_target::stopped_by_watchpoint () |
9d19df75 MS |
713 | { |
714 | CORE_ADDR addr; | |
715 | ||
f6ac5f3d | 716 | return stopped_data_address (&addr); |
9d19df75 MS |
717 | } |
718 | ||
f6ac5f3d | 719 | /* Implement the "can_do_single_step" target_ops method. */ |
750ce8d1 | 720 | |
f6ac5f3d PA |
721 | int |
722 | aarch64_linux_nat_target::can_do_single_step () | |
750ce8d1 YQ |
723 | { |
724 | return 1; | |
725 | } | |
726 | ||
4da037ef AH |
727 | /* Implement the "thread_architecture" target_ops method. */ |
728 | ||
729 | struct gdbarch * | |
730 | aarch64_linux_nat_target::thread_architecture (ptid_t ptid) | |
731 | { | |
732 | /* Return the gdbarch for the current thread. If the vector length has | |
733 | changed since the last time this was called, then do a further lookup. */ | |
734 | ||
735 | uint64_t vq = aarch64_sve_get_vq (ptid.lwp ()); | |
736 | ||
737 | /* Find the current gdbarch the same way as process_stratum_target. Only | |
738 | return it if the current vector length matches the one in the tdep. */ | |
5b6d1e4f | 739 | inferior *inf = find_inferior_ptid (this, ptid); |
4da037ef | 740 | gdb_assert (inf != NULL); |
aa70a99e SM |
741 | aarch64_gdbarch_tdep *tdep |
742 | = (aarch64_gdbarch_tdep *) gdbarch_tdep (inf->gdbarch); | |
743 | if (vq == tdep->vq) | |
4da037ef AH |
744 | return inf->gdbarch; |
745 | ||
746 | /* We reach here if the vector length for the thread is different from its | |
747 | value at process start. Lookup gdbarch via info (potentially creating a | |
748 | new one), stashing the vector length inside id. Use -1 for when SVE | |
749 | unavailable, to distinguish from an unset value of 0. */ | |
750 | struct gdbarch_info info; | |
6a5206eb | 751 | info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64); |
4da037ef AH |
752 | info.id = (int *) (vq == 0 ? -1 : vq); |
753 | return gdbarch_find_by_info (info); | |
754 | } | |
755 | ||
4601818e LM |
756 | /* Implement the "supports_memory_tagging" target_ops method. */ |
757 | ||
758 | bool | |
759 | aarch64_linux_nat_target::supports_memory_tagging () | |
760 | { | |
761 | return (linux_get_hwcap2 (this) & HWCAP2_MTE) != 0; | |
762 | } | |
763 | ||
764 | /* Implement the "fetch_memtags" target_ops method. */ | |
765 | ||
766 | bool | |
767 | aarch64_linux_nat_target::fetch_memtags (CORE_ADDR address, size_t len, | |
768 | gdb::byte_vector &tags, int type) | |
769 | { | |
770 | int tid = get_ptrace_pid (inferior_ptid); | |
771 | ||
772 | /* Allocation tags? */ | |
773 | if (type == static_cast<int> (aarch64_memtag_type::mte_allocation)) | |
774 | return aarch64_mte_fetch_memtags (tid, address, len, tags); | |
775 | ||
776 | return false; | |
777 | } | |
778 | ||
779 | /* Implement the "store_memtags" target_ops method. */ | |
780 | ||
781 | bool | |
782 | aarch64_linux_nat_target::store_memtags (CORE_ADDR address, size_t len, | |
783 | const gdb::byte_vector &tags, int type) | |
784 | { | |
785 | int tid = get_ptrace_pid (inferior_ptid); | |
786 | ||
787 | /* Allocation tags? */ | |
788 | if (type == static_cast<int> (aarch64_memtag_type::mte_allocation)) | |
789 | return aarch64_mte_store_memtags (tid, address, len, tags); | |
790 | ||
791 | return false; | |
792 | } | |
793 | ||
6c265988 | 794 | void _initialize_aarch64_linux_nat (); |
9d19df75 | 795 | void |
6c265988 | 796 | _initialize_aarch64_linux_nat () |
9d19df75 | 797 | { |
1570c37c | 798 | aarch64_initialize_hw_point (); |
9d19df75 | 799 | |
9d19df75 | 800 | /* Register the target. */ |
f6ac5f3d | 801 | linux_target = &the_aarch64_linux_nat_target; |
d9f719f1 | 802 | add_inf_child_target (&the_aarch64_linux_nat_target); |
9d19df75 | 803 | } |