1 /* GNU/Linux/RISC-V native target description support for GDB.
2    Copyright (C) 2020-2021 Free Software Foundation, Inc.
3 
4    This file is part of GDB.
5 
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.
10 
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.
15 
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/>.  */
18 
19 #include "gdbsupport/common-defs.h"
20 
21 #include "gdb_proc_service.h"
22 #include "arch/riscv.h"
23 #include "elf/common.h"
24 #include "nat/gdb_ptrace.h"
25 #include "nat/riscv-linux-tdesc.h"
26 
27 #include <sys/uio.h>
28 
29 /* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
30 #ifndef NFPREG
31 # define NFPREG 33
32 #endif
33 
34 /* See nat/riscv-linux-tdesc.h.  */
35 
36 struct riscv_gdbarch_features
riscv_linux_read_features(int tid)37 riscv_linux_read_features (int tid)
38 {
39   struct riscv_gdbarch_features features;
40   elf_fpregset_t regs;
41   int flen;
42 
43   /* Figuring out xlen is easy.  */
44   features.xlen = sizeof (elf_greg_t);
45 
46   /* Start with no f-registers.  */
47   features.flen = 0;
48 
49   /* How much worth of f-registers can we fetch if any?  */
50   for (flen = sizeof (regs.__f.__f[0]); ; flen *= 2)
51     {
52       size_t regset_size;
53       struct iovec iov;
54 
55       /* Regsets have a uniform slot size, so we count FSCR like
56 	 an FP data register.  */
57       regset_size = ELF_NFPREG * flen;
58       if (regset_size > sizeof (regs))
59 	break;
60 
61       iov.iov_base = &regs;
62       iov.iov_len = regset_size;
63       if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
64 		  (PTRACE_TYPE_ARG3) &iov) == -1)
65 	{
66 	  switch (errno)
67 	    {
68 	    case EINVAL:
69 	      continue;
70 	    case EIO:
71 	      break;
72 	    default:
73 	      perror_with_name (_("Couldn't get registers"));
74 	      break;
75 	    }
76 	}
77       else
78 	features.flen = flen;
79       break;
80     }
81 
82   return features;
83 }
84