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