1 /* Native-dependent code for GNU/Linux RISC-V.
2 Copyright (C) 2018-2023 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 (RISCV_PC_REGNUM
, regp
+ 0);
71 /* Fill the inaccessible zero register with zero. */
72 regcache
->raw_supply_zeroed (RISCV_ZERO_REGNUM
);
74 else if (regnum
== RISCV_ZERO_REGNUM
)
75 regcache
->raw_supply_zeroed (RISCV_ZERO_REGNUM
);
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 (RISCV_PC_REGNUM
, 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 (RISCV_PC_REGNUM
, 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 (RISCV_PC_REGNUM
, 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 if (inferior_ptid
== null_ptid
)
205 return this->beneath ()->read_description ();
207 const struct riscv_gdbarch_features features
208 = riscv_linux_read_features (inferior_ptid
.pid ());
209 return riscv_lookup_target_description (features
);
212 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
213 into REGCACHE using PTRACE_GETREGSET. */
216 riscv_linux_nat_target::fetch_registers (struct regcache
*regcache
, int regnum
)
220 tid
= get_ptrace_pid (regcache
->ptid());
222 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
228 iov
.iov_base
= ®s
;
229 iov
.iov_len
= sizeof (regs
);
231 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
232 (PTRACE_TYPE_ARG3
) &iov
) == -1)
233 perror_with_name (_("Couldn't get registers"));
235 supply_gregset_regnum (regcache
, ®s
, regnum
);
238 if ((regnum
>= RISCV_FIRST_FP_REGNUM
239 && regnum
<= RISCV_LAST_FP_REGNUM
)
240 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
246 iov
.iov_base
= ®s
;
247 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
248 RISCV_FIRST_FP_REGNUM
);
249 gdb_assert (iov
.iov_len
<= sizeof (regs
));
251 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
252 (PTRACE_TYPE_ARG3
) &iov
) == -1)
253 perror_with_name (_("Couldn't get registers"));
255 supply_fpregset_regnum (regcache
, ®s
, regnum
);
258 if ((regnum
== RISCV_CSR_MISA_REGNUM
)
261 /* TODO: Need to add a ptrace call for this. */
262 regcache
->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM
);
265 /* Access to other CSRs has potential security issues, don't support them for
269 /* Store REGNUM (or all registers if REGNUM == -1) to the target
270 from REGCACHE using PTRACE_SETREGSET. */
273 riscv_linux_nat_target::store_registers (struct regcache
*regcache
, int regnum
)
277 tid
= get_ptrace_pid (regcache
->ptid ());
279 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
285 iov
.iov_base
= ®s
;
286 iov
.iov_len
= sizeof (regs
);
288 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
289 (PTRACE_TYPE_ARG3
) &iov
) == -1)
290 perror_with_name (_("Couldn't get registers"));
293 fill_gregset (regcache
, ®s
, regnum
);
295 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
,
296 (PTRACE_TYPE_ARG3
) &iov
) == -1)
297 perror_with_name (_("Couldn't set registers"));
301 if ((regnum
>= RISCV_FIRST_FP_REGNUM
302 && regnum
<= RISCV_LAST_FP_REGNUM
)
303 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
309 iov
.iov_base
= ®s
;
310 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
311 RISCV_FIRST_FP_REGNUM
);
312 gdb_assert (iov
.iov_len
<= sizeof (regs
));
314 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
315 (PTRACE_TYPE_ARG3
) &iov
) == -1)
316 perror_with_name (_("Couldn't get registers"));
319 fill_fpregset (regcache
, ®s
, regnum
);
321 if (ptrace (PTRACE_SETREGSET
, tid
, NT_FPREGSET
,
322 (PTRACE_TYPE_ARG3
) &iov
) == -1)
323 perror_with_name (_("Couldn't set registers"));
327 /* Access to CSRs has potential security issues, don't support them for
331 /* Initialize RISC-V Linux native support. */
333 void _initialize_riscv_linux_nat ();
335 _initialize_riscv_linux_nat ()
337 /* Register the target. */
338 linux_target
= &the_riscv_linux_nat_target
;
339 add_inf_child_target (&the_riscv_linux_nat_target
);