18dffb485Schristos /* GNU/Linux/RISC-V specific low level interface, for the remote server 28dffb485Schristos for GDB. 3*64f917f5Schristos Copyright (C) 2020-2024 Free Software Foundation, Inc. 48dffb485Schristos 58dffb485Schristos This file is part of GDB. 68dffb485Schristos 78dffb485Schristos This program is free software; you can redistribute it and/or modify 88dffb485Schristos it under the terms of the GNU General Public License as published by 98dffb485Schristos the Free Software Foundation; either version 3 of the License, or 108dffb485Schristos (at your option) any later version. 118dffb485Schristos 128dffb485Schristos This program is distributed in the hope that it will be useful, 138dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 148dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 158dffb485Schristos GNU General Public License for more details. 168dffb485Schristos 178dffb485Schristos You should have received a copy of the GNU General Public License 188dffb485Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 198dffb485Schristos 208dffb485Schristos 218dffb485Schristos #include "linux-low.h" 228dffb485Schristos #include "tdesc.h" 238dffb485Schristos #include "elf/common.h" 248dffb485Schristos #include "nat/riscv-linux-tdesc.h" 258dffb485Schristos #include "opcode/riscv.h" 268dffb485Schristos 278dffb485Schristos /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */ 288dffb485Schristos #ifndef NFPREG 298dffb485Schristos # define NFPREG 33 308dffb485Schristos #endif 318dffb485Schristos 328dffb485Schristos /* Linux target op definitions for the RISC-V architecture. */ 338dffb485Schristos 348dffb485Schristos class riscv_target : public linux_process_target 358dffb485Schristos { 368dffb485Schristos public: 378dffb485Schristos 388dffb485Schristos const regs_info *get_regs_info () override; 398dffb485Schristos 408dffb485Schristos int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override; 418dffb485Schristos 428dffb485Schristos const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; 438dffb485Schristos 448dffb485Schristos protected: 458dffb485Schristos 468dffb485Schristos void low_arch_setup () override; 478dffb485Schristos 488dffb485Schristos bool low_cannot_fetch_register (int regno) override; 498dffb485Schristos 508dffb485Schristos bool low_cannot_store_register (int regno) override; 518dffb485Schristos 528dffb485Schristos bool low_fetch_register (regcache *regcache, int regno) override; 538dffb485Schristos 548dffb485Schristos bool low_supports_breakpoints () override; 558dffb485Schristos 568dffb485Schristos CORE_ADDR low_get_pc (regcache *regcache) override; 578dffb485Schristos 588dffb485Schristos void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; 598dffb485Schristos 608dffb485Schristos bool low_breakpoint_at (CORE_ADDR pc) override; 618dffb485Schristos }; 628dffb485Schristos 638dffb485Schristos /* The singleton target ops object. */ 648dffb485Schristos 658dffb485Schristos static riscv_target the_riscv_target; 668dffb485Schristos 678dffb485Schristos bool 688dffb485Schristos riscv_target::low_cannot_fetch_register (int regno) 698dffb485Schristos { 708dffb485Schristos gdb_assert_not_reached ("linux target op low_cannot_fetch_register " 718dffb485Schristos "is not implemented by the target"); 728dffb485Schristos } 738dffb485Schristos 748dffb485Schristos bool 758dffb485Schristos riscv_target::low_cannot_store_register (int regno) 768dffb485Schristos { 778dffb485Schristos gdb_assert_not_reached ("linux target op low_cannot_store_register " 788dffb485Schristos "is not implemented by the target"); 798dffb485Schristos } 808dffb485Schristos 818dffb485Schristos /* Implementation of linux target ops method "low_arch_setup". */ 828dffb485Schristos 838dffb485Schristos void 848dffb485Schristos riscv_target::low_arch_setup () 858dffb485Schristos { 868dffb485Schristos static const char *expedite_regs[] = { "sp", "pc", NULL }; 878dffb485Schristos 888dffb485Schristos const riscv_gdbarch_features features 898dffb485Schristos = riscv_linux_read_features (lwpid_of (current_thread)); 904b169a6bSchristos target_desc_up tdesc = riscv_create_target_description (features); 918dffb485Schristos 92*64f917f5Schristos if (tdesc->expedite_regs.empty ()) 93*64f917f5Schristos { 944b169a6bSchristos init_target_desc (tdesc.get (), expedite_regs); 95*64f917f5Schristos gdb_assert (!tdesc->expedite_regs.empty ()); 96*64f917f5Schristos } 97*64f917f5Schristos 984b169a6bSchristos current_process ()->tdesc = tdesc.release (); 998dffb485Schristos } 1008dffb485Schristos 1018dffb485Schristos /* Collect GPRs from REGCACHE into BUF. */ 1028dffb485Schristos 1038dffb485Schristos static void 1048dffb485Schristos riscv_fill_gregset (struct regcache *regcache, void *buf) 1058dffb485Schristos { 1068dffb485Schristos const struct target_desc *tdesc = regcache->tdesc; 1078dffb485Schristos elf_gregset_t *regset = (elf_gregset_t *) buf; 1088dffb485Schristos int regno = find_regno (tdesc, "zero"); 1098dffb485Schristos int i; 1108dffb485Schristos 1118dffb485Schristos collect_register_by_name (regcache, "pc", *regset); 1128dffb485Schristos for (i = 1; i < ARRAY_SIZE (*regset); i++) 1138dffb485Schristos collect_register (regcache, regno + i, *regset + i); 1148dffb485Schristos } 1158dffb485Schristos 1168dffb485Schristos /* Supply GPRs from BUF into REGCACHE. */ 1178dffb485Schristos 1188dffb485Schristos static void 1198dffb485Schristos riscv_store_gregset (struct regcache *regcache, const void *buf) 1208dffb485Schristos { 1218dffb485Schristos const elf_gregset_t *regset = (const elf_gregset_t *) buf; 1228dffb485Schristos const struct target_desc *tdesc = regcache->tdesc; 1238dffb485Schristos int regno = find_regno (tdesc, "zero"); 1248dffb485Schristos int i; 1258dffb485Schristos 1268dffb485Schristos supply_register_by_name (regcache, "pc", *regset); 1278dffb485Schristos supply_register_zeroed (regcache, regno); 1288dffb485Schristos for (i = 1; i < ARRAY_SIZE (*regset); i++) 1298dffb485Schristos supply_register (regcache, regno + i, *regset + i); 1308dffb485Schristos } 1318dffb485Schristos 1328dffb485Schristos /* Collect FPRs from REGCACHE into BUF. */ 1338dffb485Schristos 1348dffb485Schristos static void 1358dffb485Schristos riscv_fill_fpregset (struct regcache *regcache, void *buf) 1368dffb485Schristos { 1378dffb485Schristos const struct target_desc *tdesc = regcache->tdesc; 1388dffb485Schristos int regno = find_regno (tdesc, "ft0"); 1398dffb485Schristos int flen = register_size (regcache->tdesc, regno); 1408dffb485Schristos gdb_byte *regbuf = (gdb_byte *) buf; 1418dffb485Schristos int i; 1428dffb485Schristos 1438dffb485Schristos for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen) 1448dffb485Schristos collect_register (regcache, regno + i, regbuf); 1458dffb485Schristos collect_register_by_name (regcache, "fcsr", regbuf); 1468dffb485Schristos } 1478dffb485Schristos 1488dffb485Schristos /* Supply FPRs from BUF into REGCACHE. */ 1498dffb485Schristos 1508dffb485Schristos static void 1518dffb485Schristos riscv_store_fpregset (struct regcache *regcache, const void *buf) 1528dffb485Schristos { 1538dffb485Schristos const struct target_desc *tdesc = regcache->tdesc; 1548dffb485Schristos int regno = find_regno (tdesc, "ft0"); 1558dffb485Schristos int flen = register_size (regcache->tdesc, regno); 1568dffb485Schristos const gdb_byte *regbuf = (const gdb_byte *) buf; 1578dffb485Schristos int i; 1588dffb485Schristos 1598dffb485Schristos for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen) 1608dffb485Schristos supply_register (regcache, regno + i, regbuf); 1618dffb485Schristos supply_register_by_name (regcache, "fcsr", regbuf); 1628dffb485Schristos } 1638dffb485Schristos 1648dffb485Schristos /* RISC-V/Linux regsets. FPRs are optional and come in different sizes, 1658dffb485Schristos so define multiple regsets for them marking them all as OPTIONAL_REGS 1668dffb485Schristos rather than FP_REGS, so that "regsets_fetch_inferior_registers" picks 1678dffb485Schristos the right one according to size. */ 1688dffb485Schristos static struct regset_info riscv_regsets[] = { 1698dffb485Schristos { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, 1708dffb485Schristos sizeof (elf_gregset_t), GENERAL_REGS, 1718dffb485Schristos riscv_fill_gregset, riscv_store_gregset }, 1728dffb485Schristos { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, 1738dffb485Schristos sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS, 1748dffb485Schristos riscv_fill_fpregset, riscv_store_fpregset }, 1758dffb485Schristos { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, 1768dffb485Schristos sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS, 1778dffb485Schristos riscv_fill_fpregset, riscv_store_fpregset }, 1788dffb485Schristos { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, 1798dffb485Schristos sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS, 1808dffb485Schristos riscv_fill_fpregset, riscv_store_fpregset }, 1818dffb485Schristos NULL_REGSET 1828dffb485Schristos }; 1838dffb485Schristos 1848dffb485Schristos /* RISC-V/Linux regset information. */ 1858dffb485Schristos static struct regsets_info riscv_regsets_info = 1868dffb485Schristos { 1878dffb485Schristos riscv_regsets, /* regsets */ 1888dffb485Schristos 0, /* num_regsets */ 1898dffb485Schristos NULL, /* disabled_regsets */ 1908dffb485Schristos }; 1918dffb485Schristos 1928dffb485Schristos /* Definition of linux_target_ops data member "regs_info". */ 1938dffb485Schristos static struct regs_info riscv_regs = 1948dffb485Schristos { 1958dffb485Schristos NULL, /* regset_bitmap */ 1968dffb485Schristos NULL, /* usrregs */ 1978dffb485Schristos &riscv_regsets_info, 1988dffb485Schristos }; 1998dffb485Schristos 2008dffb485Schristos /* Implementation of linux target ops method "get_regs_info". */ 2018dffb485Schristos 2028dffb485Schristos const regs_info * 2038dffb485Schristos riscv_target::get_regs_info () 2048dffb485Schristos { 2058dffb485Schristos return &riscv_regs; 2068dffb485Schristos } 2078dffb485Schristos 2088dffb485Schristos /* Implementation of linux target ops method "low_fetch_register". */ 2098dffb485Schristos 2108dffb485Schristos bool 2118dffb485Schristos riscv_target::low_fetch_register (regcache *regcache, int regno) 2128dffb485Schristos { 2138dffb485Schristos const struct target_desc *tdesc = regcache->tdesc; 2148dffb485Schristos 2158dffb485Schristos if (regno != find_regno (tdesc, "zero")) 2168dffb485Schristos return false; 2178dffb485Schristos supply_register_zeroed (regcache, regno); 2188dffb485Schristos return true; 2198dffb485Schristos } 2208dffb485Schristos 2218dffb485Schristos bool 2228dffb485Schristos riscv_target::low_supports_breakpoints () 2238dffb485Schristos { 2248dffb485Schristos return true; 2258dffb485Schristos } 2268dffb485Schristos 2278dffb485Schristos /* Implementation of linux target ops method "low_get_pc". */ 2288dffb485Schristos 2298dffb485Schristos CORE_ADDR 2308dffb485Schristos riscv_target::low_get_pc (regcache *regcache) 2318dffb485Schristos { 2328dffb485Schristos elf_gregset_t regset; 2338dffb485Schristos 2348dffb485Schristos if (sizeof (regset[0]) == 8) 2358dffb485Schristos return linux_get_pc_64bit (regcache); 2368dffb485Schristos else 2378dffb485Schristos return linux_get_pc_32bit (regcache); 2388dffb485Schristos } 2398dffb485Schristos 2408dffb485Schristos /* Implementation of linux target ops method "low_set_pc". */ 2418dffb485Schristos 2428dffb485Schristos void 2438dffb485Schristos riscv_target::low_set_pc (regcache *regcache, CORE_ADDR newpc) 2448dffb485Schristos { 2458dffb485Schristos elf_gregset_t regset; 2468dffb485Schristos 2478dffb485Schristos if (sizeof (regset[0]) == 8) 2488dffb485Schristos linux_set_pc_64bit (regcache, newpc); 2498dffb485Schristos else 2508dffb485Schristos linux_set_pc_32bit (regcache, newpc); 2518dffb485Schristos } 2528dffb485Schristos 2538dffb485Schristos /* Correct in either endianness. */ 2548dffb485Schristos static const uint16_t riscv_ibreakpoint[] = { 0x0073, 0x0010 }; 2558dffb485Schristos static const uint16_t riscv_cbreakpoint = 0x9002; 2568dffb485Schristos 2578dffb485Schristos /* Implementation of target ops method "breakpoint_kind_from_pc". */ 2588dffb485Schristos 2598dffb485Schristos int 2608dffb485Schristos riscv_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr) 2618dffb485Schristos { 2628dffb485Schristos union 2638dffb485Schristos { 2648dffb485Schristos gdb_byte bytes[2]; 2658dffb485Schristos uint16_t insn; 2668dffb485Schristos } 2678dffb485Schristos buf; 2688dffb485Schristos 2698dffb485Schristos if (target_read_memory (*pcptr, buf.bytes, sizeof (buf.insn)) == 0 2708dffb485Schristos && riscv_insn_length (buf.insn == sizeof (riscv_ibreakpoint))) 2718dffb485Schristos return sizeof (riscv_ibreakpoint); 2728dffb485Schristos else 2738dffb485Schristos return sizeof (riscv_cbreakpoint); 2748dffb485Schristos } 2758dffb485Schristos 2768dffb485Schristos /* Implementation of target ops method "sw_breakpoint_from_kind". */ 2778dffb485Schristos 2788dffb485Schristos const gdb_byte * 2798dffb485Schristos riscv_target::sw_breakpoint_from_kind (int kind, int *size) 2808dffb485Schristos { 2818dffb485Schristos *size = kind; 2828dffb485Schristos switch (kind) 2838dffb485Schristos { 2848dffb485Schristos case sizeof (riscv_ibreakpoint): 2858dffb485Schristos return (const gdb_byte *) &riscv_ibreakpoint; 2868dffb485Schristos default: 2878dffb485Schristos return (const gdb_byte *) &riscv_cbreakpoint; 2888dffb485Schristos } 2898dffb485Schristos } 2908dffb485Schristos 2918dffb485Schristos /* Implementation of linux target ops method "low_breakpoint_at". */ 2928dffb485Schristos 2938dffb485Schristos bool 2948dffb485Schristos riscv_target::low_breakpoint_at (CORE_ADDR pc) 2958dffb485Schristos { 2968dffb485Schristos union 2978dffb485Schristos { 2988dffb485Schristos gdb_byte bytes[2]; 2998dffb485Schristos uint16_t insn; 3008dffb485Schristos } 3018dffb485Schristos buf; 3028dffb485Schristos 3038dffb485Schristos if (target_read_memory (pc, buf.bytes, sizeof (buf.insn)) == 0 3048dffb485Schristos && (buf.insn == riscv_cbreakpoint 3058dffb485Schristos || (buf.insn == riscv_ibreakpoint[0] 3068dffb485Schristos && target_read_memory (pc + sizeof (buf.insn), buf.bytes, 3078dffb485Schristos sizeof (buf.insn)) == 0 3088dffb485Schristos && buf.insn == riscv_ibreakpoint[1]))) 3098dffb485Schristos return true; 3108dffb485Schristos else 3118dffb485Schristos return false; 3128dffb485Schristos } 3138dffb485Schristos 3148dffb485Schristos /* The linux target ops object. */ 3158dffb485Schristos 3168dffb485Schristos linux_process_target *the_linux_target = &the_riscv_target; 3178dffb485Schristos 3188dffb485Schristos /* Initialize the RISC-V/Linux target. */ 3198dffb485Schristos 3208dffb485Schristos void 3218dffb485Schristos initialize_low_arch () 3228dffb485Schristos { 3238dffb485Schristos initialize_regsets_info (&riscv_regsets_info); 3248dffb485Schristos } 325