public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 1/3] RISC-V/Linux/native: Determine FLEN dynamically
  2020-02-01  0:06 [PATCH v4 0/3] RISC-V/Linux `gdbserver' support and associated fixes Maciej W. Rozycki
@ 2020-02-01  0:06 ` Maciej W. Rozycki
  2020-02-01  0:07 ` [PATCH v4 3/3] gdbserver: Add RISC-V/Linux support Maciej W. Rozycki
  2020-02-01  0:07 ` [PATCH v4 2/3] RISC-V/Linux/native: Factor out target description determination Maciej W. Rozycki
  2 siblings, 0 replies; 4+ messages in thread
From: Maciej W. Rozycki @ 2020-02-01  0:06 UTC (permalink / raw)
  To: gdb-patches
  Cc: Jim Wilson, Andrew Burgess, Palmer Dabbelt, Tom Tromey, guoren,
	lifang_xia, yunhai_shang, jiangshuai_li

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) in target 
description determination and that (FLEN == 64) in register access.

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 in target description 
determination 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.

Update register accessors accordingly, using FLEN determined to size the 
buffer used for NT_PRSTATUS requests and then to exchange data with the 
regcache.

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.
	(supply_fpregset_regnum, fill_fpregset): Handle regset buffer 
	offsets according to FLEN determined.
	(riscv_linux_nat_target::read_description): Determine FLEN 
	dynamically.
	(riscv_linux_nat_target::fetch_registers): Size regset buffer 
	according to FLEN determined.
	(riscv_linux_nat_target::store_registers): Likewise.
---
No changes from v3.

Changes from v2:

