1 /* Native-dependent code for GNU/Linux RISC-V.
2 Copyright (C) 2018-2020 Free Software Foundation, Inc.
4 This file is part of GDB.
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.
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.
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/>. */
22 #include "linux-nat.h"
23 #include "riscv-tdep.h"
26 #include "elf/common.h"
28 #include "nat/riscv-linux-tdesc.h"
30 #include <sys/ptrace.h>
32 /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */
37 /* RISC-V Linux native additions to the default linux support. */
39 class riscv_linux_nat_target final
: public linux_nat_target
42 /* Add our register access methods. */
43 void fetch_registers (struct regcache
*regcache
, int regnum
) override
;
44 void store_registers (struct regcache
*regcache
, int regnum
) override
;
46 /* Read suitable target description. */
47 const struct target_desc
*read_description () override
;
50 static riscv_linux_nat_target the_riscv_linux_nat_target
;
52 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
53 from regset GREGS into REGCACHE. */
56 supply_gregset_regnum (struct regcache
*regcache
, const prgregset_t
*gregs
,
60 const elf_greg_t
*regp
= *gregs
;
64 /* We only support the integer registers and PC here. */
65 for (i
= RISCV_ZERO_REGNUM
+ 1; i
< RISCV_PC_REGNUM
; i
++)
66 regcache
->raw_supply (i
, regp
+ i
);
68 /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */
69 regcache
->raw_supply (32, regp
+ 0);
71 /* Fill the inaccessible zero register with zero. */
72 regcache
->raw_supply_zeroed (0);
74 else if (regnum
== RISCV_ZERO_REGNUM
)
75 regcache
->raw_supply_zeroed (0);
76 else if (regnum
> RISCV_ZERO_REGNUM
&& regnum
< RISCV_PC_REGNUM
)
77 regcache
->raw_supply (regnum
, regp
+ regnum
);
78 else if (regnum
== RISCV_PC_REGNUM
)
79 regcache
->raw_supply (32, regp
+ 0);
82 /* Copy all general purpose registers from regset GREGS into REGCACHE. */
85 supply_gregset (struct regcache
*regcache
, const prgregset_t
*gregs
)
87 supply_gregset_regnum (regcache
, gregs
, -1);
90 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
91 from regset FPREGS into REGCACHE. */
94 supply_fpregset_regnum (struct regcache
*regcache
, const prfpregset_t
*fpregs
,
97 int flen
= register_size (regcache
->arch (), RISCV_FIRST_FP_REGNUM
);
100 const prfpregset_t
*fpregs
;
103 fpbuf
= { .fpregs
= fpregs
};
108 /* We only support the FP registers and FCSR here. */
109 for (i
= RISCV_FIRST_FP_REGNUM
;
110 i
<= RISCV_LAST_FP_REGNUM
;
111 i
++, fpbuf
.buf
+= flen
)
112 regcache
->raw_supply (i
, fpbuf
.buf
);
114 regcache
->raw_supply (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
116 else if (regnum
>= RISCV_FIRST_FP_REGNUM
&& regnum
<= RISCV_LAST_FP_REGNUM
)
118 fpbuf
.buf
+= flen
* (regnum
- RISCV_FIRST_FP_REGNUM
);
119 regcache
->raw_supply (regnum
, fpbuf
.buf
);
121 else if (regnum
== RISCV_CSR_FCSR_REGNUM
)
123 fpbuf
.buf
+= flen
* (RISCV_LAST_FP_REGNUM
- RISCV_FIRST_FP_REGNUM
+ 1);
124 regcache
->raw_supply (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
128 /* Copy all floating point registers from regset FPREGS into REGCACHE. */
131 supply_fpregset (struct regcache
*regcache
, const prfpregset_t
*fpregs
)
133 supply_fpregset_regnum (regcache
, fpregs
, -1);
136 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
137 from REGCACHE into regset GREGS. */
140 fill_gregset (const struct regcache
*regcache
, prgregset_t
*gregs
, int regnum
)
142 elf_greg_t
*regp
= *gregs
;
146 /* We only support the integer registers and PC here. */
147 for (int i
= RISCV_ZERO_REGNUM
+ 1; i
< RISCV_PC_REGNUM
; i
++)
148 regcache
->raw_collect (i
, regp
+ i
);
150 regcache
->raw_collect (32, regp
+ 0);
152 else if (regnum
== RISCV_ZERO_REGNUM
)
153 /* Nothing to do here. */
155 else if (regnum
> RISCV_ZERO_REGNUM
&& regnum
< RISCV_PC_REGNUM
)
156 regcache
->raw_collect (regnum
, regp
+ regnum
);
157 else if (regnum
== RISCV_PC_REGNUM
)
158 regcache
->raw_collect (32, regp
+ 0);
161 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
162 from REGCACHE into regset FPREGS. */
165 fill_fpregset (const struct regcache
*regcache
, prfpregset_t
*fpregs
,
168 int flen
= register_size (regcache
->arch (), RISCV_FIRST_FP_REGNUM
);
171 prfpregset_t
*fpregs
;
174 fpbuf
= { .fpregs
= fpregs
};
179 /* We only support the FP registers and FCSR here. */
180 for (i
= RISCV_FIRST_FP_REGNUM
;
181 i
<= RISCV_LAST_FP_REGNUM
;
182 i
++, fpbuf
.buf
+= flen
)
183 regcache
->raw_collect (i
, fpbuf
.buf
);
185 regcache
->raw_collect (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
187 else if (regnum
>= RISCV_FIRST_FP_REGNUM
&& regnum
<= RISCV_LAST_FP_REGNUM
)
189 fpbuf
.buf
+= flen
* (regnum
- RISCV_FIRST_FP_REGNUM
);
190 regcache
->raw_collect (regnum
, fpbuf
.buf
);
192 else if (regnum
== RISCV_CSR_FCSR_REGNUM
)
194 fpbuf
.buf
+= flen
* (RISCV_LAST_FP_REGNUM
- RISCV_FIRST_FP_REGNUM
+ 1);
195 regcache
->raw_collect (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
199 /* Return a target description for the current target. */
201 const struct target_desc
*
202 riscv_linux_nat_target::read_description ()
204 return riscv_linux_read_description (inferior_ptid
.lwp ());
207 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
208 into REGCACHE using PTRACE_GETREGSET. */
211 riscv_linux_nat_target::fetch_registers (struct regcache
*regcache
, int regnum
)
215 tid
= get_ptrace_pid (regcache
->ptid());
217 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
223 iov
.iov_base
= ®s
;
224 iov
.iov_len
= sizeof (regs
);
226 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
227 (PTRACE_TYPE_ARG3
) &iov
) == -1)
228 perror_with_name (_("Couldn't get registers"));
230 supply_gregset_regnum (regcache
, ®s
, regnum
);
233 if ((regnum
>= RISCV_FIRST_FP_REGNUM
234 && regnum
<= RISCV_LAST_FP_REGNUM
)
235 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
241 iov
.iov_base
= ®s
;
242 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
243 RISCV_FIRST_FP_REGNUM
);
244 gdb_assert (iov
.iov_len
<= sizeof (regs
));
246 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
247 (PTRACE_TYPE_ARG3
) &iov
) == -1)
248 perror_with_name (_("Couldn't get registers"));
250 supply_fpregset_regnum (regcache
, ®s
, regnum
);
253 if ((regnum
== RISCV_CSR_MISA_REGNUM
)
256 /* TODO: Need to add a ptrace call for this. */
257 regcache
->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM
);
260 /* Access to other CSRs has potential security issues, don't support them for
264 /* Store REGNUM (or all registers if REGNUM == -1) to the target
265 from REGCACHE using PTRACE_SETREGSET. */
268 riscv_linux_nat_target::store_registers (struct regcache
*regcache
, int regnum
)
272 tid
= get_ptrace_pid (regcache
->ptid ());
274 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
280 iov
.iov_base
= ®s
;
281 iov
.iov_len
= sizeof (regs
);
283 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
284 (PTRACE_TYPE_ARG3
) &iov
) == -1)
285 perror_with_name (_("Couldn't get registers"));
288 fill_gregset (regcache
, ®s
, regnum
);
290 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
,
291 (PTRACE_TYPE_ARG3
) &iov
) == -1)
292 perror_with_name (_("Couldn't set registers"));
296 if ((regnum
>= RISCV_FIRST_FP_REGNUM
297 && regnum
<= RISCV_LAST_FP_REGNUM
)
298 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
304 iov
.iov_base
= ®s
;
305 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
306 RISCV_FIRST_FP_REGNUM
);
307 gdb_assert (iov
.iov_len
<= sizeof (regs
));
309 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
310 (PTRACE_TYPE_ARG3
) &iov
) == -1)
311 perror_with_name (_("Couldn't get registers"));
314 fill_fpregset (regcache
, ®s
, regnum
);
316 if (ptrace (PTRACE_SETREGSET
, tid
, NT_FPREGSET
,
317 (PTRACE_TYPE_ARG3
) &iov
) == -1)
318 perror_with_name (_("Couldn't set registers"));
322 /* Access to CSRs has potential security issues, don't support them for
326 /* Initialize RISC-V Linux native support. */
328 void _initialize_riscv_linux_nat ();
330 _initialize_riscv_linux_nat ()
332 /* Register the target. */
333 linux_target
= &the_riscv_linux_nat_target
;
334 add_inf_child_target (&the_riscv_linux_nat_target
);