Rotate gdb/ChangeLog
[binutils-gdb.git] / gdbserver / linux-riscv-low.cc
blob32f191ea8516dcf5e768e95319db733501353c73
1 /* GNU/Linux/RISC-V specific low level interface, for the remote server
2 for GDB.
3 Copyright (C) 2020 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include "server.h"
22 #include "linux-low.h"
23 #include "tdesc.h"
24 #include "elf/common.h"
25 #include "nat/riscv-linux-tdesc.h"
26 #include "opcode/riscv.h"
28 /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */
29 #ifndef NFPREG
30 # define NFPREG 33
31 #endif
33 /* Linux target op definitions for the RISC-V architecture. */
35 class riscv_target : public linux_process_target
37 public:
39 const regs_info *get_regs_info () override;
41 int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override;
43 const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
45 protected:
47 void low_arch_setup () override;
49 bool low_cannot_fetch_register (int regno) override;
51 bool low_cannot_store_register (int regno) override;
53 bool low_fetch_register (regcache *regcache, int regno) override;
55 bool low_supports_breakpoints () override;
57 CORE_ADDR low_get_pc (regcache *regcache) override;
59 void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
61 bool low_breakpoint_at (CORE_ADDR pc) override;
64 /* The singleton target ops object. */
66 static riscv_target the_riscv_target;
68 bool
69 riscv_target::low_cannot_fetch_register (int regno)
71 gdb_assert_not_reached ("linux target op low_cannot_fetch_register "
72 "is not implemented by the target");
75 bool
76 riscv_target::low_cannot_store_register (int regno)
78 gdb_assert_not_reached ("linux target op low_cannot_store_register "
79 "is not implemented by the target");
82 /* Implementation of linux target ops method "low_arch_setup". */
84 void
85 riscv_target::low_arch_setup ()
87 static const char *expedite_regs[] = { "sp", "pc", NULL };
89 const riscv_gdbarch_features features
90 = riscv_linux_read_features (lwpid_of (current_thread));
91 target_desc_up tdesc = riscv_create_target_description (features);
93 if (!tdesc->expedite_regs)
94 init_target_desc (tdesc.get (), expedite_regs);
95 current_process ()->tdesc = tdesc.release ();
98 /* Collect GPRs from REGCACHE into BUF. */
100 static void
101 riscv_fill_gregset (struct regcache *regcache, void *buf)
103 const struct target_desc *tdesc = regcache->tdesc;
104 elf_gregset_t *regset = (elf_gregset_t *) buf;
105 int regno = find_regno (tdesc, "zero");
106 int i;
108 collect_register_by_name (regcache, "pc", *regset);
109 for (i = 1; i < ARRAY_SIZE (*regset); i++)
110 collect_register (regcache, regno + i, *regset + i);
113 /* Supply GPRs from BUF into REGCACHE. */
115 static void
116 riscv_store_gregset (struct regcache *regcache, const void *buf)
118 const elf_gregset_t *regset = (const elf_gregset_t *) buf;
119 const struct target_desc *tdesc = regcache->tdesc;
120 int regno = find_regno (tdesc, "zero");
121 int i;
123 supply_register_by_name (regcache, "pc", *regset);
124 supply_register_zeroed (regcache, regno);
125 for (i = 1; i < ARRAY_SIZE (*regset); i++)
126 supply_register (regcache, regno + i, *regset + i);
129 /* Collect FPRs from REGCACHE into BUF. */
131 static void
132 riscv_fill_fpregset (struct regcache *regcache, void *buf)
134 const struct target_desc *tdesc = regcache->tdesc;
135 int regno = find_regno (tdesc, "ft0");
136 int flen = register_size (regcache->tdesc, regno);
137 gdb_byte *regbuf = (gdb_byte *) buf;
138 int i;
140 for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen)
141 collect_register (regcache, regno + i, regbuf);
142 collect_register_by_name (regcache, "fcsr", regbuf);
145 /* Supply FPRs from BUF into REGCACHE. */
147 static void
148 riscv_store_fpregset (struct regcache *regcache, const void *buf)
150 const struct target_desc *tdesc = regcache->tdesc;
151 int regno = find_regno (tdesc, "ft0");
152 int flen = register_size (regcache->tdesc, regno);
153 const gdb_byte *regbuf = (const gdb_byte *) buf;
154 int i;
156 for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen)
157 supply_register (regcache, regno + i, regbuf);
158 supply_register_by_name (regcache, "fcsr", regbuf);
161 /* RISC-V/Linux regsets. FPRs are optional and come in different sizes,
162 so define multiple regsets for them marking them all as OPTIONAL_REGS
163 rather than FP_REGS, so that "regsets_fetch_inferior_registers" picks
164 the right one according to size. */
165 static struct regset_info riscv_regsets[] = {
166 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
167 sizeof (elf_gregset_t), GENERAL_REGS,
168 riscv_fill_gregset, riscv_store_gregset },
169 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
170 sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS,
171 riscv_fill_fpregset, riscv_store_fpregset },
172 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
173 sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS,
174 riscv_fill_fpregset, riscv_store_fpregset },
175 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
176 sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS,
177 riscv_fill_fpregset, riscv_store_fpregset },
178 NULL_REGSET
181 /* RISC-V/Linux regset information. */
182 static struct regsets_info riscv_regsets_info =
184 riscv_regsets, /* regsets */
185 0, /* num_regsets */
186 NULL, /* disabled_regsets */
189 /* Definition of linux_target_ops data member "regs_info". */
190 static struct regs_info riscv_regs =
192 NULL, /* regset_bitmap */
193 NULL, /* usrregs */
194 &riscv_regsets_info,
197 /* Implementation of linux target ops method "get_regs_info". */
199 const regs_info *
200 riscv_target::get_regs_info ()
202 return &riscv_regs;
205 /* Implementation of linux target ops method "low_fetch_register". */
207 bool
208 riscv_target::low_fetch_register (regcache *regcache, int regno)
210 const struct target_desc *tdesc = regcache->tdesc;
212 if (regno != find_regno (tdesc, "zero"))
213 return false;
214 supply_register_zeroed (regcache, regno);
215 return true;
218 bool
219 riscv_target::low_supports_breakpoints ()
221 return true;
224 /* Implementation of linux target ops method "low_get_pc". */
226 CORE_ADDR
227 riscv_target::low_get_pc (regcache *regcache)
229 elf_gregset_t regset;
231 if (sizeof (regset[0]) == 8)
232 return linux_get_pc_64bit (regcache);
233 else
234 return linux_get_pc_32bit (regcache);
237 /* Implementation of linux target ops method "low_set_pc". */
239 void
240 riscv_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
242 elf_gregset_t regset;
244 if (sizeof (regset[0]) == 8)
245 linux_set_pc_64bit (regcache, newpc);
246 else
247 linux_set_pc_32bit (regcache, newpc);
250 /* Correct in either endianness. */
251 static const uint16_t riscv_ibreakpoint[] = { 0x0073, 0x0010 };
252 static const uint16_t riscv_cbreakpoint = 0x9002;
254 /* Implementation of target ops method "breakpoint_kind_from_pc". */
257 riscv_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr)
259 union
261 gdb_byte bytes[2];
262 uint16_t insn;
264 buf;
266 if (target_read_memory (*pcptr, buf.bytes, sizeof (buf.insn)) == 0
267 && riscv_insn_length (buf.insn == sizeof (riscv_ibreakpoint)))
268 return sizeof (riscv_ibreakpoint);
269 else
270 return sizeof (riscv_cbreakpoint);
273 /* Implementation of target ops method "sw_breakpoint_from_kind". */
275 const gdb_byte *
276 riscv_target::sw_breakpoint_from_kind (int kind, int *size)
278 *size = kind;
279 switch (kind)
281 case sizeof (riscv_ibreakpoint):
282 return (const gdb_byte *) &riscv_ibreakpoint;
283 default:
284 return (const gdb_byte *) &riscv_cbreakpoint;
288 /* Implementation of linux target ops method "low_breakpoint_at". */
290 bool
291 riscv_target::low_breakpoint_at (CORE_ADDR pc)
293 union
295 gdb_byte bytes[2];
296 uint16_t insn;
298 buf;
300 if (target_read_memory (pc, buf.bytes, sizeof (buf.insn)) == 0
301 && (buf.insn == riscv_cbreakpoint
302 || (buf.insn == riscv_ibreakpoint[0]
303 && target_read_memory (pc + sizeof (buf.insn), buf.bytes,
304 sizeof (buf.insn)) == 0
305 && buf.insn == riscv_ibreakpoint[1])))
306 return true;
307 else
308 return false;
311 /* The linux target ops object. */
313 linux_process_target *the_linux_target = &the_riscv_target;
315 /* Initialize the RISC-V/Linux target. */
317 void
318 initialize_low_arch ()
320 initialize_regsets_info (&riscv_regsets_info);