1 /* Native-dependent code for NetBSD/aarch64. 2 3 Copyright (C) 2017-2018 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 #include "defs.h" 21 #include "target.h" 22 23 #include <sys/types.h> 24 #include <sys/ptrace.h> 25 26 #include <machine/frame.h> 27 #include <machine/pcb.h> 28 29 #include "netbsd-nat.h" 30 #include "aarch64-tdep.h" 31 #include "aarch64-netbsd-tdep.h" 32 #include "regcache.h" 33 #include "gdbcore.h" 34 #include "bsd-kvm.h" 35 #include "inf-ptrace.h" 36 37 struct aarch64_nbsd_nat_target final : public nbsd_nat_target 38 { 39 void fetch_registers (struct regcache *, int) override; 40 void store_registers (struct regcache *, int) override; 41 }; 42 43 static aarch64_nbsd_nat_target the_aarch64_nbsd_nat_target; 44 45 /* Determine if PT_GETREGS fetches REGNUM. */ 46 47 static bool 48 getregs_supplies (struct gdbarch *gdbarch, int regnum) 49 { 50 return (regnum >= AARCH64_X0_REGNUM && regnum <= AARCH64_CPSR_REGNUM); 51 } 52 53 /* Determine if PT_GETFPREGS fetches REGNUM. */ 54 55 static bool 56 getfpregs_supplies (struct gdbarch *gdbarch, int regnum) 57 { 58 return (regnum >= AARCH64_V0_REGNUM && regnum <= AARCH64_FPCR_REGNUM); 59 } 60 61 void 62 aarch64_nbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum) 63 { 64 ptid_t ptid = regcache->ptid (); 65 pid_t pid = ptid.pid (); 66 int lwp = ptid.lwp (); 67 68 struct gdbarch *gdbarch = regcache->arch (); 69 if (regnum == -1 || getregs_supplies (gdbarch, regnum)) 70 { 71 struct reg regs; 72 73 if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) ®s, lwp) == -1) 74 perror_with_name (_("Couldn't get registers")); 75 76 regcache_supply_regset (&aarch64_nbsd_gregset, regcache, regnum, ®s, 77 sizeof (regs)); 78 } 79 80 if (regnum == -1 || getfpregs_supplies (gdbarch, regnum)) 81 { 82 struct fpreg fpregs; 83 84 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, lwp) == -1) 85 perror_with_name (_("Couldn't get floating point status")); 86 87 regcache_supply_regset (&aarch64_nbsd_fpregset, regcache, regnum, &fpregs, 88 sizeof (fpregs)); 89 } 90 } 91 92 /* Store register REGNUM back into the inferior. If REGNUM is -1, do 93 this for all registers. */ 94 95 void 96 aarch64_nbsd_nat_target::store_registers (struct regcache *regcache, int regnum) 97 { 98 ptid_t ptid = regcache->ptid (); 99 pid_t pid = ptid.pid (); 100 int lwp = ptid.lwp (); 101 102 struct gdbarch *gdbarch = regcache->arch (); 103 if (regnum == -1 || getregs_supplies (gdbarch, regnum)) 104 { 105 struct reg regs; 106 107 if (ptrace (PT_GETREGS, pid, (PTRACE_TYPE_ARG3) ®s, lwp) == -1) 108 perror_with_name (_("Couldn't get registers")); 109 110 regcache_collect_regset (&aarch64_nbsd_gregset, regcache,regnum, ®s, 111 sizeof (regs)); 112 113 if (ptrace (PT_SETREGS, pid, (PTRACE_TYPE_ARG3) ®s, lwp) == -1) 114 perror_with_name (_("Couldn't write registers")); 115 } 116 117 if (regnum == -1 || getfpregs_supplies (gdbarch, regnum)) 118 { 119 struct fpreg fpregs; 120 121 if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, lwp) == -1) 122 perror_with_name (_("Couldn't get floating point status")); 123 124 regcache_collect_regset (&aarch64_nbsd_fpregset, regcache,regnum, &fpregs, 125 sizeof (fpregs)); 126 127 if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, lwp) == -1) 128 perror_with_name (_("Couldn't write floating point status")); 129 } 130 } 131 132 static int 133 aarch64_nbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) 134 { 135 struct trapframe tf; 136 int i; 137 138 /* The following is true for NetBSD/arm64: 139 140 The pcb contains the frame pointer at the point of the context 141 switch in cpu_switchto(). At that point we have a stack frame as 142 described by `struct trapframe', which has the following layout: 143 144 x0..x30 145 sp 146 pc 147 spsr 148 tpidr 149 150 This accounts for all callee-saved registers specified by the psABI. 151 From this information we reconstruct the register state as it would 152 look when we just returned from cpu_switchto(). 153 154 For kernel core dumps, dumpsys() builds a fake trapframe for us. */ 155 156 /* The trapframe pointer shouldn't be zero. */ 157 if (pcb->pcb_tf == 0) 158 return 0; 159 160 /* Read the stack frame, and check its validity. */ 161 read_memory ((uintptr_t)pcb->pcb_tf, (gdb_byte *) &tf, sizeof tf); 162 163 for (i = 0; i <= 30; i++) 164 { 165 regcache->raw_supply (AARCH64_X0_REGNUM + i, &tf.tf_reg[i]); 166 } 167 regcache->raw_supply (AARCH64_SP_REGNUM, &tf.tf_sp); 168 regcache->raw_supply (AARCH64_PC_REGNUM, &tf.tf_pc); 169 170 regcache->raw_supply (AARCH64_FPCR_REGNUM, &pcb->pcb_fpregs.fpcr); 171 regcache->raw_supply (AARCH64_FPSR_REGNUM, &pcb->pcb_fpregs.fpsr); 172 173 return 1; 174 } 175 176 void 177 _initialize_aarch64_nbsd_nat () 178 { 179 add_inf_child_target (&the_aarch64_nbsd_nat_target); 180 181 /* Support debugging kernel virtual memory images. */ 182 bsd_kvm_add_target (aarch64_nbsd_supply_pcb); 183 } 184