[1/4] RISC-V/Linux/native: Determine FLEN dynamically

Message ID alpine.LFD.2.21.2001231425120.14118@redsun52.ssa.fujisawa.hgst.com
State Superseded
Headers

Commit Message

Maciej W. Rozycki Jan. 23, 2020, 7:40 p.m. UTC
  Fix RISC-V native Linux support to handle a 64-bit FPU (FLEN == 64) with 
both RV32 and RV64 systems, which is a part of the current Linux ABI for 
hard-float systems, rather than assuming that (FLEN == XLEN).

We can do better however and not rely on any particular value of FLEN 
and probe for it dynamically, by observing that the PTRACE_GETREGSET 
ptrace(2) call will only accept an exact regset size, and that will 
reflect FLEN.  Therefore iterate over the call with a geometrically 
increasing regset size until a match is marked by a successful ptrace(2) 
call completion or we run beyond the maximum size we can support.

Also handle a glibc bug where ELF_NFPREG is defined in terms of NFPREG, 
however NFPREG is nowhere defined.

	gdb/
	* riscv-linux-nat.c [!NFPREG] (NFPREG): New macro.
	(riscv_linux_nat_target::read_description): Determine FLEN 
	dynamically.
---
Hi,

 Smoke-testing indicates no immediate problems with this change; full 
regression-testing is still running and will take approximately 3 days.

  Maciej
---
 gdb/riscv-linux-nat.c |   49 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 12 deletions(-)

gdb-riscv-linux-nat-flen.diff
  

Comments

Jim Wilson Jan. 24, 2020, 1:03 a.m. UTC | #1
On Thu, Jan 23, 2020 at 11:40 AM Maciej W. Rozycki <macro@wdc.com> wrote:
>         gdb/
>         * riscv-linux-nat.c [!NFPREG] (NFPREG): New macro.
>         (riscv_linux_nat_target::read_description): Determine FLEN
>         dynamically.

This looks good to me, though I'm not a formal riscv linux gdb maintainer.

Jim
  

Patch

Index: binutils-gdb/gdb/riscv-linux-nat.c
===================================================================
--- binutils-gdb.orig/gdb/riscv-linux-nat.c
+++ binutils-gdb/gdb/riscv-linux-nat.c
@@ -28,6 +28,11 @@ 
 
 #include <sys/ptrace.h>
 
+/* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
+#ifndef NFPREG
+# define NFPREG 33
+#endif
+
 /* RISC-V Linux native additions to the default linux support.  */
 
 class riscv_linux_nat_target final : public linux_nat_target
@@ -166,8 +171,8 @@  const struct target_desc *
 riscv_linux_nat_target::read_description ()
 {
   struct riscv_gdbarch_features features;
-  struct iovec iov;
   elf_fpregset_t regs;
+  int flen;
   int tid;
 
   /* Figuring out xlen is easy.  */
@@ -175,19 +180,39 @@  riscv_linux_nat_target::read_description
 
   tid = inferior_ptid.lwp ();
 
-  iov.iov_base = &regs;
-  iov.iov_len = sizeof (regs);
+  /* Start with no f-registers.  */
+  features.flen = 0;
 
-  /* Can we fetch the f-registers?  */
-  if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
-	      (PTRACE_TYPE_ARG3) &iov) == -1)
-    features.flen = 0;		/* No f-registers.  */
-  else
+  /* How much worth of f-registers can we fetch if any?  */
+  for (flen = sizeof (regs.__f.__f[0]); ; flen *= 2)
     {
-      /* TODO: We need a way to figure out the actual length of the
-	 f-registers.  We could have 64-bit x-registers, with 32-bit
-	 f-registers.  For now, just assumed xlen and flen match.  */
-      features.flen = features.xlen;
+      size_t regset_size;
+      struct iovec iov;
+
+      /* Regsets have a uniform slot size, so we count FSCR like an FGR.  */
+      regset_size = ELF_NFPREG * flen;
+      if (regset_size > sizeof (regs))
+	break;
+
+      iov.iov_base = &regs;
+      iov.iov_len = regset_size;
+      if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
+		  (PTRACE_TYPE_ARG3) &iov) == -1)
+	{
+	  switch (errno)
+	    {
+	    case EINVAL:
+	      continue;
+	    case EIO:
+	      break;
+	    default:
+	      perror_with_name (_("Couldn't get registers"));
+	      break;
+	    }
+	}
+      else
+	features.flen = flen;
+      break;
     }
 
   return riscv_create_target_description (features);