- Avoid an ambiguous FGR reference in 
  `riscv_linux_nat_target::read_description'.

- Advance through the buffer accessed in `supply_fpregset_regnum' and 
  `fill_fpregset' so as to avoid doing a variable multiplication in a 
  loop; also precalculate the buffer offset for single register accesses 
  to avoid excessive line wrapping and improve code readability.

- Move the `i' variable declaration to the beginning of `fill_fpregset', 
  for consistency with `supply_fpregset_regnum' (since the loop is being 
  rewritten anyway).

Changes from v1:

- Also set the size of the regset buffer dynamically in 
  `riscv_linux_nat_target::fetch_registers' and 
  `riscv_linux_nat_target::store_registers', and update `fill_fpregset' 
  and `supply_fpregset_regnum' accordingly.
---
 gdb/riscv-linux-nat.c |  110 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 84 insertions(+), 26 deletions(-)

gdb-riscv-linux-nat-flen.diff
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
@@ -88,21 +93,35 @@ static void
 supply_fpregset_regnum (struct regcache *regcache, const prfpregset_t *fpregs,
 			int regnum)
 {
+  int flen = register_size (regcache->arch (), RISCV_FIRST_FP_REGNUM);
+  union
+    {
+      const prfpregset_t *fpregs;
+      const gdb_byte *buf;
+    }
+  fpbuf = { .fpregs = fpregs };
   int i;
 
   if (regnum == -1)
     {
       /* We only support the FP registers and FCSR here.  */
-      for (i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++)
-	regcache->raw_supply (i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]);
+      for (i = RISCV_FIRST_FP_REGNUM;
+	   i <= RISCV_LAST_FP_REGNUM;
+	   i++, fpbuf.buf += flen)
+	regcache->raw_supply (i, fpbuf.buf);
 
-      regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
+      regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, fpbuf.buf);
     }
   else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
-    regcache->raw_supply (regnum,
-			  &fpregs->__d.__f[regnum - RISCV_FIRST_FP_REGNUM]);
+    {
+      fpbuf.buf += flen * (regnum - RISCV_FIRST_FP_REGNUM);
+      regcache->raw_supply (regnum, fpbuf.buf);
+    }
   else if (regnum == RISCV_CSR_FCSR_REGNUM)
-    regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
+    {
+      fpbuf.buf += flen * (RISCV_LAST_FP_REGNUM - RISCV_FIRST_FP_REGNUM + 1);
+      regcache->raw_supply (RISCV_CSR_FCSR_REGNUM, fpbuf.buf);
+    }
 }
 
 /* Copy all floating point registers from regset FPREGS into REGCACHE.  */
@@ -145,19 +164,35 @@ void
 fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs,
 	       int regnum)
 {
+  int flen = register_size (regcache->arch (), RISCV_FIRST_FP_REGNUM);
+  union
+    {
+      prfpregset_t *fpregs;
+      gdb_byte *buf;
+    }
+  fpbuf = { .fpregs = fpregs };
+  int i;
+
   if (regnum == -1)
     {
       /* We only support the FP registers and FCSR here.  */
-      for (int i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++)
-	regcache->raw_collect (i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]);
+      for (i = RISCV_FIRST_FP_REGNUM;
+	   i <= RISCV_LAST_FP_REGNUM;
+	   i++, fpbuf.buf += flen)
+	regcache->raw_collect (i, fpbuf.buf);
 
-      regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
+      regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, fpbuf.buf);
     }
   else if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
-    regcache->raw_collect (regnum,
-			   &fpregs->__d.__f[regnum - RISCV_FIRST_FP_REGNUM]);
+    {
+      fpbuf.buf += flen * (regnum - RISCV_FIRST_FP_REGNUM);
+      regcache->raw_collect (regnum, fpbuf.buf);
+    }
   else if (regnum == RISCV_CSR_FCSR_REGNUM)
-    regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr);
+    {
+      fpbuf.buf += flen * (RISCV_LAST_FP_REGNUM - RISCV_FIRST_FP_REGNUM + 1);
+      regcache->raw_collect (RISCV_CSR_FCSR_REGNUM, fpbuf.buf);
+    }
 }
 
 /* Return a target description for the current target.  */
@@ -166,8 +201,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 +210,40 @@ 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 FP data register.  */
+      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);
@@ -228,7 +284,8 @@ riscv_linux_nat_target::fetch_registers
       elf_fpregset_t regs;
 
       iov.iov_base = &regs;
-      iov.iov_len = sizeof (regs);
+      iov.iov_len = ELF_NFPREG * register_size (regcache->arch (),
+						RISCV_FIRST_FP_REGNUM);
 
       if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
 		  (PTRACE_TYPE_ARG3) &iov) == -1)
@@ -289,7 +346,8 @@ riscv_linux_nat_target::store_registers
       elf_fpregset_t regs;
 
       iov.iov_base = &regs;
-      iov.iov_len = sizeof (regs);
+      iov.iov_len = ELF_NFPREG * register_size (regcache->arch (),
+						RISCV_FIRST_FP_REGNUM);
 
       if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET,
 		  (PTRACE_TYPE_ARG3) &iov) == -1)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v4 0/3] RISC-V/Linux `gdbserver' support and associated fixes
@ 2020-02-01  0:06 Maciej W. Rozycki
  2020-02-01  0:06 ` [PATCH v4 1/3] RISC-V/Linux/native: Determine FLEN dynamically Maciej W. Rozycki
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Maciej W. Rozycki @ 2020-02-01  0:06 UTC (permalink / raw)
  To: gdb-patches
  Cc: Jim Wilson, Andrew Burgess, Palmer Dabbelt, Tom Tromey, guoren,
	lifang_xia, yunhai_shang, jiangshuai_li

Hi,

 Reposting v3 as v4 due to the wrong version of 3/3.  Maybe the threading 
will come right too (fingers crossed).

 Beyond the issues discussed with v2 I have now also slightly optimised 
regcache supply/collect handlers to avoid doing a costly variable 
multiplication in a loop, and added buffer offset precalculations so as to 
avoid excessive line wrapping and hopefully making code more readable.

 Also I have noticed missing Python and ncurses development libraries 
limiting testing in my native setup.  With these installed native test 
results improved a little, as follows:

		=== gdb Summary ===

# of expected passes		61354
# of unexpected failures	1636
# of unexpected successes	1
# of expected failures		58
# of unknown successes		3
# of known failures		85
# of unresolved testcases	113
# of untested testcases		160
# of unsupported tests		323

however a worrying regression has appeared:

FAIL: gdb.base/return-nodebug.exp: float: full width of the returned result

This has turned out not to be related to this patch series however and 
triggers reliably now in my setup regardless of whether this patch set has 
been applied or not.  Instead it is an outcome of GDB failing to NaN-box 
data of the `float' type when assigning it to a hardware register.

 I have filed PR tdep/25489 to track it as I may not be able to look into 
