1/* Native-dependent code for BSD Unix running on ARM's, for GDB. 2 3 Copyright (C) 1988-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20/* We define this to get types like register_t. */ 21#include "defs.h" 22#include "gdbcore.h" 23#include "inferior.h" 24#include "regcache.h" 25#include "target.h" 26#include <sys/types.h> 27#include <sys/ptrace.h> 28#include <sys/sysctl.h> 29#include <machine/reg.h> 30#include <machine/pcb.h> 31#include <machine/frame.h> 32#include <arm/arm32/frame.h> 33 34#include "arm-tdep.h" 35#include "arm-netbsd-tdep.h" 36#include "aarch32-tdep.h" 37#include "inf-ptrace.h" 38#include "netbsd-nat.h" 39#include "bsd-kvm.h" 40 41/* Determine if PT_GETREGS fetches REGNUM. */ 42 43static bool 44getregs_supplies (int regnum) 45{ 46 return ((regnum >= ARM_A1_REGNUM && regnum <= ARM_PC_REGNUM) 47 || regnum == ARM_PS_REGNUM); 48} 49 50/* Determine if PT_GETFPREGS fetches REGNUM. */ 51 52static bool 53getfpregs_supplies (int regnum) 54{ 55 return ((regnum >= ARM_D0_REGNUM && regnum <= ARM_D31_REGNUM) 56 || regnum == ARM_FPSCR_REGNUM); 57} 58 59class arm_netbsd_nat_target final : public nbsd_nat_target 60{ 61public: 62 /* Add our register access methods. */ 63 void fetch_registers (struct regcache *, int) override; 64 void store_registers (struct regcache *, int) override; 65 const struct target_desc *read_description () override; 66}; 67 68static arm_netbsd_nat_target the_arm_netbsd_nat_target; 69 70static int 71armnbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) 72{ 73 struct switchframe sf; 74 75 /* The following is true for NetBSD/arm32 in 5.0 and after: 76 77 The pcb contains r8-r13 (sp) at the point of context switch in 78 cpu_switchto() or call of dumpsys(). At that point we have a 79 stack frame as described by `struct switchframe', which for 80 NetBSD/arm32 has the following layout: 81 82 r4 ascending. 83 r5 | 84 r6 | 85 r7 \|/ 86 old sp 87 pc 88 89 we reconstruct the register state as it would look when we just 90 returned from cpu_switchto() or dumpsys(). */ 91 92 if (!arm_apcs_32) 93 return 0; 94 95 /* The stack pointer shouldn't be zero. */ 96 if (pcb->pcb_sp == 0) 97 return 0; 98 99 read_memory (pcb->pcb_sp, (gdb_byte *) &sf, sizeof sf); 100 101 regcache->raw_supply (ARM_PC_REGNUM, &sf.sf_pc); 102 regcache->raw_supply (ARM_SP_REGNUM, &pcb->pcb_sp); 103 regcache->raw_supply (12, &pcb->pcb_r12); 104 regcache->raw_supply (11, &pcb->pcb_r11); 105 regcache->raw_supply (10, &pcb->pcb_r10); 106 regcache->raw_supply (9, &pcb->pcb_r9); 107 regcache->raw_supply (8, &pcb->pcb_r8); 108 regcache->raw_supply (7, &sf.sf_r7); 109 regcache->raw_supply (6, &sf.sf_r6); 110 regcache->raw_supply (5, &sf.sf_r5); 111 regcache->raw_supply (4, &sf.sf_r4); 112 113 return 1; 114} 115 116static void 117arm_supply_vfpregset (struct regcache *regcache, struct fpreg *fpregset) 118{ 119 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (regcache->arch ()); 120 if (tdep->vfp_register_count == 0) 121 return; 122 123 struct vfpreg &vfp = fpregset->fpr_vfp; 124 for (int regno = 0; regno <= tdep->vfp_register_count; regno++) 125 regcache->raw_supply (regno + ARM_D0_REGNUM, (char *) &vfp.vfp_regs[regno]); 126 127 regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); 128} 129 130static void 131fetch_register (struct regcache *regcache, int regno) 132{ 133 struct reg inferior_registers; 134 int ret; 135 int lwp = regcache->ptid ().lwp (); 136 137 ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), 138 (PTRACE_TYPE_ARG3) &inferior_registers, lwp); 139 140 if (ret < 0) 141 { 142 warning (_("unable to fetch general register")); 143 return; 144 } 145 arm_nbsd_supply_gregset (nullptr, regcache, regno, &inferior_registers, 146 sizeof (inferior_registers)); 147} 148 149static void 150fetch_fp_register (struct regcache *regcache, int regno) 151{ 152 struct fpreg inferior_fp_registers; 153 int lwp = regcache->ptid ().lwp (); 154 155 int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), 156 (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); 157 158 struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; 159 160 if (ret < 0) 161 { 162 warning (_("unable to fetch floating-point register")); 163 return; 164 } 165 166 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (regcache->arch ()); 167 if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) 168 regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); 169 else if (regno >= ARM_D0_REGNUM 170 && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) 171 { 172 regcache->raw_supply (regno, 173 (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); 174 } 175 else 176 warning (_("Invalid register number.")); 177} 178 179static void 180fetch_fp_regs (struct regcache *regcache) 181{ 182 struct fpreg inferior_fp_registers; 183 int lwp = regcache->ptid ().lwp (); 184 int ret; 185 int regno; 186 187 ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), 188 (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); 189 190 if (ret < 0) 191 { 192 warning (_("unable to fetch general registers")); 193 return; 194 } 195 196 arm_supply_vfpregset (regcache, &inferior_fp_registers); 197} 198 199void 200arm_netbsd_nat_target::fetch_registers (struct regcache *regcache, int regno) 201{ 202 if (regno >= 0) 203 { 204 /* Handle discontinuous range for general purpose registers. 205 For floating-point registers, it happens to be continuous, 206 but use specific static function for clarity. */ 207 if (getregs_supplies (regno)) 208 fetch_register (regcache, regno); 209 else if (getfpregs_supplies (regno)) 210 fetch_fp_register (regcache, regno); 211 else 212 warning (_("unable to fetch register %d"), regno); 213 } 214 else 215 { 216 fetch_register (regcache, -1); 217 fetch_fp_regs (regcache); 218 } 219} 220 221 222static void 223store_register (const struct regcache *regcache, int regno) 224{ 225 struct gdbarch *gdbarch = regcache->arch (); 226 struct reg inferior_registers; 227 int lwp = regcache->ptid ().lwp (); 228 int ret; 229 230 ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), 231 (PTRACE_TYPE_ARG3) &inferior_registers, lwp); 232 233 if (ret < 0) 234 { 235 warning (_("unable to fetch general registers")); 236 return; 237 } 238 239 switch (regno) 240 { 241 case ARM_SP_REGNUM: 242 regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); 243 break; 244 245 case ARM_LR_REGNUM: 246 regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); 247 break; 248 249 case ARM_PC_REGNUM: 250 if (arm_apcs_32) 251 regcache->raw_collect (ARM_PC_REGNUM, 252 (char *) &inferior_registers.r_pc); 253 else 254 { 255 unsigned pc_val; 256 257 regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); 258 259 pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); 260 inferior_registers.r_pc ^= gdbarch_addr_bits_remove 261 (gdbarch, inferior_registers.r_pc); 262 inferior_registers.r_pc |= pc_val; 263 } 264 break; 265 266 case ARM_PS_REGNUM: 267 if (arm_apcs_32) 268 regcache->raw_collect (ARM_PS_REGNUM, 269 (char *) &inferior_registers.r_cpsr); 270 else 271 { 272 unsigned psr_val; 273 274 regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); 275 276 psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); 277 inferior_registers.r_pc = gdbarch_addr_bits_remove 278 (gdbarch, inferior_registers.r_pc); 279 inferior_registers.r_pc |= psr_val; 280 } 281 break; 282 283 default: 284 regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); 285 break; 286 } 287 288 ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), 289 (PTRACE_TYPE_ARG3) &inferior_registers, lwp); 290 291 if (ret < 0) 292 warning (_("unable to write register %d to inferior"), regno); 293} 294 295static void 296store_regs (const struct regcache *regcache) 297{ 298 struct gdbarch *gdbarch = regcache->arch (); 299 struct reg inferior_registers; 300 int lwp = regcache->ptid ().lwp (); 301 int ret; 302 int regno; 303 304 305 for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++) 306 regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); 307 308 regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); 309 regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); 310 311 if (arm_apcs_32) 312 { 313 regcache->raw_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); 314 regcache->raw_collect (ARM_PS_REGNUM, 315 (char *) &inferior_registers.r_cpsr); 316 } 317 else 318 { 319 unsigned pc_val; 320 unsigned psr_val; 321 322 regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); 323 regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); 324 325 pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); 326 psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); 327 328 inferior_registers.r_pc = pc_val | psr_val; 329 } 330 331 ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), 332 (PTRACE_TYPE_ARG3) &inferior_registers, lwp); 333 334 if (ret < 0) 335 warning (_("unable to store general registers")); 336} 337 338static void 339store_fp_register (const struct regcache *regcache, int regno) 340{ 341 struct fpreg inferior_fp_registers; 342 int lwp = regcache->ptid ().lwp (); 343 int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), 344 (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); 345 struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; 346 347 if (ret < 0) 348 { 349 warning (_("unable to fetch floating-point registers")); 350 return; 351 } 352 353 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (regcache->arch ()); 354 if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) 355 regcache->raw_collect (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); 356 else if (regno >= ARM_D0_REGNUM 357 && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) 358 { 359 regcache->raw_collect (regno, 360 (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); 361 } 362 else 363 warning (_("Invalid register number.")); 364 365 ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), 366 (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); 367 368 if (ret < 0) 369 warning (_("unable to write register %d to inferior"), regno); 370} 371 372static void 373store_fp_regs (const struct regcache *regcache) 374{ 375 arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (regcache->arch ()); 376 int lwp = regcache->ptid ().lwp (); 377 if (tdep->vfp_register_count == 0) 378 return; 379 380 struct fpreg fpregs; 381 for (int regno = 0; regno <= tdep->vfp_register_count; regno++) 382 regcache->raw_collect 383 (regno + ARM_D0_REGNUM, (char *) &fpregs.fpr_vfp.vfp_regs[regno]); 384 385 regcache->raw_collect (ARM_FPSCR_REGNUM, 386 (char *) &fpregs.fpr_vfp.vfp_fpscr); 387 388 int ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), 389 (PTRACE_TYPE_ARG3) &fpregs, lwp); 390 391 if (ret < 0) 392 warning (_("unable to store floating-point registers")); 393} 394 395void 396arm_netbsd_nat_target::store_registers (struct regcache *regcache, int regno) 397{ 398 if (regno >= 0) 399 { 400 if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) 401 store_register (regcache, regno); 402 else 403 store_fp_register (regcache, regno); 404 } 405 else 406 { 407 store_regs (regcache); 408 store_fp_regs (regcache); 409 } 410} 411 412const struct target_desc * 413arm_netbsd_nat_target::read_description () 414{ 415 int flag; 416 size_t len = sizeof (flag); 417 418 if (sysctlbyname("machdep.fpu_present", &flag, &len, NULL, 0) != 0 419 || !flag) 420 return arm_read_description (ARM_FP_TYPE_NONE, false); 421 422 len = sizeof(flag); 423 if (sysctlbyname("machdep.neon_present", &flag, &len, NULL, 0) == 0 && flag) 424 return aarch32_read_description (); 425 426 return arm_read_description (ARM_FP_TYPE_VFPV3, false); 427} 428 429void _initialize_arm_netbsd_nat (); 430void 431_initialize_arm_netbsd_nat () 432{ 433 /* Support debugging kernel virtual memory images. */ 434 bsd_kvm_add_target (armnbsd_supply_pcb); 435 436 add_inf_child_target (&the_arm_netbsd_nat_target); 437} 438