1 1.1 christos /* Native-dependent code for FreeBSD/aarch64. 2 1.1 christos 3 1.1.1.4 christos Copyright (C) 2017-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This file is part of GDB. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 1.1 christos 20 1.1.1.3 christos #include "arch-utils.h" 21 1.1.1.3 christos #include "inferior.h" 22 1.1.1.2 christos #include "regcache.h" 23 1.1 christos #include "target.h" 24 1.1.1.3 christos #include "nat/aarch64-hw-point.h" 25 1.1 christos 26 1.1.1.3 christos #include "elf/common.h" 27 1.1.1.3 christos 28 1.1.1.3 christos #include <sys/param.h> 29 1.1 christos #include <sys/ptrace.h> 30 1.1.1.3 christos #include <machine/armreg.h> 31 1.1 christos #include <machine/reg.h> 32 1.1 christos 33 1.1 christos #include "fbsd-nat.h" 34 1.1 christos #include "aarch64-tdep.h" 35 1.1 christos #include "aarch64-fbsd-tdep.h" 36 1.1.1.3 christos #include "aarch64-nat.h" 37 1.1 christos #include "inf-ptrace.h" 38 1.1 christos 39 1.1.1.3 christos #if __FreeBSD_version >= 1400005 40 1.1.1.3 christos #define HAVE_DBREG 41 1.1.1.3 christos 42 1.1.1.3 christos #include <unordered_set> 43 1.1.1.3 christos #endif 44 1.1.1.3 christos 45 1.1.1.3 christos #ifdef HAVE_DBREG 46 1.1.1.3 christos struct aarch64_fbsd_nat_target final 47 1.1.1.3 christos : public aarch64_nat_target<fbsd_nat_target> 48 1.1.1.3 christos #else 49 1.1 christos struct aarch64_fbsd_nat_target final : public fbsd_nat_target 50 1.1.1.3 christos #endif 51 1.1 christos { 52 1.1 christos void fetch_registers (struct regcache *, int) override; 53 1.1 christos void store_registers (struct regcache *, int) override; 54 1.1.1.3 christos 55 1.1.1.3 christos const struct target_desc *read_description () override; 56 1.1.1.3 christos 57 1.1.1.3 christos #ifdef HAVE_DBREG 58 1.1.1.3 christos /* Hardware breakpoints and watchpoints. */ 59 1.1.1.3 christos bool stopped_by_watchpoint () override; 60 1.1.1.3 christos bool stopped_data_address (CORE_ADDR *) override; 61 1.1.1.3 christos bool stopped_by_hw_breakpoint () override; 62 1.1.1.3 christos bool supports_stopped_by_hw_breakpoint () override; 63 1.1.1.3 christos 64 1.1.1.3 christos void post_startup_inferior (ptid_t) override; 65 1.1.1.3 christos void post_attach (int pid) override; 66 1.1.1.3 christos 67 1.1.1.3 christos void low_new_fork (ptid_t parent, pid_t child) override; 68 1.1.1.3 christos void low_delete_thread (thread_info *) override; 69 1.1.1.3 christos void low_prepare_to_resume (thread_info *) override; 70 1.1.1.3 christos 71 1.1.1.3 christos private: 72 1.1.1.3 christos void probe_debug_regs (int pid); 73 1.1.1.3 christos static bool debug_regs_probed; 74 1.1.1.3 christos #endif 75 1.1 christos }; 76 1.1 christos 77 1.1 christos static aarch64_fbsd_nat_target the_aarch64_fbsd_nat_target; 78 1.1 christos 79 1.1.1.3 christos /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this 80 1.1.1.3 christos for all registers. */ 81 1.1 christos 82 1.1.1.3 christos void 83 1.1.1.3 christos aarch64_fbsd_nat_target::fetch_registers (struct regcache *regcache, 84 1.1.1.3 christos int regnum) 85 1.1 christos { 86 1.1.1.3 christos fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS, 87 1.1.1.3 christos &aarch64_fbsd_gregset); 88 1.1.1.3 christos fetch_register_set<struct fpreg> (regcache, regnum, PT_GETFPREGS, 89 1.1.1.3 christos &aarch64_fbsd_fpregset); 90 1.1.1.3 christos 91 1.1.1.3 christos gdbarch *gdbarch = regcache->arch (); 92 1.1.1.3 christos aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch); 93 1.1.1.3 christos if (tdep->has_tls ()) 94 1.1.1.3 christos fetch_regset<uint64_t> (regcache, regnum, NT_ARM_TLS, 95 1.1.1.3 christos &aarch64_fbsd_tls_regset, tdep->tls_regnum_base); 96 1.1 christos } 97 1.1 christos 98 1.1.1.3 christos /* Store register REGNUM back into the inferior. If REGNUM is -1, do 99 1.1.1.3 christos this for all registers. */ 100 1.1 christos 101 1.1.1.3 christos void 102 1.1.1.3 christos aarch64_fbsd_nat_target::store_registers (struct regcache *regcache, 103 1.1.1.3 christos int regnum) 104 1.1 christos { 105 1.1.1.3 christos store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS, 106 1.1.1.3 christos &aarch64_fbsd_gregset); 107 1.1.1.3 christos store_register_set<struct fpreg> (regcache, regnum, PT_GETFPREGS, 108 1.1.1.3 christos PT_SETFPREGS, &aarch64_fbsd_fpregset); 109 1.1.1.3 christos 110 1.1.1.3 christos gdbarch *gdbarch = regcache->arch (); 111 1.1.1.3 christos aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch); 112 1.1.1.3 christos if (tdep->has_tls ()) 113 1.1.1.3 christos store_regset<uint64_t> (regcache, regnum, NT_ARM_TLS, 114 1.1.1.3 christos &aarch64_fbsd_tls_regset, tdep->tls_regnum_base); 115 1.1 christos } 116 1.1 christos 117 1.1.1.3 christos /* Implement the target read_description method. */ 118 1.1 christos 119 1.1.1.3 christos const struct target_desc * 120 1.1.1.3 christos aarch64_fbsd_nat_target::read_description () 121 1.1.1.3 christos { 122 1.1.1.4 christos if (inferior_ptid == null_ptid) 123 1.1.1.4 christos return this->beneath ()->read_description (); 124 1.1.1.4 christos 125 1.1.1.3 christos aarch64_features features; 126 1.1.1.3 christos features.tls = have_regset (inferior_ptid, NT_ARM_TLS)? 1 : 0; 127 1.1.1.3 christos return aarch64_read_description (features); 128 1.1.1.3 christos } 129 1.1.1.3 christos 130 1.1.1.3 christos #ifdef HAVE_DBREG 131 1.1.1.3 christos bool aarch64_fbsd_nat_target::debug_regs_probed; 132 1.1.1.3 christos 133 1.1.1.3 christos /* Set of threads which need to update debug registers on next resume. */ 134 1.1.1.3 christos 135 1.1.1.3 christos static std::unordered_set<lwpid_t> aarch64_debug_pending_threads; 136 1.1.1.3 christos 137 1.1.1.3 christos /* Implement the "stopped_data_address" target_ops method. */ 138 1.1.1.3 christos 139 1.1.1.3 christos bool 140 1.1.1.3 christos aarch64_fbsd_nat_target::stopped_data_address (CORE_ADDR *addr_p) 141 1.1 christos { 142 1.1.1.3 christos siginfo_t siginfo; 143 1.1.1.3 christos struct aarch64_debug_reg_state *state; 144 1.1 christos 145 1.1.1.3 christos if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo)) 146 1.1.1.3 christos return false; 147 1.1 christos 148 1.1.1.3 christos /* This must be a hardware breakpoint. */ 149 1.1.1.3 christos if (siginfo.si_signo != SIGTRAP 150 1.1.1.3 christos || siginfo.si_code != TRAP_TRACE 151 1.1.1.3 christos || siginfo.si_trapno != EXCP_WATCHPT_EL0) 152 1.1.1.3 christos return false; 153 1.1.1.3 christos 154 1.1.1.3 christos const CORE_ADDR addr_trap = (CORE_ADDR) siginfo.si_addr; 155 1.1.1.3 christos 156 1.1.1.3 christos /* Check if the address matches any watched address. */ 157 1.1.1.3 christos state = aarch64_get_debug_reg_state (inferior_ptid.pid ()); 158 1.1.1.3 christos return aarch64_stopped_data_address (state, addr_trap, addr_p); 159 1.1.1.3 christos } 160 1.1 christos 161 1.1.1.3 christos /* Implement the "stopped_by_watchpoint" target_ops method. */ 162 1.1 christos 163 1.1.1.3 christos bool 164 1.1.1.3 christos aarch64_fbsd_nat_target::stopped_by_watchpoint () 165 1.1.1.3 christos { 166 1.1.1.4 christos return stopped_data_address (nullptr); 167 1.1.1.3 christos } 168 1.1.1.3 christos 169 1.1.1.3 christos /* Implement the "stopped_by_hw_breakpoint" target_ops method. */ 170 1.1.1.3 christos 171 1.1.1.3 christos bool 172 1.1.1.3 christos aarch64_fbsd_nat_target::stopped_by_hw_breakpoint () 173 1.1.1.3 christos { 174 1.1.1.3 christos siginfo_t siginfo; 175 1.1.1.3 christos struct aarch64_debug_reg_state *state; 176 1.1.1.3 christos 177 1.1.1.3 christos if (!fbsd_nat_get_siginfo (inferior_ptid, &siginfo)) 178 1.1.1.3 christos return false; 179 1.1 christos 180 1.1.1.3 christos /* This must be a hardware breakpoint. */ 181 1.1.1.3 christos if (siginfo.si_signo != SIGTRAP 182 1.1.1.3 christos || siginfo.si_code != TRAP_TRACE 183 1.1.1.3 christos || siginfo.si_trapno != EXCP_WATCHPT_EL0) 184 1.1.1.3 christos return false; 185 1.1.1.3 christos 186 1.1.1.3 christos return !stopped_by_watchpoint(); 187 1.1.1.3 christos } 188 1.1.1.3 christos 189 1.1.1.3 christos /* Implement the "supports_stopped_by_hw_breakpoint" target_ops method. */ 190 1.1.1.3 christos 191 1.1.1.3 christos bool 192 1.1.1.3 christos aarch64_fbsd_nat_target::supports_stopped_by_hw_breakpoint () 193 1.1.1.3 christos { 194 1.1.1.3 christos return true; 195 1.1.1.3 christos } 196 1.1.1.3 christos 197 1.1.1.3 christos /* Fetch the hardware debug register capability information. */ 198 1.1.1.3 christos 199 1.1.1.3 christos void 200 1.1.1.3 christos aarch64_fbsd_nat_target::probe_debug_regs (int pid) 201 1.1.1.3 christos { 202 1.1.1.3 christos if (!debug_regs_probed) 203 1.1.1.3 christos { 204 1.1.1.3 christos struct dbreg reg; 205 1.1.1.3 christos 206 1.1.1.3 christos debug_regs_probed = true; 207 1.1.1.3 christos aarch64_num_bp_regs = 0; 208 1.1.1.3 christos aarch64_num_wp_regs = 0; 209 1.1.1.3 christos 210 1.1.1.3 christos if (ptrace(PT_GETDBREGS, pid, (PTRACE_TYPE_ARG3) ®, 0) == 0) 211 1.1.1.3 christos { 212 1.1.1.3 christos switch (reg.db_debug_ver) 213 1.1.1.3 christos { 214 1.1.1.3 christos case AARCH64_DEBUG_ARCH_V8: 215 1.1.1.3 christos case AARCH64_DEBUG_ARCH_V8_1: 216 1.1.1.3 christos case AARCH64_DEBUG_ARCH_V8_2: 217 1.1.1.3 christos case AARCH64_DEBUG_ARCH_V8_4: 218 1.1.1.4 christos case AARCH64_DEBUG_ARCH_V8_8: 219 1.1.1.4 christos case AARCH64_DEBUG_ARCH_V8_9: 220 1.1.1.3 christos break; 221 1.1.1.3 christos default: 222 1.1.1.3 christos return; 223 1.1.1.3 christos } 224 1.1.1.3 christos 225 1.1.1.3 christos aarch64_num_bp_regs = reg.db_nbkpts; 226 1.1.1.3 christos if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM) 227 1.1.1.3 christos { 228 1.1.1.3 christos warning (_("Unexpected number of hardware breakpoint registers" 229 1.1.1.3 christos " reported by ptrace, got %d, expected %d."), 230 1.1.1.3 christos aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM); 231 1.1.1.3 christos aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM; 232 1.1.1.3 christos } 233 1.1.1.3 christos aarch64_num_wp_regs = reg.db_nwtpts; 234 1.1.1.3 christos if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM) 235 1.1.1.3 christos { 236 1.1.1.3 christos warning (_("Unexpected number of hardware watchpoint registers" 237 1.1.1.3 christos " reported by ptrace, got %d, expected %d."), 238 1.1.1.3 christos aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM); 239 1.1.1.3 christos aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM; 240 1.1.1.3 christos } 241 1.1.1.3 christos } 242 1.1 christos } 243 1.1 christos } 244 1.1 christos 245 1.1.1.3 christos /* Implement the virtual inf_ptrace_target::post_startup_inferior method. */ 246 1.1 christos 247 1.1 christos void 248 1.1.1.3 christos aarch64_fbsd_nat_target::post_startup_inferior (ptid_t ptid) 249 1.1 christos { 250 1.1.1.3 christos aarch64_remove_debug_reg_state (ptid.pid ()); 251 1.1.1.3 christos probe_debug_regs (ptid.pid ()); 252 1.1.1.3 christos fbsd_nat_target::post_startup_inferior (ptid); 253 1.1.1.3 christos } 254 1.1 christos 255 1.1.1.3 christos /* Implement the "post_attach" target_ops method. */ 256 1.1.1.3 christos 257 1.1.1.3 christos void 258 1.1.1.3 christos aarch64_fbsd_nat_target::post_attach (int pid) 259 1.1.1.3 christos { 260 1.1.1.3 christos aarch64_remove_debug_reg_state (pid); 261 1.1.1.3 christos probe_debug_regs (pid); 262 1.1.1.3 christos fbsd_nat_target::post_attach (pid); 263 1.1.1.3 christos } 264 1.1 christos 265 1.1.1.3 christos /* Implement the virtual fbsd_nat_target::low_new_fork method. */ 266 1.1 christos 267 1.1.1.3 christos void 268 1.1.1.3 christos aarch64_fbsd_nat_target::low_new_fork (ptid_t parent, pid_t child) 269 1.1.1.3 christos { 270 1.1.1.3 christos struct aarch64_debug_reg_state *parent_state, *child_state; 271 1.1 christos 272 1.1.1.3 christos /* If there is no parent state, no watchpoints nor breakpoints have 273 1.1.1.3 christos been set, so there is nothing to do. */ 274 1.1.1.3 christos parent_state = aarch64_lookup_debug_reg_state (parent.pid ()); 275 1.1.1.3 christos if (parent_state == nullptr) 276 1.1.1.3 christos return; 277 1.1.1.3 christos 278 1.1.1.3 christos /* The kernel clears debug registers in the new child process after 279 1.1.1.3 christos fork, but GDB core assumes the child inherits the watchpoints/hw 280 1.1.1.3 christos breakpoints of the parent, and will remove them all from the 281 1.1.1.3 christos forked off process. Copy the debug registers mirrors into the 282 1.1.1.3 christos new process so that all breakpoints and watchpoints can be 283 1.1.1.3 christos removed together. */ 284 1.1 christos 285 1.1.1.3 christos child_state = aarch64_get_debug_reg_state (child); 286 1.1.1.3 christos *child_state = *parent_state; 287 1.1.1.3 christos } 288 1.1.1.3 christos 289 1.1.1.3 christos /* Mark debug register state "dirty" for all threads belonging to the 290 1.1.1.3 christos current inferior. */ 291 1.1.1.3 christos 292 1.1.1.3 christos void 293 1.1.1.3 christos aarch64_notify_debug_reg_change (ptid_t ptid, 294 1.1.1.3 christos int is_watchpoint, unsigned int idx) 295 1.1.1.3 christos { 296 1.1.1.3 christos for (thread_info *tp : current_inferior ()->non_exited_threads ()) 297 1.1 christos { 298 1.1.1.3 christos if (tp->ptid.lwp_p ()) 299 1.1.1.3 christos aarch64_debug_pending_threads.emplace (tp->ptid.lwp ()); 300 1.1.1.3 christos } 301 1.1.1.3 christos } 302 1.1.1.3 christos 303 1.1.1.3 christos /* Implement the virtual fbsd_nat_target::low_delete_thread method. */ 304 1.1.1.3 christos 305 1.1.1.3 christos void 306 1.1.1.3 christos aarch64_fbsd_nat_target::low_delete_thread (thread_info *tp) 307 1.1.1.3 christos { 308 1.1.1.3 christos gdb_assert(tp->ptid.lwp_p ()); 309 1.1.1.3 christos aarch64_debug_pending_threads.erase (tp->ptid.lwp ()); 310 1.1.1.3 christos } 311 1.1 christos 312 1.1.1.3 christos /* Implement the virtual fbsd_nat_target::low_prepare_to_resume method. */ 313 1.1 christos 314 1.1.1.3 christos void 315 1.1.1.3 christos aarch64_fbsd_nat_target::low_prepare_to_resume (thread_info *tp) 316 1.1.1.3 christos { 317 1.1.1.3 christos gdb_assert(tp->ptid.lwp_p ()); 318 1.1 christos 319 1.1.1.3 christos if (aarch64_debug_pending_threads.erase (tp->ptid.lwp ()) == 0) 320 1.1.1.3 christos return; 321 1.1.1.3 christos 322 1.1.1.3 christos struct aarch64_debug_reg_state *state = 323 1.1.1.3 christos aarch64_lookup_debug_reg_state (tp->ptid.pid ()); 324 1.1.1.3 christos gdb_assert(state != nullptr); 325 1.1.1.3 christos 326 1.1.1.3 christos struct dbreg reg; 327 1.1.1.3 christos memset (®, 0, sizeof(reg)); 328 1.1.1.3 christos for (int i = 0; i < aarch64_num_bp_regs; i++) 329 1.1.1.3 christos { 330 1.1.1.3 christos reg.db_breakregs[i].dbr_addr = state->dr_addr_bp[i]; 331 1.1.1.3 christos reg.db_breakregs[i].dbr_ctrl = state->dr_ctrl_bp[i]; 332 1.1 christos } 333 1.1.1.3 christos for (int i = 0; i < aarch64_num_wp_regs; i++) 334 1.1.1.3 christos { 335 1.1.1.3 christos reg.db_watchregs[i].dbw_addr = state->dr_addr_wp[i]; 336 1.1.1.3 christos reg.db_watchregs[i].dbw_ctrl = state->dr_ctrl_wp[i]; 337 1.1.1.3 christos } 338 1.1.1.3 christos if (ptrace(PT_SETDBREGS, tp->ptid.lwp (), (PTRACE_TYPE_ARG3) ®, 0) != 0) 339 1.1.1.3 christos error (_("Failed to set hardware debug registers")); 340 1.1.1.3 christos } 341 1.1.1.3 christos #else 342 1.1.1.3 christos /* A stub that should never be called. */ 343 1.1.1.3 christos void 344 1.1.1.3 christos aarch64_notify_debug_reg_change (ptid_t ptid, 345 1.1.1.3 christos int is_watchpoint, unsigned int idx) 346 1.1.1.3 christos { 347 1.1.1.3 christos gdb_assert (true); 348 1.1 christos } 349 1.1.1.3 christos #endif 350 1.1 christos 351 1.1.1.2 christos void _initialize_aarch64_fbsd_nat (); 352 1.1 christos void 353 1.1.1.2 christos _initialize_aarch64_fbsd_nat () 354 1.1 christos { 355 1.1.1.3 christos #ifdef HAVE_DBREG 356 1.1.1.3 christos aarch64_initialize_hw_point (); 357 1.1.1.3 christos #endif 358 1.1 christos add_inf_child_target (&the_aarch64_fbsd_nat_target); 359 1.1 christos } 360