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"
25 #include "target-descriptions.h"
27 #include "elf/common.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 (32, regp
+ 0);
70 /* Fill the inaccessible zero register with zero. */
71 regcache
->raw_supply_zeroed (0);
73 else if (regnum
== RISCV_ZERO_REGNUM
)
74 regcache
->raw_supply_zeroed (0);
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 (32, 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 (32, 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 (32, 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 struct riscv_gdbarch_features features
;
208 /* Figuring out xlen is easy. */
209 features
.xlen
= sizeof (elf_greg_t
);
211 tid
= inferior_ptid
.lwp ();
213 /* Start with no f-registers. */
216 /* How much worth of f-registers can we fetch if any? */
217 for (flen
= sizeof (regs
.__f
.__f
[0]); ; flen
*= 2)
222 /* Regsets have a uniform slot size, so we count FSCR like
223 an FP data register. */
224 regset_size
= ELF_NFPREG
* flen
;
225 if (regset_size
> sizeof (regs
))
228 iov
.iov_base
= ®s
;
229 iov
.iov_len
= regset_size
;
230 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
231 (PTRACE_TYPE_ARG3
) &iov
) == -1)
240 perror_with_name (_("Couldn't get registers"));
245 features
.flen
= flen
;
249 return riscv_create_target_description (features
);
252 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target
253 into REGCACHE using PTRACE_GETREGSET. */
256 riscv_linux_nat_target::fetch_registers (struct regcache
*regcache
, int regnum
)
260 tid
= get_ptrace_pid (regcache
->ptid());
262 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
268 iov
.iov_base
= ®s
;
269 iov
.iov_len
= sizeof (regs
);
271 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
272 (PTRACE_TYPE_ARG3
) &iov
) == -1)
273 perror_with_name (_("Couldn't get registers"));
275 supply_gregset_regnum (regcache
, ®s
, regnum
);
278 if ((regnum
>= RISCV_FIRST_FP_REGNUM
279 && regnum
<= RISCV_LAST_FP_REGNUM
)
280 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
286 iov
.iov_base
= ®s
;
287 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
288 RISCV_FIRST_FP_REGNUM
);
289 gdb_assert (iov
.iov_len
<= sizeof (regs
));
291 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
292 (PTRACE_TYPE_ARG3
) &iov
) == -1)
293 perror_with_name (_("Couldn't get registers"));
295 supply_fpregset_regnum (regcache
, ®s
, regnum
);
298 if ((regnum
== RISCV_CSR_MISA_REGNUM
)
301 /* TODO: Need to add a ptrace call for this. */
302 regcache
->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM
);
305 /* Access to other CSRs has potential security issues, don't support them for
309 /* Store REGNUM (or all registers if REGNUM == -1) to the target
310 from REGCACHE using PTRACE_SETREGSET. */
313 riscv_linux_nat_target::store_registers (struct regcache
*regcache
, int regnum
)
317 tid
= get_ptrace_pid (regcache
->ptid ());
319 if ((regnum
>= RISCV_ZERO_REGNUM
&& regnum
<= RISCV_PC_REGNUM
)
325 iov
.iov_base
= ®s
;
326 iov
.iov_len
= sizeof (regs
);
328 if (ptrace (PTRACE_GETREGSET
, tid
, NT_PRSTATUS
,
329 (PTRACE_TYPE_ARG3
) &iov
) == -1)
330 perror_with_name (_("Couldn't get registers"));
333 fill_gregset (regcache
, ®s
, regnum
);
335 if (ptrace (PTRACE_SETREGSET
, tid
, NT_PRSTATUS
,
336 (PTRACE_TYPE_ARG3
) &iov
) == -1)
337 perror_with_name (_("Couldn't set registers"));
341 if ((regnum
>= RISCV_FIRST_FP_REGNUM
342 && regnum
<= RISCV_LAST_FP_REGNUM
)
343 || (regnum
== RISCV_CSR_FCSR_REGNUM
)
349 iov
.iov_base
= ®s
;
350 iov
.iov_len
= ELF_NFPREG
* register_size (regcache
->arch (),
351 RISCV_FIRST_FP_REGNUM
);
352 gdb_assert (iov
.iov_len
<= sizeof (regs
));
354 if (ptrace (PTRACE_GETREGSET
, tid
, NT_FPREGSET
,
355 (PTRACE_TYPE_ARG3
) &iov
) == -1)
356 perror_with_name (_("Couldn't get registers"));
359 fill_fpregset (regcache
, ®s
, regnum
);
361 if (ptrace (PTRACE_SETREGSET
, tid
, NT_FPREGSET
,
362 (PTRACE_TYPE_ARG3
) &iov
) == -1)
363 perror_with_name (_("Couldn't set registers"));
367 /* Access to CSRs has potential security issues, don't support them for
371 /* Initialize RISC-V Linux native support. */
373 void _initialize_riscv_linux_nat ();
375 _initialize_riscv_linux_nat ()
377 /* Register the target. */
378 linux_target
= &the_riscv_linux_nat_target
;
379 add_inf_child_target (&the_riscv_linux_nat_target
);