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>
29 /* Called when resuming a thread LWP.
30 The hardware debug registers are updated when there is any change. */
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
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 ());
52 debug_printf ("prepare_to_resume thread %d\n", tid
);
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
);
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. */
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. */
94 aarch64_linux_delete_thread (struct arch_lwp_info
*arch_lwp
)
99 /* Convert native siginfo FROM to the siginfo in the layout of the
100 inferior's architecture TO. */
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
;
130 switch (to
->si_signo
)
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
;
143 to
->cpt_si_addr
= (intptr_t) from
->si_addr
;
146 to
->cpt_si_band
= from
->si_band
;
147 to
->cpt_si_fd
= from
->si_fd
;
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
;
158 /* Convert inferior's architecture siginfo FROM to native siginfo TO. */
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
;
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
;
188 switch (to
->si_signo
)
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
;
201 to
->si_addr
= (void *) (intptr_t) from
->cpt_si_addr
;
204 to
->si_band
= from
->cpt_si_band
;
205 to
->si_fd
= from
->cpt_si_fd
;
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
;
216 /* Called by libthread_db. Returns a pointer to the thread local
217 storage (or its descriptor). */
220 aarch64_ps_get_thread_area (struct ps_prochandle
*ph
,
221 lwpid_t lwpid
, int idx
, void **base
,
230 iovec
.iov_base
= ®64
;
231 iovec
.iov_len
= sizeof (reg64
);
235 iovec
.iov_base
= ®32
;
236 iovec
.iov_len
= sizeof (reg32
);
239 if (ptrace (PTRACE_GETREGSET
, lwpid
, NT_ARM_TLS
, &iovec
) != 0)
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. */
246 *base
= (void *) (reg64
- idx
);
248 *base
= (void *) (uintptr_t) (reg32
- idx
);
253 /* See nat/aarch64-linux.h. */
256 aarch64_tls_register_count (int tid
)
258 uint64_t tls_regs
[2];
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
267 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_TLS
, &iovec
) != 0)
270 /* Calculate how many TPIDR registers we have. */
271 return iovec
.iov_len
/ sizeof (uint64_t);