GDB (xrefs)
Loading...
Searching...
No Matches
aarch64-linux.c
Go to the documentation of this file.
1/* Copyright (C) 2009-2023 Free Software Foundation, Inc.
2 Contributed by ARM Ltd.
3
4 This file is part of GDB.
5
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.
10
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.
15
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/>. */
18
19#include "gdbsupport/common-defs.h"
20#include "gdbsupport/break-common.h"
21#include "nat/linux-nat.h"
23#include "nat/aarch64-linux.h"
24
25#include "elf/common.h"
26#include "nat/gdb_ptrace.h"
27#include <asm/ptrace.h>
28#include <sys/uio.h>
29
30/* Called when resuming a thread LWP.
31 The hardware debug registers are updated when there is any change. */
32
33void
35{
36 struct arch_lwp_info *info = lwp_arch_private_info (lwp);
37
38 /* NULL means this is the main thread still going through the shell,
39 or, no watchpoint has been set yet. In that case, there's
40 nothing to do. */
41 if (info == NULL)
42 return;
43
44 if (DR_HAS_CHANGED (info->dr_changed_bp)
45 || DR_HAS_CHANGED (info->dr_changed_wp))
46 {
47 ptid_t ptid = ptid_of_lwp (lwp);
48 int tid = ptid.lwp ();
49 struct aarch64_debug_reg_state *state
50 = aarch64_get_debug_reg_state (ptid.pid ());
51
52 if (show_debug_regs)
53 debug_printf ("prepare_to_resume thread %d\n", tid);
54
55 /* Watchpoints. */
56 if (DR_HAS_CHANGED (info->dr_changed_wp))
57 {
58 aarch64_linux_set_debug_regs (state, tid, 1);
59 DR_CLEAR_CHANGED (info->dr_changed_wp);
60 }
61
62 /* Breakpoints. */
63 if (DR_HAS_CHANGED (info->dr_changed_bp))
64 {
65 aarch64_linux_set_debug_regs (state, tid, 0);
66 DR_CLEAR_CHANGED (info->dr_changed_bp);
67 }
68 }
69}
70
71/* Function to call when a new thread is detected. */
72
73void
75{
76 ptid_t ptid = ptid_of_lwp (lwp);
77 struct aarch64_debug_reg_state *state
78 = aarch64_get_debug_reg_state (ptid.pid ());
79 struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
80
81 /* If there are hardware breakpoints/watchpoints in the process then mark that
82 all the hardware breakpoint/watchpoint register pairs for this thread need
83 to be initialized (with data from aarch_process_info.debug_reg_state). */
84 if (aarch64_any_set_debug_regs_state (state, false))
85 DR_MARK_ALL_CHANGED (info->dr_changed_bp, aarch64_num_bp_regs);
86 if (aarch64_any_set_debug_regs_state (state, true))
87 DR_MARK_ALL_CHANGED (info->dr_changed_wp, aarch64_num_wp_regs);
88
89 lwp_set_arch_private_info (lwp, info);
90}
91
92/* See nat/aarch64-linux.h. */
93
94void
96{
97 xfree (arch_lwp);
98}
99
100/* Convert native siginfo FROM to the siginfo in the layout of the
101 inferior's architecture TO. */
102
103void
105{
106 memset (to, 0, sizeof (*to));
107
108 to->si_signo = from->si_signo;
109 to->si_errno = from->si_errno;
110 to->si_code = from->si_code;
111
112 if (to->si_code == SI_TIMER)
113 {
114 to->cpt_si_timerid = from->si_timerid;
115 to->cpt_si_overrun = from->si_overrun;
116 to->cpt_si_ptr = (intptr_t) from->si_ptr;
117 }
118 else if (to->si_code == SI_USER)
119 {
120 to->cpt_si_pid = from->si_pid;
121 to->cpt_si_uid = from->si_uid;
122 }
123 else if (to->si_code < 0)
124 {
125 to->cpt_si_pid = from->si_pid;
126 to->cpt_si_uid = from->si_uid;
127 to->cpt_si_ptr = (intptr_t) from->si_ptr;
128 }
129 else
130 {
131 switch (to->si_signo)
132 {
133 case SIGCHLD:
134 to->cpt_si_pid = from->si_pid;
135 to->cpt_si_uid = from->si_uid;
136 to->cpt_si_status = from->si_status;
137 to->cpt_si_utime = from->si_utime;
138 to->cpt_si_stime = from->si_stime;
139 break;
140 case SIGILL:
141 case SIGFPE:
142 case SIGSEGV:
143 case SIGBUS:
144 to->cpt_si_addr = (intptr_t) from->si_addr;
145 break;
146 case SIGPOLL:
147 to->cpt_si_band = from->si_band;
148 to->cpt_si_fd = from->si_fd;
149 break;
150 default:
151 to->cpt_si_pid = from->si_pid;
152 to->cpt_si_uid = from->si_uid;
153 to->cpt_si_ptr = (intptr_t) from->si_ptr;
154 break;
155 }
156 }
157}
158
159/* Convert inferior's architecture siginfo FROM to native siginfo TO. */
160
161void
163{
164 memset (to, 0, sizeof (*to));
165
166 to->si_signo = from->si_signo;
167 to->si_errno = from->si_errno;
168 to->si_code = from->si_code;
169
170 if (to->si_code == SI_TIMER)
171 {
172 to->si_timerid = from->cpt_si_timerid;
173 to->si_overrun = from->cpt_si_overrun;
174 to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
175 }
176 else if (to->si_code == SI_USER)
177 {
178 to->si_pid = from->cpt_si_pid;
179 to->si_uid = from->cpt_si_uid;
180 }
181 if (to->si_code < 0)
182 {
183 to->si_pid = from->cpt_si_pid;
184 to->si_uid = from->cpt_si_uid;
185 to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
186 }
187 else
188 {
189 switch (to->si_signo)
190 {
191 case SIGCHLD:
192 to->si_pid = from->cpt_si_pid;
193 to->si_uid = from->cpt_si_uid;
194 to->si_status = from->cpt_si_status;
195 to->si_utime = from->cpt_si_utime;
196 to->si_stime = from->cpt_si_stime;
197 break;
198 case SIGILL:
199 case SIGFPE:
200 case SIGSEGV:
201 case SIGBUS:
202 to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
203 break;
204 case SIGPOLL:
205 to->si_band = from->cpt_si_band;
206 to->si_fd = from->cpt_si_fd;
207 break;
208 default:
209 to->si_pid = from->cpt_si_pid;
210 to->si_uid = from->cpt_si_uid;
211 to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr;
212 break;
213 }
214 }
215}
216
217/* Called by libthread_db. Returns a pointer to the thread local
218 storage (or its descriptor). */
219
220ps_err_e
222 lwpid_t lwpid, int idx, void **base,
223 int is_64bit_p)
224{
225 struct iovec iovec;
226 uint64_t reg64;
227 uint32_t reg32;
228
229 if (is_64bit_p)
230 {
231 iovec.iov_base = &reg64;
232 iovec.iov_len = sizeof (reg64);
233 }
234 else
235 {
236 iovec.iov_base = &reg32;
237 iovec.iov_len = sizeof (reg32);
238 }
239
240 if (ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec) != 0)
241 return PS_ERR;
242
243 /* IDX is the bias from the thread pointer to the beginning of the
244 thread descriptor. It has to be subtracted due to implementation
245 quirks in libthread_db. */
246 if (is_64bit_p)
247 *base = (void *) (reg64 - idx);
248 else
249 *base = (void *) (uintptr_t) (reg32 - idx);
250
251 return PS_OK;
252}
253
254/* See nat/aarch64-linux.h. */
255
256int
258{
259 uint64_t tls_regs[2];
260 struct iovec iovec;
261 iovec.iov_base = tls_regs;
262 iovec.iov_len = sizeof (tls_regs);
263
264 /* Attempt to read both TPIDR and TPIDR2. If ptrace returns less data than
265 we are expecting, that means it doesn't support all the registers. From
266 the iovec length, figure out how many TPIDR registers the target actually
267 supports. */
268 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0)
269 return 0;
270
271 /* Calculate how many TPIDR registers we have. */
272 return iovec.iov_len / sizeof (uint64_t);
273}
int aarch64_num_bp_regs
bool aarch64_any_set_debug_regs_state(aarch64_debug_reg_state *state, bool watchpoint)
int aarch64_num_wp_regs
void aarch64_linux_set_debug_regs(struct aarch64_debug_reg_state *state, int tid, int watchpoint)
#define DR_MARK_ALL_CHANGED(x, m)
#define DR_HAS_CHANGED(x)
#define DR_CLEAR_CHANGED(x)
ps_err_e aarch64_ps_get_thread_area(struct ps_prochandle *ph, lwpid_t lwpid, int idx, void **base, int is_64bit_p)
void aarch64_linux_prepare_to_resume(struct lwp_info *lwp)
void aarch64_linux_new_thread(struct lwp_info *lwp)
void aarch64_compat_siginfo_from_siginfo(compat_siginfo_t *to, siginfo_t *from)
void aarch64_siginfo_from_compat_siginfo(siginfo_t *to, compat_siginfo_t *from)
int aarch64_tls_register_count(int tid)
void aarch64_linux_delete_thread(struct arch_lwp_info *arch_lwp)
struct aarch64_debug_reg_state * aarch64_get_debug_reg_state(pid_t pid)
Definition aarch64-nat.c:51
void xfree(void *)
#define ptrace(request, pid, addr, data)
Definition gdb_ptrace.h:141
ptid_t ptid_of_lwp(struct lwp_info *lwp)
Definition linux-nat.c:277
void lwp_set_arch_private_info(struct lwp_info *lwp, struct arch_lwp_info *info)
Definition linux-nat.c:285
struct arch_lwp_info * lwp_arch_private_info(struct lwp_info *lwp)
Definition linux-nat.c:294
#define PTRACE_GETREGSET