1 /* Native-dependent code for GNU/Linux RISC-V.
2 Copyright (C) 2018 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"
24 #include "riscv-tdep.h"
26 #include <sys/ptrace.h>
28 /* RISC-V Linux native additions to the default linux support. */
30 class riscv_linux_nat_target final
: public linux_nat_target
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
;
38 static riscv_linux_nat_target the_riscv_linux_nat_target
;
40 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
41 from regset GREGS into REGCACHE. */
44 supply_gregset_regnum (struct regcache
*regcache
, const prgregset_t
*gregs
,
48 const elf_greg_t
*regp
= *gregs
;
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
);
56 /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */
57 regcache
->raw_supply (32, regp
+ 0);
59 /* Fill the inaccessible zero register with zero. */
60 regcache
->raw_supply_zeroed (0);
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);
70 /* Copy all general purpose registers from regset GREGS into REGCACHE. */
73 supply_gregset (struct regcache
*regcache
, const prgregset_t
*gregs
)
75 supply_gregset_regnum (regcache
, gregs
, -1);
78 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
79 from regset FPREGS into REGCACHE. */
82 supply_fpregset_regnum (struct regcache
*regcache
, const prfpregset_t
*fpregs
,
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
]);
93 regcache
->raw_supply (RISCV_CSR_FCSR_REGNUM
, &fpregs
->__d
.__fcsr
);
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
);
102 /* Copy all floating point registers from regset FPREGS into REGCACHE. */
105 supply_fpregset (struct regcache
*regcache
, const prfpregset_t
*fpregs
)
107 supply_fpregset_regnum (regcache
, fpregs
, -1);
110 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1)
111 from REGCACHE into regset GREGS. */
114 fill_gregset (const struct regcache
*regcache
, prgregset_t
*gregs
, int regnum
)
116 elf_greg_t
*regp
= *gregs
;
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
);
124 regcache
->raw_collect (32, regp
+ 0);
126 else if (regnum
== RISCV_ZERO_REGNUM
)
127 /* Nothing to do here. */
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);
135 /* Copy floating point register REGNUM (or all fp regs if REGNUM == -1)
136 from REGCACHE into regset FPREGS. */
139 fill_fpregset (const struct regcache
*regcache
, prfpregset_t
*fpregs
,
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
]);
148 regcache
->raw_collect (RISCV_CSR_FCSR_REGNUM
, &fpregs
->__d
.__fcsr
);
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
);
157 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
158 into REGCACHE using PTRACE_GETREGSET. */
161 riscv_linux_nat_target::fetch_registers (struct regcache
*regcache
, int regnum
)
165 tid
= get_ptrace_pid (regcache
->ptid());
167 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
173 iov
.iov_base
= ®s
;
174 iov
.iov_len
= sizeof (regs
);
176 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
177 (PTRACE_TYPE_ARG3
) &iov
) == -1)
178 perror_with_name (_("Couldn't get registers"));
180 supply_gregset_regnum (regcache
, ®s
, regnum
);
183 if ((regnum
>= RISCV_FIRST_FP_REGNUM
184 && regnum
<= RISCV_LAST_FP_REGNUM
)
185 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
191 iov
.iov_base
= ®s
;
192 iov
.iov_len
= sizeof (regs
);
194 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRFPREG
,
195 (PTRACE_TYPE_ARG3
) &iov
) == -1)
196 perror_with_name (_("Couldn't get registers"));
198 supply_fpregset_regnum (regcache
, ®s
, regnum
);
201 if ((regnum
== RISCV_CSR_MISA_REGNUM
)
204 /* TODO: Need to add a ptrace call for this. */
205 regcache
->raw_supply_zeroed (regnum
);
208 /* Access to other CSRs has potential security issues, don't support them for
212 /* Store REGNUM (or all registers if REGNUM == -1) to the target
213 from REGCACHE using PTRACE_SETREGSET. */
216 riscv_linux_nat_target::store_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"));
236 fill_gregset (regcache
, ®s
, regnum
);
238 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
,
239 (PTRACE_TYPE_ARG3
) &iov
) == -1)
240 perror_with_name (_("Couldn't set registers"));
244 if ((regnum
>= RISCV_FIRST_FP_REGNUM
245 && regnum
<= RISCV_LAST_FP_REGNUM
)
246 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
252 iov
.iov_base
= ®s
;
253 iov
.iov_len
= sizeof (regs
);
255 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRFPREG
,
256 (PTRACE_TYPE_ARG3
) &iov
) == -1)
257 perror_with_name (_("Couldn't get registers"));
260 fill_fpregset (regcache
, ®s
, regnum
);
262 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRFPREG
,
263 (PTRACE_TYPE_ARG3
) &iov
) == -1)
264 perror_with_name (_("Couldn't set registers"));
268 /* Access to CSRs has potential security issues, don't support them for
272 /* Initialize RISC-V Linux native support. */
275 _initialize_riscv_linux_nat (void)
277 /* Register the target. */
278 linux_target
= &the_riscv_linux_nat_target
;
279 add_inf_child_target (&the_riscv_linux_nat_target
);