1 /* Copyright (C) 2009-2022 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/common-defs.h"
20 #include "gdbsupport/break-common.h"
21 #include "nat/linux-nat.h"
22 #include "nat/aarch64-linux-hw-point.h"
23 #include "nat/aarch64-linux.h"
25 #include "elf/common.h"
26 #include "nat/gdb_ptrace.h"
27 #include <asm/ptrace.h>
30 /* Called when resuming a thread LWP.
31 The hardware debug registers are updated when there is any change. */
34 aarch64_linux_prepare_to_resume (struct lwp_info
*lwp
)
36 struct arch_lwp_info
*info
= lwp_arch_private_info (lwp
);
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
44 if (DR_HAS_CHANGED (info
->dr_changed_bp
)
45 || DR_HAS_CHANGED (info
->dr_changed_wp
))
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 ());
53 debug_printf ("prepare_to_resume thread %d\n", tid
);
56 if (DR_HAS_CHANGED (info
->dr_changed_wp
))
58 aarch64_linux_set_debug_regs (state
, tid
, 1);
59 DR_CLEAR_CHANGED (info
->dr_changed_wp
);
63 if (DR_HAS_CHANGED (info
->dr_changed_bp
))
65 aarch64_linux_set_debug_regs (state
, tid
, 0);
66 DR_CLEAR_CHANGED (info
->dr_changed_bp
);
71 /* Function to call when a new thread is detected. */
74 aarch64_linux_new_thread (struct lwp_info
*lwp
)
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
);
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_linux_any_set_debug_regs_state (state
, false))
85 DR_MARK_ALL_CHANGED (info
->dr_changed_bp
, aarch64_num_bp_regs
);
86 if (aarch64_linux_any_set_debug_regs_state (state
, true))
87 DR_MARK_ALL_CHANGED (info
->dr_changed_wp
, aarch64_num_wp_regs
);
89 lwp_set_arch_private_info (lwp
, info
);
92 /* See nat/aarch64-linux.h. */
95 aarch64_linux_delete_thread (struct arch_lwp_info
*arch_lwp
)
100 /* Convert native siginfo FROM to the siginfo in the layout of the
101 inferior's architecture TO. */
104 aarch64_compat_siginfo_from_siginfo (compat_siginfo_t
*to
, siginfo_t
*from
)
106 memset (to
, 0, sizeof (*to
));
108 to
->si_signo
= from
->si_signo
;
109 to
->si_errno
= from
->si_errno
;
110 to
->si_code
= from
->si_code
;
112 if (to
->si_code
== SI_TIMER
)
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
;
118 else if (to
->si_code
== SI_USER
)
120 to
->cpt_si_pid
= from
->si_pid
;
121 to
->cpt_si_uid
= from
->si_uid
;
123 else if (to
->si_code
< 0)
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
;
131 switch (to
->si_signo
)
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
;
144 to
->cpt_si_addr
= (intptr_t) from
->si_addr
;
147 to
->cpt_si_band
= from
->si_band
;
148 to
->cpt_si_fd
= from
->si_fd
;
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
;
159 /* Convert inferior's architecture siginfo FROM to native siginfo TO. */
162 aarch64_siginfo_from_compat_siginfo (siginfo_t
*to
, compat_siginfo_t
*from
)
164 memset (to
, 0, sizeof (*to
));
166 to
->si_signo
= from
->si_signo
;
167 to
->si_errno
= from
->si_errno
;
168 to
->si_code
= from
->si_code
;
170 if (to
->si_code
== SI_TIMER
)
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
;
176 else if (to
->si_code
== SI_USER
)
178 to
->si_pid
= from
->cpt_si_pid
;
179 to
->si_uid
= from
->cpt_si_uid
;
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
;
189 switch (to
->si_signo
)
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
;
202 to
->si_addr
= (void *) (intptr_t) from
->cpt_si_addr
;
205 to
->si_band
= from
->cpt_si_band
;
206 to
->si_fd
= from
->cpt_si_fd
;
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
;
217 /* Called by libthread_db. Returns a pointer to the thread local
218 storage (or its descriptor). */
221 aarch64_ps_get_thread_area (struct ps_prochandle
*ph
,
222 lwpid_t lwpid
, int idx
, void **base
,
231 iovec
.iov_base
= ®64
;
232 iovec
.iov_len
= sizeof (reg64
);
236 iovec
.iov_base
= ®32
;
237 iovec
.iov_len
= sizeof (reg32
);
240 if (ptrace (PTRACE_GETREGSET
, lwpid
, NT_ARM_TLS
, &iovec
) != 0)
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. */
247 *base
= (void *) (reg64
- idx
);
249 *base
= (void *) (uintptr_t) (reg32
- idx
);