]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdbserver/linux-riscv-low.cc
[PATCH] fix windmc typedef bug
[thirdparty/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 bool low_breakpoint_at (CORE_ADDR pc) override;
62 };
63
64 /* The singleton target ops object. */
65
66 static riscv_target the_riscv_target;
67
68 bool
69 riscv_target::low_cannot_fetch_register (int regno)
70 {
71 gdb_assert_not_reached ("linux target op low_cannot_fetch_register "
72 "is not implemented by the target");
73 }
74
75 bool
76 riscv_target::low_cannot_store_register (int regno)
77 {
78 gdb_assert_not_reached ("linux target op low_cannot_store_register "
79 "is not implemented by the target");
80 }
81
82 /* Implementation of linux target ops method "low_arch_setup". */
83
84 void
85 riscv_target::low_arch_setup ()
86 {
87 static const char *expedite_regs[] = { "sp", "pc", NULL };
88
89 const riscv_gdbarch_features features
90 = riscv_linux_read_features (lwpid_of (current_thread));
91 target_desc *tdesc = riscv_create_target_description (features);
92
93 if (!tdesc->expedite_regs)
94 init_target_desc (tdesc, expedite_regs);
95 current_process ()->tdesc = tdesc;
96 }
97
98 /* Collect GPRs from REGCACHE into BUF. */
99
100 static void
101 riscv_fill_gregset (struct regcache *regcache, void *buf)
102 {
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;
107
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);
111 }
112
113 /* Supply GPRs from BUF into REGCACHE. */
114
115 static void
116 riscv_store_gregset (struct regcache *regcache, const void *buf)
117 {
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;
122
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);
127 }
128
129 /* Collect FPRs from REGCACHE into BUF. */
130
131 static void
132 riscv_fill_fpregset (struct regcache *regcache, void *buf)
133 {
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;
139
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);
143 }
144
145 /* Supply FPRs from BUF into REGCACHE. */
146
147 static void
148 riscv_store_fpregset (struct regcache *regcache, const void *buf)
149 {
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;
155
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);
159 }
160
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
179 };
180
181 /* RISC-V/Linux regset information. */
182 static struct regsets_info riscv_regsets_info =
183 {
184 riscv_regsets, /* regsets */
185 0, /* num_regsets */
186 NULL, /* disabled_regsets */
187 };
188
189 /* Definition of linux_target_ops data member "regs_info". */
190 static struct regs_info riscv_regs =
191 {
192 NULL, /* regset_bitmap */
193 NULL, /* usrregs */
194 &riscv_regsets_info,
195 };
196
197 /* Implementation of linux target ops method "get_regs_info". */
198
199 const regs_info *
200 riscv_target::get_regs_info ()
201 {
202 return &riscv_regs;
203 }
204
205 /* Implementation of linux target ops method "low_fetch_register". */
206
207 bool
208 riscv_target::low_fetch_register (regcache *regcache, int regno)
209 {
210 const struct target_desc *tdesc = regcache->tdesc;
211
212 if (regno != find_regno (tdesc, "zero"))
213 return false;
214 supply_register_zeroed (regcache, regno);
215 return true;
216 }
217
218 bool
219 riscv_target::low_supports_breakpoints ()
220 {
221 return true;
222 }
223
224 /* Implementation of linux target ops method "low_get_pc". */
225
226 CORE_ADDR
227 riscv_target::low_get_pc (regcache *regcache)
228 {
229 elf_gregset_t regset;
230
231 if (sizeof (regset[0]) == 8)
232 return linux_get_pc_64bit (regcache);
233 else
234 return linux_get_pc_32bit (regcache);
235 }
236
237 /* Implementation of linux target ops method "low_set_pc". */
238
239 void
240 riscv_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
241 {
242 elf_gregset_t regset;
243
244 if (sizeof (regset[0]) == 8)
245 linux_set_pc_64bit (regcache, newpc);
246 else
247 linux_set_pc_32bit (regcache, newpc);
248 }
249
250 /* Correct in either endianness. */
251 static const uint16_t riscv_ibreakpoint[] = { 0x0073, 0x0010 };
252 static const uint16_t riscv_cbreakpoint = 0x9002;
253
254 /* Implementation of target ops method "breakpoint_kind_from_pc". */
255
256 int
257 riscv_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr)
258 {
259 union
260 {
261 gdb_byte bytes[2];
262 uint16_t insn;
263 }
264 buf;
265
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);
271 }
272
273 /* Implementation of target ops method "sw_breakpoint_from_kind". */
274
275 const gdb_byte *
276 riscv_target::sw_breakpoint_from_kind (int kind, int *size)
277 {
278 *size = kind;
279 switch (kind)
280 {
281 case sizeof (riscv_ibreakpoint):
282 return (const gdb_byte *) &riscv_ibreakpoint;
283 default:
284 return (const gdb_byte *) &riscv_cbreakpoint;
285 }
286 }
287
288 /* Implementation of linux target ops method "low_breakpoint_at". */
289
290 bool
291 riscv_target::low_breakpoint_at (CORE_ADDR pc)
292 {
293 union
294 {
295 gdb_byte bytes[2];
296 uint16_t insn;
297 }
298 buf;
299
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;
309 }
310
311 /* The linux target ops object. */
312
313 linux_process_target *the_linux_target = &the_riscv_target;
314
315 /* Initialize the RISC-V/Linux target. */
316
317 void
318 initialize_low_arch ()
319 {
320 initialize_regsets_info (&riscv_regsets_info);
321 }