RISC-V: Add native linux support.
[deliverable/binutils-gdb.git] / gdb / riscv-linux-nat.c
CommitLineData
3c77f97e
JW
1/* Native-dependent code for GNU/Linux RISC-V.
2 Copyright (C) 2018 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19#include "defs.h"
20#include "regcache.h"
21#include "gregset.h"
22#include "linux-nat.h"
23#include "elf.h"
24#include "riscv-tdep.h"
25
26#include <sys/ptrace.h>
27
28/* RISC-V Linux native additions to the default linux support. */
29
30class riscv_linux_nat_target final : public linux_nat_target
31{
32public:
33 /* Add our register access methods. */
34 void fetch_registers (struct regcache *regcache, int regnum) override;
35 void store_registers (struct regcache *regcache, int regnum) override;
36};
37
38static riscv_linux_nat_target the_riscv_linux_nat_target;
39
40/* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
41 from regset GREGS into REGCACHE. */
42
43static void
44supply_gregset_regnum (struct regcache *regcache, const prgregset_t *gregs,
45 int regnum)
46{
47 int i;
48 const elf_greg_t *regp = *gregs;
49
50 if (regnum == -1)
51 {
52 /* We only support the integer registers and PC here. */
53 for (i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++)
54 regcache->raw_supply (i, regp + i);
55
56 /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */
57 regcache->raw_supply (32, regp + 0);
58
59 /* Fill the inaccessible zero register with zero. */
60 regcache->raw_supply_zeroed (0);
61 }
62 else if (regnum == RISCV_ZERO_REGNUM)
63 regcache->raw_supply_zeroed (0);
64 else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM)
65 regcache->raw_supply (regnum, regp + regnum);
66 else if (regnum == RISCV_PC_REGNUM)
67 regcache->raw_supply (32, regp + 0);
68}
69
70/* Copy all general purpose registers from regset GREGS into REGCACHE. */
71
72void
73supply_gregset (struct regcache *regcache, const prgregset_t *gregs)
74{
75 supply_gregset_regnum (regcache, gregs, -1);
76}
77
78/* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
79 from regset FPREGS into REGCACHE. */
80
81static void
82supply_fpregset_regnum (struct regcache *regcache, const prfpregset_t *fpregs,
83 int regnum)
84{
85 int i;
86
87 if (regnum == -1)
88 {
89 /* We only support the FP registers and FCSR here. */
90 for (i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++)
91 regcache->raw_supply (i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]);
92
93 regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
94 }
95 else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
96 regcache->raw_supply (regnum,
97 &fpregs->__d.__f[regnum - RISCV_FIRST_FP_REGNUM]);
98 else if (regnum == RISCV_CSR_FCSR_REGNUM)
99 regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
100}
101
102/* Copy all floating point registers from regset FPREGS into REGCACHE. */
103
104void
105supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs)
106{
107 supply_fpregset_regnum (regcache, fpregs, -1);
108}
109
110/* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
111 from REGCACHE into regset GREGS. */
112
113void
114fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum)
115{
116 elf_greg_t *regp = *gregs;
117
118 if (regnum == -1)
119 {
120 /* We only support the integer registers and PC here. */
121 for (int i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++)
122 regcache->raw_collect (i, regp + i);
123
124 regcache->raw_collect (32, regp + 0);
125 }
126 else if (regnum == RISCV_ZERO_REGNUM)
127 /* Nothing to do here. */
128 ;
129 else if (regnum > RISCV_ZERO_REGNUM && regnum < RISCV_PC_REGNUM)
130 regcache->raw_collect (regnum, regp + regnum);
131 else if (regnum == RISCV_PC_REGNUM)
132 regcache->raw_collect (32, regp + 0);
133}
134
135/* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
136 from REGCACHE into regset FPREGS. */
137
138void
139fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs,
140 int regnum)
141{
142 if (regnum == -1)
143 {
144 /* We only support the FP registers and FCSR here. */
145 for (int i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++)
146 regcache->raw_collect (i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]);
147
148 regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
149 }
150 else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
151 regcache->raw_collect (regnum,
152 &fpregs->__d.__f[regnum - RISCV_FIRST_FP_REGNUM]);
153 else if (regnum == RISCV_CSR_FCSR_REGNUM)
154 regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
155}
156
157/* Fetch REGNUM (or all registers if REGNUM == -1) from the target
158 into REGCACHE using PTRACE_GETREGSET. */
159
160void
161riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
162{
163 int tid;
164
165 tid = get_ptrace_pid (regcache->ptid());
166
167 if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM)
168 || (regnum == -1))
169 {
170 struct iovec iov;
171 elf_gregset_t regs;
172
173 iov.iov_base = &regs;
174 iov.iov_len = sizeof (regs);
175
176 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS,
177 (PTRACE_TYPE_ARG3) &iov) == -1)
178 perror_with_name (_("Couldn't get registers"));
179 else
180 supply_gregset_regnum (regcache, &regs, regnum);
181 }
182
183 if ((regnum >= RISCV_FIRST_FP_REGNUM
184 && regnum <= RISCV_LAST_FP_REGNUM)
185 || (regnum == RISCV_CSR_FCSR_REGNUM)
186 || (regnum == -1))
187 {
188 struct iovec iov;
189 elf_fpregset_t regs;
190
191 iov.iov_base = &regs;
192 iov.iov_len = sizeof (regs);
193
194 if (ptrace (PTRACE_GETREGSET, tid, NT_PRFPREG,
195 (PTRACE_TYPE_ARG3) &iov) == -1)
196 perror_with_name (_("Couldn't get registers"));
197 else
198 supply_fpregset_regnum (regcache, &regs, regnum);
199 }
200
201 if ((regnum == RISCV_CSR_MISA_REGNUM)
202 || (regnum == -1))
203 {
204 /* TODO: Need to add a ptrace call for this. */
205 regcache->raw_supply_zeroed (regnum);
206 }
207
208 /* Access to other CSRs has potential security issues, don't support them for
209 now. */
210}
211
212/* Store REGNUM (or all registers if REGNUM == -1) to the target
213 from REGCACHE using PTRACE_SETREGSET. */
214
215void
216riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
217{
218 int tid;
219
220 tid = get_ptrace_pid (regcache->ptid ());
221
222 if ((regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_PC_REGNUM)
223 || (regnum == -1))
224 {
225 struct iovec iov;
226 elf_gregset_t regs;
227
228 iov.iov_base = &regs;
229 iov.iov_len = sizeof (regs);
230
231 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS,
232 (PTRACE_TYPE_ARG3) &iov) == -1)
233 perror_with_name (_("Couldn't get registers"));
234 else
235 {
236 fill_gregset (regcache, &regs, regnum);
237
238 if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS,
239 (PTRACE_TYPE_ARG3) &iov) == -1)
240 perror_with_name (_("Couldn't set registers"));
241 }
242 }
243
244 if ((regnum >= RISCV_FIRST_FP_REGNUM
245 && regnum <= RISCV_LAST_FP_REGNUM)
246 || (regnum == RISCV_CSR_FCSR_REGNUM)
247 || (regnum == -1))
248 {
249 struct iovec iov;
250 elf_fpregset_t regs;
251
252 iov.iov_base = &regs;
253 iov.iov_len = sizeof (regs);
254
255 if (ptrace (PTRACE_GETREGSET, tid, NT_PRFPREG,
256 (PTRACE_TYPE_ARG3) &iov) == -1)
257 perror_with_name (_("Couldn't get registers"));
258 else
259 {
260 fill_fpregset (regcache, &regs, regnum);
261
262 if (ptrace (PTRACE_SETREGSET, tid, NT_PRFPREG,
263 (PTRACE_TYPE_ARG3) &iov) == -1)
264 perror_with_name (_("Couldn't set registers"));
265 }
266 }
267
268 /* Access to CSRs has potential security issues, don't support them for
269 now. */
270}
271
272/* Initialize RISC-V Linux native support. */
273
274void
275_initialize_riscv_linux_nat (void)
276{
277 /* Register the target. */
278 linux_target = &the_riscv_linux_nat_target;
279 add_inf_child_target (&the_riscv_linux_nat_target);
280}
This page took 0.034506 seconds and 4 git commands to generate.