1 /* Native-dependent code for GNU/Linux RISC-V.
2 Copyright (C) 2018-2022 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 const struct riscv_gdbarch_features features
205 = riscv_linux_read_features (inferior_ptid
.pid ());
206 return riscv_lookup_target_description (features
);
209 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
210 into REGCACHE using PTRACE_GETREGSET. */
213 riscv_linux_nat_target::fetch_registers (struct regcache
*regcache
, int regnum
)
217 tid
= get_ptrace_pid (regcache
->ptid());
219 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
225 iov
.iov_base
= ®s
;
226 iov
.iov_len
= sizeof (regs
);
228 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
229 (PTRACE_TYPE_ARG3
) &iov
) == -1)
230 perror_with_name (_("Couldn't get registers"));
232 supply_gregset_regnum (regcache
, ®s
, regnum
);
235 if ((regnum
>= RISCV_FIRST_FP_REGNUM
236 && regnum
<= RISCV_LAST_FP_REGNUM
)
237 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
243 iov
.iov_base
= ®s
;
244 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
245 RISCV_FIRST_FP_REGNUM
);
246 gdb_assert (iov
.iov_len
<= sizeof (regs
));
248 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
249 (PTRACE_TYPE_ARG3
) &iov
) == -1)
250 perror_with_name (_("Couldn't get registers"));
252 supply_fpregset_regnum (regcache
, ®s
, regnum
);
255 if ((regnum
== RISCV_CSR_MISA_REGNUM
)
258 /* TODO: Need to add a ptrace call for this. */
259 regcache
->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM
);
262 /* Access to other CSRs has potential security issues, don't support them for
266 /* Store REGNUM (or all registers if REGNUM == -1) to the target
267 from REGCACHE using PTRACE_SETREGSET. */
270 riscv_linux_nat_target::store_registers (struct regcache
*regcache
, int regnum
)
274 tid
= get_ptrace_pid (regcache
->ptid ());
276 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
282 iov
.iov_base
= ®s
;
283 iov
.iov_len
= sizeof (regs
);
285 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
286 (PTRACE_TYPE_ARG3
) &iov
) == -1)
287 perror_with_name (_("Couldn't get registers"));
290 fill_gregset (regcache
, ®s
, regnum
);
292 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
,
293 (PTRACE_TYPE_ARG3
) &iov
) == -1)
294 perror_with_name (_("Couldn't set registers"));
298 if ((regnum
>= RISCV_FIRST_FP_REGNUM
299 && regnum
<= RISCV_LAST_FP_REGNUM
)
300 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
306 iov
.iov_base
= ®s
;
307 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
308 RISCV_FIRST_FP_REGNUM
);
309 gdb_assert (iov
.iov_len
<= sizeof (regs
));
311 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
312 (PTRACE_TYPE_ARG3
) &iov
) == -1)
313 perror_with_name (_("Couldn't get registers"));
316 fill_fpregset (regcache
, ®s
, regnum
);
318 if (ptrace (PTRACE_SETREGSET
, tid
, NT_FPREGSET
,
319 (PTRACE_TYPE_ARG3
) &iov
) == -1)
320 perror_with_name (_("Couldn't set registers"));
324 /* Access to CSRs has potential security issues, don't support them for
328 /* Initialize RISC-V Linux native support. */
330 void _initialize_riscv_linux_nat ();
332 _initialize_riscv_linux_nat ()
334 /* Register the target. */
335 linux_target
= &the_riscv_linux_nat_target
;
336 add_inf_child_target (&the_riscv_linux_nat_target
);