it right away.

 Except as noted above here have been no regressions in native 
`riscv64-linux-gnu' testing and remote `gdbserver' test results are the 
same as previously (barring the usual gdb.threads/ fluctuations).

 As usually see individual changes for details.

  Maciej

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v4 3/3] gdbserver: Add RISC-V/Linux support
  2020-02-01  0:06 [PATCH v4 0/3] RISC-V/Linux `gdbserver' support and associated fixes Maciej W. Rozycki
  2020-02-01  0:06 ` [PATCH v4 1/3] RISC-V/Linux/native: Determine FLEN dynamically Maciej W. Rozycki
@ 2020-02-01  0:07 ` Maciej W. Rozycki
  2020-02-01  0:07 ` [PATCH v4 2/3] RISC-V/Linux/native: Factor out target description determination Maciej W. Rozycki
  2 siblings, 0 replies; 4+ messages in thread
From: Maciej W. Rozycki @ 2020-02-01  0:07 UTC (permalink / raw)
  To: gdb-patches
  Cc: Jim Wilson, Andrew Burgess, Palmer Dabbelt, Tom Tromey, guoren,
	lifang_xia, yunhai_shang, jiangshuai_li

Implement RISC-V/Linux support for both RV64 and RV32 systems, including 
XML target description handling based on features determined, GPR and 
FPR regset support including dynamic sizing of the latter, and software 
breakpoint handling.  Define two NT_FPREGSET regsets of a different size 
matching the FPR sizes supported for generic `gdbserver' code to pick 
from according to what the OS supplies.

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

	gdb/
	* arch/riscv.h (riscv_create_target_description): Remove `const' 
	qualifier from the return type.
	* arch/riscv.c (riscv_create_target_description): Likewise.
	* nat/riscv-linux-tdesc.h (riscv_linux_read_description): 
	Likewise.
	* nat/riscv-linux-tdesc.c (riscv_linux_read_description): 
	Likewise.
	* configure.tgt <riscv*-*-linux*>: Set build_gdbserver=yes.

	gdb/gdbserver/
	* linux-riscv-low.c: New file.
	* Makefile.in (SFILES): Add linux-riscv-low.c, arch/riscv.c, and 
	nat/riscv-linux-tdesc.c.
	* configure.srv <riscv*-*-linux*> (srv_tgtobj)
	(srv_linux_regsets, srv_linux_usrregs, srv_linux_thread_db): 
	Define.
---
Changes from v3:

- Actually include changes from v2.

Changes from v2:

- Advance through the buffer accessed in `riscv_fill_fpregset' and 
  `riscv_store_fpregset' so as to avoid doing a variable multiplication in 
  a loop; rename the `regset' variable to `regbuf'.

- Use OPTIONAL_REGS rather than FP_REGS as the type for the floating-point 
  regsets.

- Add comments throughout.

Changes from v1:

- Make `gdbserver' selected for automatic build in a RISC-V/Linux/native
  GDB configuration (thanks, Jim, for pointing this out!).

- Remove most of `riscv_arch_setup' and use `riscv_linux_read_description' 
  from 2/3 instead.

- Stop using `elf_fpregset_t*' in favour to just a raw `gdb_byte *' buffer 
  and size the regset according to the FPR size in `riscv_fill_fpregset' 
  and `riscv_store_fpregset'.

