Add translations for various sub-directories
[binutils-gdb.git] / gdb / nat / aarch64-linux.c
blob5a95f22a6fce974d44437dfbc779ca7b0af67308
1 /* Copyright (C) 2009-2024 Free Software Foundation, Inc.
2 Contributed by ARM Ltd.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "gdbsupport/break-common.h"
20 #include "nat/linux-nat.h"
21 #include "nat/aarch64-linux-hw-point.h"
22 #include "nat/aarch64-linux.h"
24 #include "elf/common.h"
25 #include "nat/gdb_ptrace.h"
26 #include <asm/ptrace.h>
27 #include <sys/uio.h>
29 /* Called when resuming a thread LWP.
30 The hardware debug registers are updated when there is any change. */
32 void
33 aarch64_linux_prepare_to_resume (struct lwp_info *lwp)
35 struct arch_lwp_info *info = lwp_arch_private_info (lwp);
37 /* NULL means this is the main thread still going through the shell,
38 or, no watchpoint has been set yet. In that case, there's
39 nothing to do. */
40 if (info == NULL)
41 return;
43 if (DR_HAS_CHANGED (info->dr_changed_bp)
44 || DR_HAS_CHANGED (info->dr_changed_wp))
46 ptid_t ptid = ptid_of_lwp (lwp);
47 int tid = ptid.lwp ();
48 struct aarch64_debug_reg_state *state
49 = aarch64_get_debug_reg_state (ptid.pid ());
51 if (show_debug_regs)
52 debug_printf ("prepare_to_resume thread %d\n", tid);
54 /* Watchpoints. */
55 if (DR_HAS_CHANGED (info->dr_changed_wp))
57 aarch64_linux_set_debug_regs (state, tid, 1);
58 DR_CLEAR_CHANGED (info->dr_changed_wp);
61 /* Breakpoints. */
62 if (DR_HAS_CHANGED (info->dr_changed_bp))
64 aarch64_linux_set_debug_regs (state, tid, 0);
65 DR_CLEAR_CHANGED (info->dr_changed_bp);
70 /* Function to call when a new thread is detected. */
72 void
73 aarch64_linux_new_thread (struct lwp_info *lwp)
75 ptid_t ptid = ptid_of_lwp (lwp);
76 struct aarch64_debug_reg_state *state
77 = aarch64_get_debug_reg_state (ptid.pid ());
78 struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
80 /* If there are hardware breakpoints/watchpoints in the process then mark that
81 all the hardware breakpoint/watchpoint register pairs for this thread need
82 to be initialized (with data from aarch_process_info.debug_reg_state). */
83 if (aarch64_any_set_debug_regs_state (state, false))
84 DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs);
85 if (aarch64_any_set_debug_regs_state (state, true))
86 DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs);
88 lwp_set_arch_private_info (lwp, info);
91 /* See nat/aarch64-linux.h. */
93 void
94 aarch64_linux_delete_thread (struct arch_lwp_info *arch_lwp)
96 xfree (arch_lwp);
99 /* Convert native siginfo FROM to the siginfo in the layout of the
100 inferior's architecture TO. */
102 void
103 aarch64_compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from)
105 memset (to, 0, sizeof (*to));
107 to->si_signo = from->si_signo;
108 to->si_errno = from->si_errno;
109 to->si_code = from->si_code;
111 if (to->si_code == SI_TIMER)
113 to->cpt_si_timerid = from->si_timerid;
114 to->cpt_si_overrun = from->si_overrun;
115 to->cpt_si_ptr = (intptr_t) from->si_ptr;
117 else if (to->si_code == SI_USER)
119 to->cpt_si_pid = from->si_pid;
120 to->cpt_si_uid = from->si_uid;
122 else if (to->si_code < 0)
124 to->cpt_si_pid = from->si_pid;
125 to->cpt_si_uid = from->si_uid;
126 to->cpt_si_ptr = (intptr_t) from->si_ptr;
128 else
130 switch (to->si_signo)
132 case SIGCHLD:
133 to->cpt_si_pid = from->si_pid;
134 to->cpt_si_uid = from->si_uid;
135 to->cpt_si_status = from->si_status;
136 to->cpt_si_utime = from->si_utime;
137 to->cpt_si_stime = from->si_stime;
138 break;
139 case SIGILL:
140 case SIGFPE:
141 case SIGSEGV:
142 case SIGBUS:
143 to->cpt_si_addr = (intptr_t) from->si_addr;
144 break;
145 case SIGPOLL:
146 to->cpt_si_band = from->si_band;
147 to->cpt_si_fd = from->si_fd;
148 break;
149 default:
150 to->cpt_si_pid = from->si_pid;
151 to->cpt_si_uid = from->si_uid;
152 to->cpt_si_ptr = (intptr_t) from->si_ptr;
153 break;
158 /* Convert inferior's architecture siginfo FROM to native siginfo TO. */
160 void
161 aarch64_siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
163 memset (to, 0, sizeof (*to));
165 to->si_signo = from->si_signo;
166 to->si_errno = from->si_errno;
167 to->si_code = from->si_code;
169 if (to->si_code == SI_TIMER)
171 to->si_timerid = from->cpt_si_timerid;
172 to->si_overrun = from->cpt_si_overrun;
173 to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
175 else if (to->si_code == SI_USER)
177 to->si_pid = from->cpt_si_pid;
178 to->si_uid = from->cpt_si_uid;
180 if (to->si_code < 0)
182 to->si_pid = from->cpt_si_pid;
183 to->si_uid = from->cpt_si_uid;
184 to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
186 else
188 switch (to->si_signo)
190 case SIGCHLD:
191 to->si_pid = from->cpt_si_pid;
192 to->si_uid = from->cpt_si_uid;
193 to->si_status = from->cpt_si_status;
194 to->si_utime = from->cpt_si_utime;
195 to->si_stime = from->cpt_si_stime;
196 break;
197 case SIGILL:
198 case SIGFPE:
199 case SIGSEGV:
200 case SIGBUS:
201 to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
202 break;
203 case SIGPOLL:
204 to->si_band = from->cpt_si_band;
205 to->si_fd = from->cpt_si_fd;
206 break;
207 default:
208 to->si_pid = from->cpt_si_pid;
209 to->si_uid = from->cpt_si_uid;
210 to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr;
211 break;
216 /* Called by libthread_db. Returns a pointer to the thread local
217 storage (or its descriptor). */
219 ps_err_e
220 aarch64_ps_get_thread_area (struct ps_prochandle *ph,
221 lwpid_t lwpid, int idx, void **base,
222 int is_64bit_p)
224 struct iovec iovec;
225 uint64_t reg64;
226 uint32_t reg32;
228 if (is_64bit_p)
230 iovec.iov_base = &reg64;
231 iovec.iov_len = sizeof (reg64);
233 else
235 iovec.iov_base = &reg32;
236 iovec.iov_len = sizeof (reg32);
239 if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
240 return PS_ERR;
242 /* IDX is the bias from the thread pointer to the beginning of the
243 thread descriptor. It has to be subtracted due to implementation
244 quirks in libthread_db. */
245 if (is_64bit_p)
246 *base = (void *) (reg64 - idx);
247 else
248 *base = (void *) (uintptr_t) (reg32 - idx);
250 return PS_OK;
253 /* See nat/aarch64-linux.h. */
256 aarch64_tls_register_count (int tid)
258 uint64_t tls_regs[2];
259 struct iovec iovec;
260 iovec.iov_base = tls_regs;
261 iovec.iov_len = sizeof (tls_regs);
263 /* Attempt to read both TPIDR and TPIDR2. If ptrace returns less data than
264 we are expecting, that means it doesn't support all the registers. From
265 the iovec length, figure out how many TPIDR registers the target actually
266 supports. */
267 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
268 return 0;
270 /* Calculate how many TPIDR registers we have. */
271 return iovec.iov_len / sizeof (uint64_t);