1 /* GNU/Linux/RISC-V specific low level interface, for the remote server 2 for GDB. 3 Copyright (C) 2020-2024 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 21 #include "linux-low.h" 22 #include "tdesc.h" 23 #include "elf/common.h" 24 #include "nat/riscv-linux-tdesc.h" 25 #include "opcode/riscv.h" 26 27 /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */ 28 #ifndef NFPREG 29 # define NFPREG 33 30 #endif 31 32 /* Linux target op definitions for the RISC-V architecture. */ 33 34 class riscv_target : public linux_process_target 35 { 36 public: 37 38 const regs_info *get_regs_info () override; 39 40 int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override; 41 42 const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; 43 44 protected: 45 46 void low_arch_setup () override; 47 48 bool low_cannot_fetch_register (int regno) override; 49 50 bool low_cannot_store_register (int regno) override; 51 52 bool low_fetch_register (regcache *regcache, int regno) override; 53 54 bool low_supports_breakpoints () override; 55 56 CORE_ADDR low_get_pc (regcache *regcache) override; 57 58 void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; 59 60 bool low_breakpoint_at (CORE_ADDR pc) override; 61 }; 62 63 /* The singleton target ops object. */ 64 65 static riscv_target the_riscv_target; 66 67 bool 68 riscv_target::low_cannot_fetch_register (int regno) 69 { 70 gdb_assert_not_reached ("linux target op low_cannot_fetch_register " 71 "is not implemented by the target"); 72 } 73 74 bool 75 riscv_target::low_cannot_store_register (int regno) 76 { 77 gdb_assert_not_reached ("linux target op low_cannot_store_register " 78 "is not implemented by the target"); 79 } 80 81 /* Implementation of linux target ops method "low_arch_setup". */ 82 83 void 84 riscv_target::low_arch_setup () 85 { 86 static const char *expedite_regs[] = { "sp", "pc", NULL }; 87 88 const riscv_gdbarch_features features 89 = riscv_linux_read_features (lwpid_of (current_thread)); 90 target_desc_up tdesc = riscv_create_target_description (features); 91 92 if (tdesc->expedite_regs.empty ()) 93 { 94 init_target_desc (tdesc.get (), expedite_regs); 95 gdb_assert (!tdesc->expedite_regs.empty ()); 96 } 97 98 current_process ()->tdesc = tdesc.release (); 99 } 100 101 /* Collect GPRs from REGCACHE into BUF. */ 102 103 static void 104 riscv_fill_gregset (struct regcache *regcache, void *buf) 105 { 106 const struct target_desc *tdesc = regcache->tdesc; 107 elf_gregset_t *regset = (elf_gregset_t *) buf; 108 int regno = find_regno (tdesc, "zero"); 109 int i; 110 111 collect_register_by_name (regcache, "pc", *regset); 112 for (i = 1; i < ARRAY_SIZE (*regset); i++) 113 collect_register (regcache, regno + i, *regset + i); 114 } 115 116 /* Supply GPRs from BUF into REGCACHE. */ 117 118 static void 119 riscv_store_gregset (struct regcache *regcache, const void *buf) 120 { 121 const elf_gregset_t *regset = (const elf_gregset_t *) buf; 122 const struct target_desc *tdesc = regcache->tdesc; 123 int regno = find_regno (tdesc, "zero"); 124 int i; 125 126 supply_register_by_name (regcache, "pc", *regset); 127 supply_register_zeroed (regcache, regno); 128 for (i = 1; i < ARRAY_SIZE (*regset); i++) 129 supply_register (regcache, regno + i, *regset + i); 130 } 131 132 /* Collect FPRs from REGCACHE into BUF. */ 133 134 static void 135 riscv_fill_fpregset (struct regcache *regcache, void *buf) 136 { 137 const struct target_desc *tdesc = regcache->tdesc; 138 int regno = find_regno (tdesc, "ft0"); 139 int flen = register_size (regcache->tdesc, regno); 140 gdb_byte *regbuf = (gdb_byte *) buf; 141 int i; 142 143 for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen) 144 collect_register (regcache, regno + i, regbuf); 145 collect_register_by_name (regcache, "fcsr", regbuf); 146 } 147 148 /* Supply FPRs from BUF into REGCACHE. */ 149 150 static void 151 riscv_store_fpregset (struct regcache *regcache, const void *buf) 152 { 153 const struct target_desc *tdesc = regcache->tdesc; 154 int regno = find_regno (tdesc, "ft0"); 155 int flen = register_size (regcache->tdesc, regno); 156 const gdb_byte *regbuf = (const gdb_byte *) buf; 157 int i; 158 159 for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen) 160 supply_register (regcache, regno + i, regbuf); 161 supply_register_by_name (regcache, "fcsr", regbuf); 162 } 163 164 /* RISC-V/Linux regsets. FPRs are optional and come in different sizes, 165 so define multiple regsets for them marking them all as OPTIONAL_REGS 166 rather than FP_REGS, so that "regsets_fetch_inferior_registers" picks 167 the right one according to size. */ 168 static struct regset_info riscv_regsets[] = { 169 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, 170 sizeof (elf_gregset_t), GENERAL_REGS, 171 riscv_fill_gregset, riscv_store_gregset }, 172 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, 173 sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS, 174 riscv_fill_fpregset, riscv_store_fpregset }, 175 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, 176 sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS, 177 riscv_fill_fpregset, riscv_store_fpregset }, 178 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, 179 sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS, 180 riscv_fill_fpregset, riscv_store_fpregset }, 181 NULL_REGSET 182 }; 183 184 /* RISC-V/Linux regset information. */ 185 static struct regsets_info riscv_regsets_info = 186 { 187 riscv_regsets, /* regsets */ 188 0, /* num_regsets */ 189 NULL, /* disabled_regsets */ 190 }; 191 192 /* Definition of linux_target_ops data member "regs_info". */ 193 static struct regs_info riscv_regs = 194 { 195 NULL, /* regset_bitmap */ 196 NULL, /* usrregs */ 197 &riscv_regsets_info, 198 }; 199 200 /* Implementation of linux target ops method "get_regs_info". */ 201 202 const regs_info * 203 riscv_target::get_regs_info () 204 { 205 return &riscv_regs; 206 } 207 208 /* Implementation of linux target ops method "low_fetch_register". */ 209 210 bool 211 riscv_target::low_fetch_register (regcache *regcache, int regno) 212 { 213 const struct target_desc *tdesc = regcache->tdesc; 214 215 if (regno != find_regno (tdesc, "zero")) 216 return false; 217 supply_register_zeroed (regcache, regno); 218 return true; 219 } 220 221 bool 222 riscv_target::low_supports_breakpoints () 223 { 224 return true; 225 } 226 227 /* Implementation of linux target ops method "low_get_pc". */ 228 229 CORE_ADDR 230 riscv_target::low_get_pc (regcache *regcache) 231 { 232 elf_gregset_t regset; 233 234 if (sizeof (regset[0]) == 8) 235 return linux_get_pc_64bit (regcache); 236 else 237 return linux_get_pc_32bit (regcache); 238 } 239 240 /* Implementation of linux target ops method "low_set_pc". */ 241 242 void 243 riscv_target::low_set_pc (regcache *regcache, CORE_ADDR newpc) 244 { 245 elf_gregset_t regset; 246 247 if (sizeof (regset[0]) == 8) 248 linux_set_pc_64bit (regcache, newpc); 249 else 250 linux_set_pc_32bit (regcache, newpc); 251 } 252 253 /* Correct in either endianness. */ 254 static const uint16_t riscv_ibreakpoint[] = { 0x0073, 0x0010 }; 255 static const uint16_t riscv_cbreakpoint = 0x9002; 256 257 /* Implementation of target ops method "breakpoint_kind_from_pc". */ 258 259 int 260 riscv_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr) 261 { 262 union 263 { 264 gdb_byte bytes[2]; 265 uint16_t insn; 266 } 267 buf; 268 269 if (target_read_memory (*pcptr, buf.bytes, sizeof (buf.insn)) == 0 270 && riscv_insn_length (buf.insn == sizeof (riscv_ibreakpoint))) 271 return sizeof (riscv_ibreakpoint); 272 else 273 return sizeof (riscv_cbreakpoint); 274 } 275 276 /* Implementation of target ops method "sw_breakpoint_from_kind". */ 277 278 const gdb_byte * 279 riscv_target::sw_breakpoint_from_kind (int kind, int *size) 280 { 281 *size = kind; 282 switch (kind) 283 { 284 case sizeof (riscv_ibreakpoint): 285 return (const gdb_byte *) &riscv_ibreakpoint; 286 default: 287 return (const gdb_byte *) &riscv_cbreakpoint; 288 } 289 } 290 291 /* Implementation of linux target ops method "low_breakpoint_at". */ 292 293 bool 294 riscv_target::low_breakpoint_at (CORE_ADDR pc) 295 { 296 union 297 { 298 gdb_byte bytes[2]; 299 uint16_t insn; 300 } 301 buf; 302 303 if (target_read_memory (pc, buf.bytes, sizeof (buf.insn)) == 0 304 && (buf.insn == riscv_cbreakpoint 305 || (buf.insn == riscv_ibreakpoint[0] 306 && target_read_memory (pc + sizeof (buf.insn), buf.bytes, 307 sizeof (buf.insn)) == 0 308 && buf.insn == riscv_ibreakpoint[1]))) 309 return true; 310 else 311 return false; 312 } 313 314 /* The linux target ops object. */ 315 316 linux_process_target *the_linux_target = &the_riscv_target; 317 318 /* Initialize the RISC-V/Linux target. */ 319 320 void 321 initialize_low_arch () 322 { 323 initialize_regsets_info (&riscv_regsets_info); 324 } 325