- Define 2 NT_FPREGSET regsets of a different size for generic `gdbserver' 
  code to pick from according to what the OS supplies.
---
 gdb/arch/riscv.c                |    2 
 gdb/arch/riscv.h                |    4 
 gdb/configure.tgt               |    1 
 gdb/gdbserver/Makefile.in       |    3 
 gdb/gdbserver/configure.srv     |    7 +
 gdb/gdbserver/linux-riscv-low.c |  274 ++++++++++++++++++++++++++++++++++++++++
 gdb/nat/riscv-linux-tdesc.c     |    2 
 gdb/nat/riscv-linux-tdesc.h     |    2 
 8 files changed, 290 insertions(+), 5 deletions(-)

gdb-riscv-gdbserver-linux.diff
Index: binutils-gdb/gdb/arch/riscv.c
===================================================================
--- binutils-gdb.orig/gdb/arch/riscv.c
+++ binutils-gdb/gdb/arch/riscv.c
@@ -43,7 +43,7 @@ static std::unordered_map<riscv_gdbarch_
 
 /* See arch/riscv.h.  */
 
-const target_desc *
+target_desc *
 riscv_create_target_description (struct riscv_gdbarch_features features)
 {
   /* Have we seen this feature set before?  If we have return the same
Index: binutils-gdb/gdb/arch/riscv.h
===================================================================
--- binutils-gdb.orig/gdb/arch/riscv.h
+++ binutils-gdb/gdb/arch/riscv.h
@@ -69,7 +69,7 @@ struct riscv_gdbarch_features
 /* Create and return a target description that is compatible with
    FEATURES.  */
 
-const target_desc *riscv_create_target_description
-	(struct riscv_gdbarch_features features);
+target_desc *riscv_create_target_description
+  (struct riscv_gdbarch_features features);
 
 #endif /* ARCH_RISCV_H */
Index: binutils-gdb/gdb/configure.tgt
===================================================================
--- binutils-gdb.orig/gdb/configure.tgt
+++ binutils-gdb/gdb/configure.tgt
@@ -553,6 +553,7 @@ riscv*-*-linux*)
 	# Target: Linux/RISC-V
 	gdb_target_obs="riscv-linux-tdep.o glibc-tdep.o \
  			linux-tdep.o solib-svr4.o symfile-mem.o linux-record.o"
+	build_gdbserver=yes
 	;;
 
 riscv*-*-*)
Index: binutils-gdb/gdb/gdbserver/Makefile.in
===================================================================
--- binutils-gdb.orig/gdb/gdbserver/Makefile.in
+++ binutils-gdb/gdb/gdbserver/Makefile.in
@@ -177,6 +177,7 @@ SFILES = \
 	$(srcdir)/linux-mips-low.c \
 	$(srcdir)/linux-nios2-low.c \
 	$(srcdir)/linux-ppc-low.c \
+	$(srcdir)/linux-riscv-low.c \
 	$(srcdir)/linux-s390-low.c \
 	$(srcdir)/linux-sh-low.c \
 	$(srcdir)/linux-sparc-low.c \
@@ -203,6 +204,7 @@ SFILES = \
 	$(srcdir)/../arch/arm-get-next-pcs.c \
 	$(srcdir)/../arch/arm-linux.c \
 	$(srcdir)/../arch/ppc-linux-common.c \
+	$(srcdir)/../arch/riscv.c \
 	$(srcdir)/../../gdbsupport/btrace-common.c \
 	$(srcdir)/../../gdbsupport/buffer.c \
 	$(srcdir)/../../gdbsupport/cleanups.c \
@@ -236,6 +238,7 @@ SFILES = \
 	$(srcdir)/../nat/linux-personality.c \
 	$(srcdir)/../nat/mips-linux-watch.c \
 	$(srcdir)/../nat/ppc-linux.c \
+	$(srcdir)/../nat/riscv-linux-tdesc.c \
 	$(srcdir)/../nat/fork-inferior.c \
 	$(srcdir)/../target/waitstatus.c
 
Index: binutils-gdb/gdb/gdbserver/configure.srv
===================================================================
--- binutils-gdb.orig/gdb/gdbserver/configure.srv
+++ binutils-gdb/gdb/gdbserver/configure.srv
@@ -267,6 +267,13 @@ case "${target}" in
 			srv_xmlfiles="${srv_xmlfiles} rs6000/power-fpu.xml"
 			srv_lynxos=yes
 			;;
+  riscv*-*-linux*)	srv_tgtobj="arch/riscv.o nat/riscv-linux-tdesc.o"
+			srv_tgtobj="${srv_tgtobj} linux-riscv-low.o"
+			srv_tgtobj="${srv_tgtobj} ${srv_linux_obj}"
+			srv_linux_regsets=yes
+			srv_linux_usrregs=yes
+			srv_linux_thread_db=yes
+			;;
   s390*-*-linux*)	srv_regobj="s390-linux32.o"
 			srv_regobj="${srv_regobj} s390-linux32v1.o"
 			srv_regobj="${srv_regobj} s390-linux32v2.o"
Index: binutils-gdb/gdb/gdbserver/linux-riscv-low.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/gdbserver/linux-riscv-low.c
@@ -0,0 +1,274 @@
+/* GNU/Linux/RISC-V specific low level interface, for the remote server
+   for GDB.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+
+#include "linux-low.h"
+#include "tdesc.h"
+#include "elf/common.h"
+#include "nat/riscv-linux-tdesc.h"
+#include "opcode/riscv.h"
+
+/* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
+#ifndef NFPREG
+# define NFPREG 33
+#endif
+
+/* Implementation of linux_target_ops method "arch_setup".  */
+
+static void
+riscv_arch_setup ()
+{
+  static const char *expedite_regs[] = { "sp", "pc", NULL };
+  target_desc *tdesc;
+
+  tdesc = riscv_linux_read_description (lwpid_of (current_thread));
+  if (!tdesc->expedite_regs)
+    init_target_desc (tdesc, expedite_regs);
+  current_process ()->tdesc = tdesc;
+}
+
+/* Collect GPRs from REGCACHE into BUF.  */
+
+static void
+riscv_fill_gregset (struct regcache *regcache, void *buf)
+{
+  const struct target_desc *tdesc = regcache->tdesc;
+  elf_gregset_t *regset = (elf_gregset_t *) buf;
+  int regno = find_regno (tdesc, "zero");
+  int i;
+
+  collect_register_by_name (regcache, "pc", *regset);
+  for (i = 1; i < ARRAY_SIZE (*regset); i++)
+    collect_register (regcache, regno + i, *regset + i);
+}
+
+/* Supply GPRs from BUF into REGCACHE.  */
+
+static void
+riscv_store_gregset (struct regcache *regcache, const void *buf)
+{
+  const elf_gregset_t *regset = (const elf_gregset_t *) buf;
+  const struct target_desc *tdesc = regcache->tdesc;
+  int regno = find_regno (tdesc, "zero");
+  int i;
+
+  supply_register_by_name (regcache, "pc", *regset);
+  supply_register_zeroed (regcache, regno);
+  for (i = 1; i < ARRAY_SIZE (*regset); i++)
+    supply_register (regcache, regno + i, *regset + i);
+}
+
+/* Collect FPRs from REGCACHE into BUF.  */
+
+static void
+riscv_fill_fpregset (struct regcache *regcache, void *buf)
+{
+  const struct target_desc *tdesc = regcache->tdesc;
+  int regno = find_regno (tdesc, "ft0");
+  int flen = register_size (regcache->tdesc, regno);
+  gdb_byte *regbuf = (gdb_byte *) buf;
+  int i;
+
+  for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen)
+    collect_register (regcache, regno + i, regbuf);
+  collect_register_by_name (regcache, "fcsr", regbuf);
+}
+
+/* Supply FPRs from BUF into REGCACHE.  */
+
+static void
+riscv_store_fpregset (struct regcache *regcache, const void *buf)
+{
+  const struct target_desc *tdesc = regcache->tdesc;
+  int regno = find_regno (tdesc, "ft0");
+  int flen = register_size (regcache->tdesc, regno);
+  const gdb_byte *regbuf = (const gdb_byte *) buf;
+  int i;
+
+  for (i = 0; i < ELF_NFPREG - 1; i++, regbuf += flen)
+    supply_register (regcache, regno + i, regbuf);
+  supply_register_by_name (regcache, "fcsr", regbuf);
+}
+
+/* RISC-V/Linux regsets.  FPRs are optional and come in different sizes,
+   so define multiple regsets for them marking them all as OPTIONAL_REGS
+   rather than FP_REGS, so that "regsets_fetch_inferior_registers" picks
+   the right one according to size.  */
+static struct regset_info riscv_regsets[] = {
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS,
+    sizeof (elf_gregset_t), GENERAL_REGS,
+    riscv_fill_gregset, riscv_store_gregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
+    sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS,
+    riscv_fill_fpregset, riscv_store_fpregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
+    sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS,
+    riscv_fill_fpregset, riscv_store_fpregset },
+  NULL_REGSET
+};
+
+/* RISC-V/Linux regset information.  */
+static struct regsets_info riscv_regsets_info =
+  {
+    riscv_regsets, /* regsets */
+    0, /* num_regsets */
+    NULL, /* disabled_regsets */
+  };
+
+/* Definition of linux_target_ops data member "regs_info".  */
+static struct regs_info riscv_regs =
+  {
+    NULL, /* regset_bitmap */
+    NULL, /* usrregs */
+    &riscv_regsets_info,
+  };
+
+/* Implementation of linux_target_ops method "regs_info".  */
+
+static const struct regs_info *
+riscv_regs_info ()
+{
+  return &riscv_regs;
+}
+
+/* Implementation of linux_target_ops method "fetch_register".  */
+
+static int
+riscv_fetch_register (struct regcache *regcache, int regno)
+{
+  const struct target_desc *tdesc = regcache->tdesc;
+
+  if (regno != find_regno (tdesc, "zero"))
+    return 0;
+  supply_register_zeroed (regcache, regno);
+  return 1;
+}
+
+/* Implementation of linux_target_ops method "get_pc".  */
+
+static CORE_ADDR
+riscv_get_pc (struct regcache *regcache)
+{
+  elf_gregset_t regset;
+
+  if (sizeof (regset[0]) == 8)
+    return linux_get_pc_64bit (regcache);
+  else
+    return linux_get_pc_32bit (regcache);
+}
+
+/* Implementation of linux_target_ops method "set_pc".  */
+
+static void
+riscv_set_pc (struct regcache *regcache, CORE_ADDR newpc)
+{
+  elf_gregset_t regset;
+
+  if (sizeof (regset[0]) == 8)
+    linux_set_pc_64bit (regcache, newpc);
+  else
+    linux_set_pc_32bit (regcache, newpc);
+}
+
+/* Correct in either endianness.  */
+static const uint16_t riscv_ibreakpoint[] = { 0x0073, 0x0010 };
+static const uint16_t riscv_cbreakpoint = 0x9002;
+
+/* Implementation of linux_target_ops method "breakpoint_kind_from_pc".  */
+
+static int
+riscv_breakpoint_kind_from_pc (CORE_ADDR *pcptr)
+{
+  union
+    {
+      gdb_byte bytes[2];
+      uint16_t insn;
+    }
+  buf;
+
+  if (target_read_memory (*pcptr, buf.bytes, sizeof (buf.insn)) == 0
+      && riscv_insn_length (buf.insn == sizeof (riscv_ibreakpoint)))
+    return sizeof (riscv_ibreakpoint);
+  else
+    return sizeof (riscv_cbreakpoint);
+}
+
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte *
+riscv_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = kind;
+  switch (kind)
+    {
+      case sizeof (riscv_ibreakpoint):
+	return (const gdb_byte *) &riscv_ibreakpoint;
+      default:
+	return (const gdb_byte *) &riscv_cbreakpoint;
+    }
+}
+
+/* Implementation of linux_target_ops method "breakpoint_at".  */
+
+static int
+riscv_breakpoint_at (CORE_ADDR pc)
+{
+  union
+    {
+      gdb_byte bytes[2];
+      uint16_t insn;
+    }
+  buf;
+
+  if (target_read_memory (pc, buf.bytes, sizeof (buf.insn)) == 0
+      && (buf.insn == riscv_cbreakpoint
+	  || (buf.insn == riscv_ibreakpoint[0]
+	      && target_read_memory (pc + sizeof (buf.insn), buf.bytes,
+				     sizeof (buf.insn)) == 0
+	      && buf.insn == riscv_ibreakpoint[1])))
+    return 1;
+  else
+    return 0;
+}
+
+/* RISC-V/Linux target operations.  */
+struct linux_target_ops the_low_target =
+{
+  riscv_arch_setup,
+  riscv_regs_info,
+  NULL, /* cannot_fetch_register */
+  NULL, /* cannot_store_register */
+  riscv_fetch_register,
+  riscv_get_pc,
+  riscv_set_pc,
+  riscv_breakpoint_kind_from_pc,
+  riscv_sw_breakpoint_from_kind,
+  NULL, /* get_next_pcs */
+  0,    /* decr_pc_after_break */
+  riscv_breakpoint_at,
+};
+
+/* Initialize the RISC-V/Linux target.  */
+
+void
+initialize_low_arch ()
+{
+  initialize_regsets_info (&riscv_regsets_info);
+}
Index: binutils-gdb/gdb/nat/riscv-linux-tdesc.c
===================================================================
--- binutils-gdb.orig/gdb/nat/riscv-linux-tdesc.c
+++ binutils-gdb/gdb/nat/riscv-linux-tdesc.c
@@ -33,7 +33,7 @@
 
 /* Determine XLEN and FLEN and return a corresponding target description.  */
 
-const struct target_desc *
+struct target_desc *
 riscv_linux_read_description (int tid)
 {
   struct riscv_gdbarch_features features;
Index: binutils-gdb/gdb/nat/riscv-linux-tdesc.h
===================================================================
--- binutils-gdb.orig/gdb/nat/riscv-linux-tdesc.h
+++ binutils-gdb/gdb/nat/riscv-linux-tdesc.h
@@ -22,6 +22,6 @@
 struct target_desc;
 
 /* Return a target description for the LWP identified by TID.  */
-const struct target_desc *riscv_linux_read_description (int tid);
+struct target_desc *riscv_linux_read_description (int tid);
 
 #endif /* NAT_RISCV_LINUX_TDESC_H */

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v4 2/3] RISC-V/Linux/native: Factor out target description determination
  2020-02-01  0:06 [PATCH v4 0/3] RISC-V/Linux `gdbserver' support and associated fixes Maciej W. Rozycki
  2020-02-01  0:06 ` [PATCH v4 1/3] RISC-V/Linux/native: Determine FLEN dynamically Maciej W. Rozycki
  2020-02-01  0:07 ` [PATCH v4 3/3] gdbserver: Add RISC-V/Linux support Maciej W. Rozycki
