1 /* Native-dependent code for GNU/Linux RISC-V.
2 Copyright (C) 2018-2024 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/>. */
21 #include "linux-nat.h"
22 #include "riscv-tdep.h"
25 #include "elf/common.h"
27 #include "nat/riscv-linux-tdesc.h"
29 #include <sys/ptrace.h>
31 /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */
36 /* RISC-V Linux native additions to the default linux support. */
38 class riscv_linux_nat_target final
: public linux_nat_target
41 /* Add our register access methods. */
42 void fetch_registers (struct regcache
*regcache
, int regnum
) override
;
43 void store_registers (struct regcache
*regcache
, int regnum
) override
;
45 /* Read suitable target description. */
46 const struct target_desc
*read_description () override
;
49 static riscv_linux_nat_target the_riscv_linux_nat_target
;
51 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
52 from regset GREGS into REGCACHE. */
55 supply_gregset_regnum (struct regcache
*regcache
, const prgregset_t
*gregs
,
59 const elf_greg_t
*regp
= *gregs
;
63 /* We only support the integer registers and PC here. */
64 for (i
= RISCV_ZERO_REGNUM
+ 1; i
< RISCV_PC_REGNUM
; i
++)
65 regcache
->raw_supply (i
, regp
+ i
);
67 /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */
68 regcache
->raw_supply (RISCV_PC_REGNUM
, regp
+ 0);
70 /* Fill the inaccessible zero register with zero. */
71 regcache
->raw_supply_zeroed (RISCV_ZERO_REGNUM
);
73 else if (regnum
== RISCV_ZERO_REGNUM
)
74 regcache
->raw_supply_zeroed (RISCV_ZERO_REGNUM
);
75 else if (regnum
> RISCV_ZERO_REGNUM
&& regnum
< RISCV_PC_REGNUM
)
76 regcache
->raw_supply (regnum
, regp
+ regnum
);
77 else if (regnum
== RISCV_PC_REGNUM
)
78 regcache
->raw_supply (RISCV_PC_REGNUM
, regp
+ 0);
81 /* Copy all general purpose registers from regset GREGS into REGCACHE. */
84 supply_gregset (struct regcache
*regcache
, const prgregset_t
*gregs
)
86 supply_gregset_regnum (regcache
, gregs
, -1);
89 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
90 from regset FPREGS into REGCACHE. */
93 supply_fpregset_regnum (struct regcache
*regcache
, const prfpregset_t
*fpregs
,
96 int flen
= register_size (regcache
->arch (), RISCV_FIRST_FP_REGNUM
);
99 const prfpregset_t
*fpregs
;
102 fpbuf
= { .fpregs
= fpregs
};
107 /* We only support the FP registers and FCSR here. */
108 for (i
= RISCV_FIRST_FP_REGNUM
;
109 i
<= RISCV_LAST_FP_REGNUM
;
110 i
++, fpbuf
.buf
+= flen
)
111 regcache
->raw_supply (i
, fpbuf
.buf
);
113 regcache
->raw_supply (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
115 else if (regnum
>= RISCV_FIRST_FP_REGNUM
&& regnum
<= RISCV_LAST_FP_REGNUM
)
117 fpbuf
.buf
+= flen
* (regnum
- RISCV_FIRST_FP_REGNUM
);
118 regcache
->raw_supply (regnum
, fpbuf
.buf
);
120 else if (regnum
== RISCV_CSR_FCSR_REGNUM
)
122 fpbuf
.buf
+= flen
* (RISCV_LAST_FP_REGNUM
- RISCV_FIRST_FP_REGNUM
+ 1);
123 regcache
->raw_supply (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
127 /* Copy all floating point registers from regset FPREGS into REGCACHE. */
130 supply_fpregset (struct regcache
*regcache
, const prfpregset_t
*fpregs
)
132 supply_fpregset_regnum (regcache
, fpregs
, -1);
135 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
136 from REGCACHE into regset GREGS. */
139 fill_gregset (const struct regcache
*regcache
, prgregset_t
*gregs
, int regnum
)
141 elf_greg_t
*regp
= *gregs
;
145 /* We only support the integer registers and PC here. */
146 for (int i
= RISCV_ZERO_REGNUM
+ 1; i
< RISCV_PC_REGNUM
; i
++)
147 regcache
->raw_collect (i
, regp
+ i
);
149 regcache
->raw_collect (RISCV_PC_REGNUM
, regp
+ 0);
151 else if (regnum
== RISCV_ZERO_REGNUM
)
152 /* Nothing to do here. */
154 else if (regnum
> RISCV_ZERO_REGNUM
&& regnum
< RISCV_PC_REGNUM
)
155 regcache
->raw_collect (regnum
, regp
+ regnum
);
156 else if (regnum
== RISCV_PC_REGNUM
)
157 regcache
->raw_collect (RISCV_PC_REGNUM
, regp
+ 0);
160 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
161 from REGCACHE into regset FPREGS. */
164 fill_fpregset (const struct regcache
*regcache
, prfpregset_t
*fpregs
,
167 int flen
= register_size (regcache
->arch (), RISCV_FIRST_FP_REGNUM
);
170 prfpregset_t
*fpregs
;
173 fpbuf
= { .fpregs
= fpregs
};
178 /* We only support the FP registers and FCSR here. */
179 for (i
= RISCV_FIRST_FP_REGNUM
;
180 i
<= RISCV_LAST_FP_REGNUM
;
181 i
++, fpbuf
.buf
+= flen
)
182 regcache
->raw_collect (i
, fpbuf
.buf
);
184 regcache
->raw_collect (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
186 else if (regnum
>= RISCV_FIRST_FP_REGNUM
&& regnum
<= RISCV_LAST_FP_REGNUM
)
188 fpbuf
.buf
+= flen
* (regnum
- RISCV_FIRST_FP_REGNUM
);
189 regcache
->raw_collect (regnum
, fpbuf
.buf
);
191 else if (regnum
== RISCV_CSR_FCSR_REGNUM
)
193 fpbuf
.buf
+= flen
* (RISCV_LAST_FP_REGNUM
- RISCV_FIRST_FP_REGNUM
+ 1);
194 regcache
->raw_collect (RISCV_CSR_FCSR_REGNUM
, fpbuf
.buf
);
198 /* Return a target description for the current target. */
200 const struct target_desc
*
201 riscv_linux_nat_target::read_description ()
203 if (inferior_ptid
== null_ptid
)
204 return this->beneath ()->read_description ();
206 const struct riscv_gdbarch_features features
207 = riscv_linux_read_features (inferior_ptid
.pid ());
208 return riscv_lookup_target_description (features
);
211 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
212 into REGCACHE using PTRACE_GETREGSET. */
215 riscv_linux_nat_target::fetch_registers (struct regcache
*regcache
, int regnum
)
219 tid
= get_ptrace_pid (regcache
->ptid());
221 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
227 iov
.iov_base
= ®s
;
228 iov
.iov_len
= sizeof (regs
);
230 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
231 (PTRACE_TYPE_ARG3
) &iov
) == -1)
232 perror_with_name (_("Couldn't get registers"));
234 supply_gregset_regnum (regcache
, ®s
, regnum
);
237 if ((regnum
>= RISCV_FIRST_FP_REGNUM
238 && regnum
<= RISCV_LAST_FP_REGNUM
)
239 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
245 iov
.iov_base
= ®s
;
246 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
247 RISCV_FIRST_FP_REGNUM
);
248 gdb_assert (iov
.iov_len
<= sizeof (regs
));
250 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
251 (PTRACE_TYPE_ARG3
) &iov
) == -1)
252 perror_with_name (_("Couldn't get registers"));
254 supply_fpregset_regnum (regcache
, ®s
, regnum
);
257 if ((regnum
== RISCV_CSR_MISA_REGNUM
)
260 /* TODO: Need to add a ptrace call for this. */
261 regcache
->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM
);
264 /* Access to other CSRs has potential security issues, don't support them for
268 /* Store REGNUM (or all registers if REGNUM == -1) to the target
269 from REGCACHE using PTRACE_SETREGSET. */
272 riscv_linux_nat_target::store_registers (struct regcache
*regcache
, int regnum
)
276 tid
= get_ptrace_pid (regcache
->ptid ());
278 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
284 iov
.iov_base
= ®s
;
285 iov
.iov_len
= sizeof (regs
);
287 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
288 (PTRACE_TYPE_ARG3
) &iov
) == -1)
289 perror_with_name (_("Couldn't get registers"));
292 fill_gregset (regcache
, ®s
, regnum
);
294 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
,
295 (PTRACE_TYPE_ARG3
) &iov
) == -1)
296 perror_with_name (_("Couldn't set registers"));
300 if ((regnum
>= RISCV_FIRST_FP_REGNUM
301 && regnum
<= RISCV_LAST_FP_REGNUM
)
302 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
308 iov
.iov_base
= ®s
;
309 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
310 RISCV_FIRST_FP_REGNUM
);
311 gdb_assert (iov
.iov_len
<= sizeof (regs
));
313 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
314 (PTRACE_TYPE_ARG3
) &iov
) == -1)
315 perror_with_name (_("Couldn't get registers"));
318 fill_fpregset (regcache
, ®s
, regnum
);
320 if (ptrace (PTRACE_SETREGSET
, tid
, NT_FPREGSET
,
321 (PTRACE_TYPE_ARG3
) &iov
) == -1)
322 perror_with_name (_("Couldn't set registers"));
326 /* Access to CSRs has potential security issues, don't support them for
330 /* Initialize RISC-V Linux native support. */
332 void _initialize_riscv_linux_nat ();
334 _initialize_riscv_linux_nat ()
336 /* Register the target. */
337 linux_target
= &the_riscv_linux_nat_target
;
338 add_inf_child_target (&the_riscv_linux_nat_target
);