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" 22 #include "nat/aarch64-linux-hw-point.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 33 void 34 aarch64_linux_prepare_to_resume (struct lwp_info *lwp) 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 73 void 74 aarch64_linux_new_thread (struct lwp_info *lwp) 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 94 void 95 aarch64_linux_delete_thread (struct arch_lwp_info *arch_lwp) 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 103 void 104 aarch64_compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from) 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 161 void 162 aarch64_siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from) 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 220 ps_err_e 221 aarch64_ps_get_thread_area (struct ps_prochandle *ph, 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 = ®64; 232 iovec.iov_len = sizeof (reg64); 233 } 234 else 235 { 236 iovec.iov_base = ®32; 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 256 int 257 aarch64_tls_register_count (int tid) 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 the request fails, it means 265 the Linux Kernel does not support TPIDR2. 266 267 Otherwise the Linux Kernel supports both TPIDR and TPIDR2. */ 268 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_TLS, &iovec) != 0) 269 return 1; 270 271 /* TPIDR2 is available as well. */ 272 return 2; 273 } 274