@ 2020-02-01  0:07 ` Maciej W. Rozycki
  2 siblings, 0 replies; 4+ messages in thread
From: Maciej W. Rozycki @ 2020-02-01  0:07 UTC (permalink / raw)
  To: gdb-patches
  Cc: Jim Wilson, Andrew Burgess, Palmer Dabbelt, Tom Tromey, guoren,
	lifang_xia, yunhai_shang, jiangshuai_li

In preparation for RISC-V/Linux `gdbserver' support factor out parts of 
native target description determination code that can be shared between 
the programs.

	gdb/
	* nat/riscv-linux-tdesc.h: New file.
	* nat/riscv-linux-tdesc.c: New file, taking code from...
	* riscv-linux-nat.c (riscv_linux_nat_target::read_description): 
	... here.
	* configure.nat <linux> <riscv*>: Add nat/riscv-linux-tdesc.o to
	NATDEPFILES.
---
No changes from v3.

Changes from v2:

- Carry the change to the FGR reference over from 1/3.

New change in v2.
---
 gdb/configure.nat           |    3 +
 gdb/nat/riscv-linux-tdesc.c |   83 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/nat/riscv-linux-tdesc.h |   27 ++++++++++++++
 gdb/riscv-linux-nat.c       |   51 +--------------------------
 4 files changed, 115 insertions(+), 49 deletions(-)

