xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/linux-riscv-low.cc (revision 64f917f5a88990e32dd65fcd4348042fa7f852b9)
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