1 /* Native-dependent code for GNU/Linux RISC-V. 2 Copyright (C) 2018-2020 Free Software Foundation, Inc. 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 "defs.h" 20 #include "regcache.h" 21 #include "gregset.h" 22 #include "linux-nat.h" 23 #include "riscv-tdep.h" 24 #include "inferior.h" 25 26 #include "elf/common.h" 27 28 #include "nat/riscv-linux-tdesc.h" 29 30 #include <sys/ptrace.h> 31 32 /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */ 33 #ifndef NFPREG 34 # define NFPREG 33 35 #endif 36 37 /* RISC-V Linux native additions to the default linux support. */ 38 39 class riscv_linux_nat_target final : public linux_nat_target 40 { 41 public: 42 /* Add our register access methods. */ 43 void fetch_registers (struct regcache *regcache, int regnum) override; 44 void store_registers (struct regcache *regcache, int regnum) override; 45 46 /* Read suitable target description. */ 47 const struct target_desc *read_description () override; 48 }; 49 50 static riscv_linux_nat_target the_riscv_linux_nat_target; 51 52 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1) 53 from regset GREGS into REGCACHE. */ 54 55 static void 56 supply_gregset_regnum (struct regcache *regcache, const prgregset_t *gregs, 57 int regnum) 58 { 59 int i; 60 const elf_greg_t *regp = *gregs; 61 62 if (regnum == -1) 63 { 64 /* We only support the integer registers and PC here. */ 65 for (i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++) 66 regcache->raw_supply (i, regp + i); 67 68 /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */ 69 regcache->raw_supply (32, regp + 0); 70 71 /* Fill the inaccessible zero register with zero. */ 72 regcache->raw_supply_zeroed (0); 73 } 74 else if (regnum == RISCV_ZERO_REGNUM) 75 regcache->raw_supply_zeroed (0); 76 else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM) 77 regcache->raw_supply (regnum, regp + regnum); 78 else if (regnum == RISCV_PC_REGNUM) 79 regcache->raw_supply (32, regp + 0); 80 } 81 82 /* Copy all general purpose registers from regset GREGS into REGCACHE. */ 83 84 void 85 supply_gregset (struct regcache *regcache, const prgregset_t *gregs) 86 { 87 supply_gregset_regnum (regcache, gregs, -1); 88 } 89 90 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1) 91 from regset FPREGS into REGCACHE. */ 92 93 static void 94 supply_fpregset_regnum (struct regcache *regcache, const prfpregset_t *fpregs, 95 int regnum) 96 { 97 int flen = register_size (regcache->arch (), RISCV_FIRST_FP_REGNUM); 98 union 99 { 100 const prfpregset_t *fpregs; 101 const gdb_byte *buf; 102 } 103 fpbuf = { .fpregs = fpregs }; 104 int i; 105 106 if (regnum == -1) 107 { 108 /* We only support the FP registers and FCSR here. */ 109 for (i = RISCV_FIRST_FP_REGNUM; 110 i <= RISCV_LAST_FP_REGNUM; 111 i++, fpbuf.buf += flen) 112 regcache->raw_supply (i, fpbuf.buf); 113 114 regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 115 } 116 else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM) 117 { 118 fpbuf.buf += flen * (regnum - RISCV_FIRST_FP_REGNUM); 119 regcache->raw_supply (regnum, fpbuf.buf); 120 } 121 else if (regnum == RISCV_CSR_FCSR_REGNUM) 122 { 123 fpbuf.buf += flen * (RISCV_LAST_FP_REGNUM - RISCV_FIRST_FP_REGNUM + 1); 124 regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 125 } 126 } 127 128 /* Copy all floating point registers from regset FPREGS into REGCACHE. */ 129 130 void 131 supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs) 132 { 133 supply_fpregset_regnum (regcache, fpregs, -1); 134 } 135 136 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1) 137 from REGCACHE into regset GREGS. */ 138 139 void 140 fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum) 141 { 142 elf_greg_t *regp = *gregs; 143 144 if (regnum == -1) 145 { 146 /* We only support the integer registers and PC here. */ 147 for (int i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++) 148 regcache->raw_collect (i, regp + i); 149 150 regcache->raw_collect (32, regp + 0); 151 } 152 else if (regnum == RISCV_ZERO_REGNUM) 153 /* Nothing to do here. */ 154 ; 155 else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM) 156 regcache->raw_collect (regnum, regp + regnum); 157 else if (regnum == RISCV_PC_REGNUM) 158 regcache->raw_collect (32, regp + 0); 159 } 160 161 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1) 162 from REGCACHE into regset FPREGS. */ 163 164 void 165 fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, 166 int regnum) 167 { 168 int flen = register_size (regcache->arch (), RISCV_FIRST_FP_REGNUM); 169 union 170 { 171 prfpregset_t *fpregs; 172 gdb_byte *buf; 173 } 174 fpbuf = { .fpregs = fpregs }; 175 int i; 176 177 if (regnum == -1) 178 { 179 /* We only support the FP registers and FCSR here. */ 180 for (i = RISCV_FIRST_FP_REGNUM; 181 i <= RISCV_LAST_FP_REGNUM; 182 i++, fpbuf.buf += flen) 183 regcache->raw_collect (i, fpbuf.buf); 184 185 regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 186 } 187 else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM) 188 { 189 fpbuf.buf += flen * (regnum - RISCV_FIRST_FP_REGNUM); 190 regcache->raw_collect (regnum, fpbuf.buf); 191 } 192 else if (regnum == RISCV_CSR_FCSR_REGNUM) 193 { 194 fpbuf.buf += flen * (RISCV_LAST_FP_REGNUM - RISCV_FIRST_FP_REGNUM + 1); 195 regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 196 } 197 } 198 199 /* Return a target description for the current target. */ 200 201 const struct target_desc * 202 riscv_linux_nat_target::read_description () 203 { 204 const struct riscv_gdbarch_features features 205 = riscv_linux_read_features (inferior_ptid.lwp ()); 206 return riscv_lookup_target_description (features); 207 } 208 209 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target 210 into REGCACHE using PTRACE_GETREGSET. */ 211 212 void 213 riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) 214 { 215 int tid; 216 217 tid = get_ptrace_pid (regcache->ptid()); 218 219 if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM) 220 || (regnum == -1)) 221 { 222 struct iovec iov; 223 elf_gregset_t regs; 224 225 iov.iov_base = ®s; 226 iov.iov_len = sizeof (regs); 227 228 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, 229 (PTRACE_TYPE_ARG3) &iov) == -1) 230 perror_with_name (_("Couldn't get registers")); 231 else 232 supply_gregset_regnum (regcache, ®s, regnum); 233 } 234 235 if ((regnum >= RISCV_FIRST_FP_REGNUM 236 && regnum <= RISCV_LAST_FP_REGNUM) 237 || (regnum == RISCV_CSR_FCSR_REGNUM) 238 || (regnum == -1)) 239 { 240 struct iovec iov; 241 elf_fpregset_t regs; 242 243 iov.iov_base = ®s; 244 iov.iov_len = ELF_NFPREG * register_size (regcache->arch (), 245 RISCV_FIRST_FP_REGNUM); 246 gdb_assert (iov.iov_len <= sizeof (regs)); 247 248 if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, 249 (PTRACE_TYPE_ARG3) &iov) == -1) 250 perror_with_name (_("Couldn't get registers")); 251 else 252 supply_fpregset_regnum (regcache, ®s, regnum); 253 } 254 255 if ((regnum == RISCV_CSR_MISA_REGNUM) 256 || (regnum == -1)) 257 { 258 /* TODO: Need to add a ptrace call for this. */ 259 regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM); 260 } 261 262 /* Access to other CSRs has potential security issues, don't support them for 263 now. */ 264 } 265 266 /* Store REGNUM (or all registers if REGNUM == -1) to the target 267 from REGCACHE using PTRACE_SETREGSET. */ 268 269 void 270 riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum) 271 { 272 int tid; 273 274 tid = get_ptrace_pid (regcache->ptid ()); 275 276 if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM) 277 || (regnum == -1)) 278 { 279 struct iovec iov; 280 elf_gregset_t regs; 281 282 iov.iov_base = ®s; 283 iov.iov_len = sizeof (regs); 284 285 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, 286 (PTRACE_TYPE_ARG3) &iov) == -1) 287 perror_with_name (_("Couldn't get registers")); 288 else 289 { 290 fill_gregset (regcache, ®s, regnum); 291 292 if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, 293 (PTRACE_TYPE_ARG3) &iov) == -1) 294 perror_with_name (_("Couldn't set registers")); 295 } 296 } 297 298 if ((regnum >= RISCV_FIRST_FP_REGNUM 299 && regnum <= RISCV_LAST_FP_REGNUM) 300 || (regnum == RISCV_CSR_FCSR_REGNUM) 301 || (regnum == -1)) 302 { 303 struct iovec iov; 304 elf_fpregset_t regs; 305 306 iov.iov_base = ®s; 307 iov.iov_len = ELF_NFPREG * register_size (regcache->arch (), 308 RISCV_FIRST_FP_REGNUM); 309 gdb_assert (iov.iov_len <= sizeof (regs)); 310 311 if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, 312 (PTRACE_TYPE_ARG3) &iov) == -1) 313 perror_with_name (_("Couldn't get registers")); 314 else 315 { 316 fill_fpregset (regcache, ®s, regnum); 317 318 if (ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, 319 (PTRACE_TYPE_ARG3) &iov) == -1) 320 perror_with_name (_("Couldn't set registers")); 321 } 322 } 323 324 /* Access to CSRs has potential security issues, don't support them for 325 now. */ 326 } 327 328 /* Initialize RISC-V Linux native support. */ 329 330 void _initialize_riscv_linux_nat (); 331 void 332 _initialize_riscv_linux_nat () 333 { 334 /* Register the target. */ 335 linux_target = &the_riscv_linux_nat_target; 336 add_inf_child_target (&the_riscv_linux_nat_target); 337 } 338