gdb-riscv-linux-nat-tdesc.diff
Index: binutils-gdb/gdb/configure.nat
===================================================================
--- binutils-gdb.orig/gdb/configure.nat
+++ binutils-gdb/gdb/configure.nat
@@ -276,7 +276,8 @@ case ${gdb_host} in
 		;;
 	    riscv*)
 		# Host: RISC-V, running Linux
-		NATDEPFILES="${NATDEPFILES} riscv-linux-nat.o"
+		NATDEPFILES="${NATDEPFILES} riscv-linux-nat.o \
+		nat/riscv-linux-tdesc.o"
 		;;
 	    s390)
 		# Host: S390, running Linux
Index: binutils-gdb/gdb/nat/riscv-linux-tdesc.c
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/nat/riscv-linux-tdesc.c
@@ -0,0 +1,83 @@
+/* GNU/Linux/RISC-V native target description support for GDB.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "gdbsupport/common-defs.h"
+
+#include "gdb_proc_service.h"
+#include "arch/riscv.h"
+#include "elf/common.h"
+#include "nat/gdb_ptrace.h"
+#include "nat/riscv-linux-tdesc.h"
+
+#include <sys/uio.h>
+
+/* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
+#ifndef NFPREG
+# define NFPREG 33
+#endif
+
+/* Determine XLEN and FLEN and return a corresponding target description.  */
+
+const struct target_desc *
+riscv_linux_read_description (int tid)
+{
+  struct riscv_gdbarch_features features;
+  elf_fpregset_t regs;
+  int flen;
+
+  /* Figuring out xlen is easy.  */
+  features.xlen = sizeof (elf_greg_t);
+
+  /* Start with no f-registers.  */
+  features.flen = 0;
+
+  /* How much worth of f-registers can we fetch if any?  */
+  for (flen = sizeof (regs.__f.__f[0]); ; flen *= 2)
+    {
+      size_t regset_size;
+      struct iovec iov;
+
+      /* Regsets have a uniform slot size, so we count FSCR like
+	 an FP data register.  */
+      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);
+}
Index: binutils-gdb/gdb/nat/riscv-linux-tdesc.h
===================================================================
--- /dev/null
+++ binutils-gdb/gdb/nat/riscv-linux-tdesc.h
@@ -0,0 +1,27 @@
+/* GNU/Linux/RISC-V native target description support for GDB.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NAT_RISCV_LINUX_TDESC_H
+#define NAT_RISCV_LINUX_TDESC_H
+
+struct target_desc;
+
+/* Return a target description for the LWP identified by TID.  */
+const struct target_desc *riscv_linux_read_description (int tid);
+
+#endif /* NAT_RISCV_LINUX_TDESC_H */
Index: binutils-gdb/gdb/riscv-linux-nat.c
===================================================================
--- binutils-gdb.orig/gdb/riscv-linux-nat.c
+++ binutils-gdb/gdb/riscv-linux-nat.c
@@ -22,10 +22,11 @@
 #include "linux-nat.h"
 #include "riscv-tdep.h"
 #include "inferior.h"
