17f2ac410Schristos /* Native-dependent code for GNU/Linux RISC-V. 2*6881a400Schristos Copyright (C) 2018-2023 Free Software Foundation, Inc. 37f2ac410Schristos 47f2ac410Schristos This file is part of GDB. 57f2ac410Schristos 67f2ac410Schristos This program is free software; you can redistribute it and/or modify 77f2ac410Schristos it under the terms of the GNU General Public License as published by 87f2ac410Schristos the Free Software Foundation; either version 3 of the License, or 97f2ac410Schristos (at your option) any later version. 107f2ac410Schristos 117f2ac410Schristos This program is distributed in the hope that it will be useful, 127f2ac410Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 137f2ac410Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 147f2ac410Schristos GNU General Public License for more details. 157f2ac410Schristos 167f2ac410Schristos You should have received a copy of the GNU General Public License 177f2ac410Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 187f2ac410Schristos 197f2ac410Schristos #include "defs.h" 207f2ac410Schristos #include "regcache.h" 217f2ac410Schristos #include "gregset.h" 227f2ac410Schristos #include "linux-nat.h" 237f2ac410Schristos #include "riscv-tdep.h" 247f2ac410Schristos #include "inferior.h" 257f2ac410Schristos 267f2ac410Schristos #include "elf/common.h" 277f2ac410Schristos 287d62b00eSchristos #include "nat/riscv-linux-tdesc.h" 297d62b00eSchristos 307f2ac410Schristos #include <sys/ptrace.h> 317f2ac410Schristos 327d62b00eSchristos /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */ 337d62b00eSchristos #ifndef NFPREG 347d62b00eSchristos # define NFPREG 33 357d62b00eSchristos #endif 367d62b00eSchristos 377f2ac410Schristos /* RISC-V Linux native additions to the default linux support. */ 387f2ac410Schristos 397f2ac410Schristos class riscv_linux_nat_target final : public linux_nat_target 407f2ac410Schristos { 417f2ac410Schristos public: 427f2ac410Schristos /* Add our register access methods. */ 437f2ac410Schristos void fetch_registers (struct regcache *regcache, int regnum) override; 447f2ac410Schristos void store_registers (struct regcache *regcache, int regnum) override; 457f2ac410Schristos 467f2ac410Schristos /* Read suitable target description. */ 477f2ac410Schristos const struct target_desc *read_description () override; 487f2ac410Schristos }; 497f2ac410Schristos 507f2ac410Schristos static riscv_linux_nat_target the_riscv_linux_nat_target; 517f2ac410Schristos 527f2ac410Schristos /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1) 537f2ac410Schristos from regset GREGS into REGCACHE. */ 547f2ac410Schristos 557f2ac410Schristos static void 567f2ac410Schristos supply_gregset_regnum (struct regcache *regcache, const prgregset_t *gregs, 577f2ac410Schristos int regnum) 587f2ac410Schristos { 597f2ac410Schristos int i; 607f2ac410Schristos const elf_greg_t *regp = *gregs; 617f2ac410Schristos 627f2ac410Schristos if (regnum == -1) 637f2ac410Schristos { 647f2ac410Schristos /* We only support the integer registers and PC here. */ 657f2ac410Schristos for (i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++) 667f2ac410Schristos regcache->raw_supply (i, regp + i); 677f2ac410Schristos 687f2ac410Schristos /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */ 69*6881a400Schristos regcache->raw_supply (RISCV_PC_REGNUM, regp + 0); 707f2ac410Schristos 717f2ac410Schristos /* Fill the inaccessible zero register with zero. */ 72*6881a400Schristos regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM); 737f2ac410Schristos } 747f2ac410Schristos else if (regnum == RISCV_ZERO_REGNUM) 75*6881a400Schristos regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM); 767f2ac410Schristos else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM) 777f2ac410Schristos regcache->raw_supply (regnum, regp + regnum); 787f2ac410Schristos else if (regnum == RISCV_PC_REGNUM) 79*6881a400Schristos regcache->raw_supply (RISCV_PC_REGNUM, regp + 0); 807f2ac410Schristos } 817f2ac410Schristos 827f2ac410Schristos /* Copy all general purpose registers from regset GREGS into REGCACHE. */ 837f2ac410Schristos 847f2ac410Schristos void 857f2ac410Schristos supply_gregset (struct regcache *regcache, const prgregset_t *gregs) 867f2ac410Schristos { 877f2ac410Schristos supply_gregset_regnum (regcache, gregs, -1); 887f2ac410Schristos } 897f2ac410Schristos 907f2ac410Schristos /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1) 917f2ac410Schristos from regset FPREGS into REGCACHE. */ 927f2ac410Schristos 937f2ac410Schristos static void 947f2ac410Schristos supply_fpregset_regnum (struct regcache *regcache, const prfpregset_t *fpregs, 957f2ac410Schristos int regnum) 967f2ac410Schristos { 977d62b00eSchristos int flen = register_size (regcache->arch (), RISCV_FIRST_FP_REGNUM); 987d62b00eSchristos union 997d62b00eSchristos { 1007d62b00eSchristos const prfpregset_t *fpregs; 1017d62b00eSchristos const gdb_byte *buf; 1027d62b00eSchristos } 1037d62b00eSchristos fpbuf = { .fpregs = fpregs }; 1047f2ac410Schristos int i; 1057f2ac410Schristos 1067f2ac410Schristos if (regnum == -1) 1077f2ac410Schristos { 1087f2ac410Schristos /* We only support the FP registers and FCSR here. */ 1097d62b00eSchristos for (i = RISCV_FIRST_FP_REGNUM; 1107d62b00eSchristos i <= RISCV_LAST_FP_REGNUM; 1117d62b00eSchristos i++, fpbuf.buf += flen) 1127d62b00eSchristos regcache->raw_supply (i, fpbuf.buf); 1137f2ac410Schristos 1147d62b00eSchristos regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 1157f2ac410Schristos } 1167f2ac410Schristos else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM) 1177d62b00eSchristos { 1187d62b00eSchristos fpbuf.buf += flen * (regnum - RISCV_FIRST_FP_REGNUM); 1197d62b00eSchristos regcache->raw_supply (regnum, fpbuf.buf); 1207d62b00eSchristos } 1217f2ac410Schristos else if (regnum == RISCV_CSR_FCSR_REGNUM) 1227d62b00eSchristos { 1237d62b00eSchristos fpbuf.buf += flen * (RISCV_LAST_FP_REGNUM - RISCV_FIRST_FP_REGNUM + 1); 1247d62b00eSchristos regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 1257d62b00eSchristos } 1267f2ac410Schristos } 1277f2ac410Schristos 1287f2ac410Schristos /* Copy all floating point registers from regset FPREGS into REGCACHE. */ 1297f2ac410Schristos 1307f2ac410Schristos void 1317f2ac410Schristos supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs) 1327f2ac410Schristos { 1337f2ac410Schristos supply_fpregset_regnum (regcache, fpregs, -1); 1347f2ac410Schristos } 1357f2ac410Schristos 1367f2ac410Schristos /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1) 1377f2ac410Schristos from REGCACHE into regset GREGS. */ 1387f2ac410Schristos 1397f2ac410Schristos void 1407f2ac410Schristos fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum) 1417f2ac410Schristos { 1427f2ac410Schristos elf_greg_t *regp = *gregs; 1437f2ac410Schristos 1447f2ac410Schristos if (regnum == -1) 1457f2ac410Schristos { 1467f2ac410Schristos /* We only support the integer registers and PC here. */ 1477f2ac410Schristos for (int i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++) 1487f2ac410Schristos regcache->raw_collect (i, regp + i); 1497f2ac410Schristos 150*6881a400Schristos regcache->raw_collect (RISCV_PC_REGNUM, regp + 0); 1517f2ac410Schristos } 1527f2ac410Schristos else if (regnum == RISCV_ZERO_REGNUM) 1537f2ac410Schristos /* Nothing to do here. */ 1547f2ac410Schristos ; 1557f2ac410Schristos else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM) 1567f2ac410Schristos regcache->raw_collect (regnum, regp + regnum); 1577f2ac410Schristos else if (regnum == RISCV_PC_REGNUM) 158*6881a400Schristos regcache->raw_collect (RISCV_PC_REGNUM, regp + 0); 1597f2ac410Schristos } 1607f2ac410Schristos 1617f2ac410Schristos /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1) 1627f2ac410Schristos from REGCACHE into regset FPREGS. */ 1637f2ac410Schristos 1647f2ac410Schristos void 1657f2ac410Schristos fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, 1667f2ac410Schristos int regnum) 1677f2ac410Schristos { 1687d62b00eSchristos int flen = register_size (regcache->arch (), RISCV_FIRST_FP_REGNUM); 1697d62b00eSchristos union 1707d62b00eSchristos { 1717d62b00eSchristos prfpregset_t *fpregs; 1727d62b00eSchristos gdb_byte *buf; 1737d62b00eSchristos } 1747d62b00eSchristos fpbuf = { .fpregs = fpregs }; 1757d62b00eSchristos int i; 1767d62b00eSchristos 1777f2ac410Schristos if (regnum == -1) 1787f2ac410Schristos { 1797f2ac410Schristos /* We only support the FP registers and FCSR here. */ 1807d62b00eSchristos for (i = RISCV_FIRST_FP_REGNUM; 1817d62b00eSchristos i <= RISCV_LAST_FP_REGNUM; 1827d62b00eSchristos i++, fpbuf.buf += flen) 1837d62b00eSchristos regcache->raw_collect (i, fpbuf.buf); 1847f2ac410Schristos 1857d62b00eSchristos regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 1867f2ac410Schristos } 1877f2ac410Schristos else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM) 1887d62b00eSchristos { 1897d62b00eSchristos fpbuf.buf += flen * (regnum - RISCV_FIRST_FP_REGNUM); 1907d62b00eSchristos regcache->raw_collect (regnum, fpbuf.buf); 1917d62b00eSchristos } 1927f2ac410Schristos else if (regnum == RISCV_CSR_FCSR_REGNUM) 1937d62b00eSchristos { 1947d62b00eSchristos fpbuf.buf += flen * (RISCV_LAST_FP_REGNUM - RISCV_FIRST_FP_REGNUM + 1); 1957d62b00eSchristos regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, fpbuf.buf); 1967d62b00eSchristos } 1977f2ac410Schristos } 1987f2ac410Schristos 1997f2ac410Schristos /* Return a target description for the current target. */ 2007f2ac410Schristos 2017f2ac410Schristos const struct target_desc * 2027f2ac410Schristos riscv_linux_nat_target::read_description () 2037f2ac410Schristos { 2047d62b00eSchristos const struct riscv_gdbarch_features features 205*6881a400Schristos = riscv_linux_read_features (inferior_ptid.pid ()); 2067d62b00eSchristos return riscv_lookup_target_description (features); 2077f2ac410Schristos } 2087f2ac410Schristos 2097f2ac410Schristos /* Fetch REGNUM (or all registers if REGNUM == -1) from the target 2107f2ac410Schristos into REGCACHE using PTRACE_GETREGSET. */ 2117f2ac410Schristos 2127f2ac410Schristos void 2137f2ac410Schristos riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) 2147f2ac410Schristos { 2157f2ac410Schristos int tid; 2167f2ac410Schristos 2177f2ac410Schristos tid = get_ptrace_pid (regcache->ptid()); 2187f2ac410Schristos 2197f2ac410Schristos if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM) 2207f2ac410Schristos || (regnum == -1)) 2217f2ac410Schristos { 2227f2ac410Schristos struct iovec iov; 2237f2ac410Schristos elf_gregset_t regs; 2247f2ac410Schristos 2257f2ac410Schristos iov.iov_base = ®s; 2267f2ac410Schristos iov.iov_len = sizeof (regs); 2277f2ac410Schristos 2287f2ac410Schristos if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, 2297f2ac410Schristos (PTRACE_TYPE_ARG3) &iov) == -1) 2307f2ac410Schristos perror_with_name (_("Couldn't get registers")); 2317f2ac410Schristos else 2327f2ac410Schristos supply_gregset_regnum (regcache, ®s, regnum); 2337f2ac410Schristos } 2347f2ac410Schristos 2357f2ac410Schristos if ((regnum >= RISCV_FIRST_FP_REGNUM 2367f2ac410Schristos && regnum <= RISCV_LAST_FP_REGNUM) 2377f2ac410Schristos || (regnum == RISCV_CSR_FCSR_REGNUM) 2387f2ac410Schristos || (regnum == -1)) 2397f2ac410Schristos { 2407f2ac410Schristos struct iovec iov; 2417f2ac410Schristos elf_fpregset_t regs; 2427f2ac410Schristos 2437f2ac410Schristos iov.iov_base = ®s; 2447d62b00eSchristos iov.iov_len = ELF_NFPREG * register_size (regcache->arch (), 2457d62b00eSchristos RISCV_FIRST_FP_REGNUM); 2467d62b00eSchristos gdb_assert (iov.iov_len <= sizeof (regs)); 2477f2ac410Schristos 2487f2ac410Schristos if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, 2497f2ac410Schristos (PTRACE_TYPE_ARG3) &iov) == -1) 2507f2ac410Schristos perror_with_name (_("Couldn't get registers")); 2517f2ac410Schristos else 2527f2ac410Schristos supply_fpregset_regnum (regcache, ®s, regnum); 2537f2ac410Schristos } 2547f2ac410Schristos 2557f2ac410Schristos if ((regnum == RISCV_CSR_MISA_REGNUM) 2567f2ac410Schristos || (regnum == -1)) 2577f2ac410Schristos { 2587f2ac410Schristos /* TODO: Need to add a ptrace call for this. */ 2597f2ac410Schristos regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM); 2607f2ac410Schristos } 2617f2ac410Schristos 2627f2ac410Schristos /* Access to other CSRs has potential security issues, don't support them for 2637f2ac410Schristos now. */ 2647f2ac410Schristos } 2657f2ac410Schristos 2667f2ac410Schristos /* Store REGNUM (or all registers if REGNUM == -1) to the target 2677f2ac410Schristos from REGCACHE using PTRACE_SETREGSET. */ 2687f2ac410Schristos 2697f2ac410Schristos void 2707f2ac410Schristos riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum) 2717f2ac410Schristos { 2727f2ac410Schristos int tid; 2737f2ac410Schristos 2747f2ac410Schristos tid = get_ptrace_pid (regcache->ptid ()); 2757f2ac410Schristos 2767f2ac410Schristos if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM) 2777f2ac410Schristos || (regnum == -1)) 2787f2ac410Schristos { 2797f2ac410Schristos struct iovec iov; 2807f2ac410Schristos elf_gregset_t regs; 2817f2ac410Schristos 2827f2ac410Schristos iov.iov_base = ®s; 2837f2ac410Schristos iov.iov_len = sizeof (regs); 2847f2ac410Schristos 2857f2ac410Schristos if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, 2867f2ac410Schristos (PTRACE_TYPE_ARG3) &iov) == -1) 2877f2ac410Schristos perror_with_name (_("Couldn't get registers")); 2887f2ac410Schristos else 2897f2ac410Schristos { 2907f2ac410Schristos fill_gregset (regcache, ®s, regnum); 2917f2ac410Schristos 2927f2ac410Schristos if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, 2937f2ac410Schristos (PTRACE_TYPE_ARG3) &iov) == -1) 2947f2ac410Schristos perror_with_name (_("Couldn't set registers")); 2957f2ac410Schristos } 2967f2ac410Schristos } 2977f2ac410Schristos 2987f2ac410Schristos if ((regnum >= RISCV_FIRST_FP_REGNUM 2997f2ac410Schristos && regnum <= RISCV_LAST_FP_REGNUM) 3007f2ac410Schristos || (regnum == RISCV_CSR_FCSR_REGNUM) 3017f2ac410Schristos || (regnum == -1)) 3027f2ac410Schristos { 3037f2ac410Schristos struct iovec iov; 3047f2ac410Schristos elf_fpregset_t regs; 3057f2ac410Schristos 3067f2ac410Schristos iov.iov_base = ®s; 3077d62b00eSchristos iov.iov_len = ELF_NFPREG * register_size (regcache->arch (), 3087d62b00eSchristos RISCV_FIRST_FP_REGNUM); 3097d62b00eSchristos gdb_assert (iov.iov_len <= sizeof (regs)); 3107f2ac410Schristos 3117f2ac410Schristos if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, 3127f2ac410Schristos (PTRACE_TYPE_ARG3) &iov) == -1) 3137f2ac410Schristos perror_with_name (_("Couldn't get registers")); 3147f2ac410Schristos else 3157f2ac410Schristos { 3167f2ac410Schristos fill_fpregset (regcache, ®s, regnum); 3177f2ac410Schristos 3187f2ac410Schristos if (ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET, 3197f2ac410Schristos (PTRACE_TYPE_ARG3) &iov) == -1) 3207f2ac410Schristos perror_with_name (_("Couldn't set registers")); 3217f2ac410Schristos } 3227f2ac410Schristos } 3237f2ac410Schristos 3247f2ac410Schristos /* Access to CSRs has potential security issues, don't support them for 3257f2ac410Schristos now. */ 3267f2ac410Schristos } 3277f2ac410Schristos 3287f2ac410Schristos /* Initialize RISC-V Linux native support. */ 3297f2ac410Schristos 3307d62b00eSchristos void _initialize_riscv_linux_nat (); 3317f2ac410Schristos void 3327d62b00eSchristos _initialize_riscv_linux_nat () 3337f2ac410Schristos { 3347f2ac410Schristos /* Register the target. */ 3357f2ac410Schristos linux_target = &the_riscv_linux_nat_target; 3367f2ac410Schristos add_inf_child_target (&the_riscv_linux_nat_target); 3377f2ac410Schristos } 338