-#include "target-descriptions.h"
 
 #include "elf/common.h"
 
+#include "nat/riscv-linux-tdesc.h"
+
 #include <sys/ptrace.h>
 
 /* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
@@ -200,53 +201,7 @@ fill_fpregset (const struct regcache *re
 const struct target_desc *
 riscv_linux_nat_target::read_description ()
 {
-  struct riscv_gdbarch_features features;
-  elf_fpregset_t regs;
-  int flen;
-  int tid;
-
-  /* Figuring out xlen is easy.  */
-  features.xlen = sizeof (elf_greg_t);
-
-  tid = inferior_ptid.lwp ();
-
-  /* Start with no f-registers.  */
-  features.flen = 0;
-
-  /* How much worth of f-registers can we fetch if any?  */
-  for (flen = sizeof (regs.__f.__f[0]); ; flen *= 2)
-    {
-      size_t regset_size;
-      struct iovec iov;
-
-      /* Regsets have a uniform slot size, so we count FSCR like
-	 an FP data register.  */
-      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);
+  return riscv_linux_read_description (inferior_ptid.lwp ());
 }
 
 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-02-01  0:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-01  0:06 [PATCH v4 0/3] RISC-V/Linux `gdbserver' support and associated fixes Maciej W. Rozycki
2020-02-01  0:06 ` [PATCH v4 1/3] RISC-V/Linux/native: Determine FLEN dynamically Maciej W. Rozycki
2020-02-01  0:07 ` [PATCH v4 3/3] gdbserver: Add RISC-V/Linux support Maciej W. Rozycki
2020-02-01  0:07 ` [PATCH v4 2/3] RISC-V/Linux/native: Factor out target description determination Maciej W. Rozycki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).