[v2] gdb: LoongArch: Support LBT registers

Message ID 20230831120050.3878201-1-zhoubinbin@loongson.cn
State New
Headers
Series [v2] gdb: LoongArch: Support LBT registers |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed

Commit Message

Binbin Zhou Aug. 31, 2023, noon UTC
  From: Feiyang Chen <chenfeiyang@loongson.cn>

Add LBT registers ($scrx, $eflags, $ftop) support for LoongArch.

Co-authored-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
v2:
Thanks to Kevin for his suggestion.
1. Rename LOONGARCH_SCR_REGNUM to LOONGARCH_LAST_SCR_REGNUM for better understanding;
2. Format the code so that a line of source code will not be exceeding 80 characters;
3. Change NT_LOONGARCH_LBT to NT_LARCH_LBT.

Link to V1:
https://inbox.sourceware.org/gdb-patches/20230825101113.3527944-1-chenfeiyang@loongson.cn/

 gdb/arch/loongarch.c             |   4 ++
 gdb/arch/loongarch.h             |   7 ++
 gdb/features/Makefile            |   1 +
 gdb/features/loongarch/lbt.c     |  19 ++++++
 gdb/features/loongarch/lbt.xml   |  16 +++++
 gdb/loongarch-linux-nat.c        |  56 ++++++++++++++++
 gdb/loongarch-linux-tdep.c       | 107 +++++++++++++++++++++++++++++++
 gdb/loongarch-tdep.c             |  17 +++++
 gdb/loongarch-tdep.h             |   1 +
 gdbserver/linux-loongarch-low.cc |  10 +++
 10 files changed, 238 insertions(+)
 create mode 100644 gdb/features/loongarch/lbt.c
 create mode 100644 gdb/features/loongarch/lbt.xml
  

Comments

Kevin Buettner Aug. 31, 2023, 4:05 p.m. UTC | #1
On Thu, 31 Aug 2023 20:00:50 +0800
Binbin Zhou <zhoubinbin@loongson.cn> wrote:

> From: Feiyang Chen <chenfeiyang@loongson.cn>
> 
> Add LBT registers ($scrx, $eflags, $ftop) support for LoongArch.
> 
> Co-authored-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
> v2:
> Thanks to Kevin for his suggestion.
> 1. Rename LOONGARCH_SCR_REGNUM to LOONGARCH_LAST_SCR_REGNUM for better understanding;
> 2. Format the code so that a line of source code will not be exceeding 80 characters;
> 3. Change NT_LOONGARCH_LBT to NT_LARCH_LBT.
> 
> Link to V1:
> https://inbox.sourceware.org/gdb-patches/20230825101113.3527944-1-chenfeiyang@loongson.cn/

Move the Co-authored-by tag towards the bottom of the commit message.

Aside, from that, it looks good to me.

Approved-by: Kevin Buettner <kevinb@redhat.com>
  
Tiezhu Yang Sept. 7, 2023, 11:31 a.m. UTC | #2
On 08/31/2023 08:00 PM, Binbin Zhou wrote:
> From: Feiyang Chen <chenfeiyang@loongson.cn>
>
> Add LBT registers ($scrx, $eflags, $ftop) support for LoongArch.
>
> Co-authored-by: Binbin Zhou <zhoubinbin@loongson.cn>

The patch itself looks good to me, but it is related and conflicted
with the patch "gdb: LoongArch: Add vector extensions support", and
the proper sequence is gpr, fpr, lsx, lasx and lbt.

No need to send v3, I can adjust the related code when applying the
vector and lbt patches after more testing.

Thanks,
Tiezhu
  

Patch

diff --git a/gdb/arch/loongarch.c b/gdb/arch/loongarch.c
index 168fcbc15df..255531a50f7 100644
--- a/gdb/arch/loongarch.c
+++ b/gdb/arch/loongarch.c
@@ -25,6 +25,7 @@ 
 #include "../features/loongarch/base32.c"
 #include "../features/loongarch/base64.c"
 #include "../features/loongarch/fpu.c"
+#include "../features/loongarch/lbt.c"
 
 #ifndef GDBSERVER
 #define STATIC_IN_GDB static
@@ -63,6 +64,9 @@  loongarch_create_target_description (const struct loongarch_gdbarch_features fea
   /* For now we only support creating single float and double float.  */
   regnum = create_feature_loongarch_fpu (tdesc.get (), regnum);
 
+  /* For now we only support creating scr registers, eflags and ftop.  */
+  regnum = create_feature_loongarch_lbt (tdesc.get (), regnum);
+
   return tdesc;
 }
 
diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h
index d0a63dc2ac5..b30087e3f49 100644
--- a/gdb/arch/loongarch.h
+++ b/gdb/arch/loongarch.h
@@ -41,6 +41,11 @@  enum loongarch_regnum
   LOONGARCH_FIRST_FCC_REGNUM = LOONGARCH_FIRST_FP_REGNUM + LOONGARCH_LINUX_NUM_FPREGSET,
   LOONGARCH_LINUX_NUM_FCC = 8,
   LOONGARCH_FCSR_REGNUM = LOONGARCH_FIRST_FCC_REGNUM + LOONGARCH_LINUX_NUM_FCC,
+  LOONGARCH_FIRST_SCR_REGNUM = LOONGARCH_FCSR_REGNUM + 1,
+  LOONGARCH_LINUX_NUM_SCR = 4,
+  LOONGARCH_LAST_SCR_REGNUM = LOONGARCH_FCSR_REGNUM + LOONGARCH_LINUX_NUM_SCR,
+  LOONGARCH_EFLAGS_REGNUM = LOONGARCH_LAST_SCR_REGNUM + 1,
+  LOONGARCH_FTOP_REGNUM = LOONGARCH_EFLAGS_REGNUM + 1,
 };
 
 enum loongarch_fputype
@@ -49,6 +54,8 @@  enum loongarch_fputype
   DOUBLE_FLOAT = 2,
 };
 
+#define LOONGARCH_LBT_REGS_SIZE (8 * LOONGARCH_LINUX_NUM_SCR + 4 + 4)
+
 /* The set of LoongArch architectural features that we track that impact how
    we configure the actual gdbarch instance.  We hold one of these in the
    gdbarch_tdep structure, and use it to distinguish between different
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 32341f71815..1d8221166e8 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -237,6 +237,7 @@  FEATURE_XMLFILES = aarch64-core.xml \
 	loongarch/base32.xml \
 	loongarch/base64.xml \
 	loongarch/fpu.xml \
+	loongarch/lbt.xml \
 	riscv/rv32e-xregs.xml \
 	riscv/32bit-cpu.xml \
 	riscv/32bit-fpu.xml \
diff --git a/gdb/features/loongarch/lbt.c b/gdb/features/loongarch/lbt.c
new file mode 100644
index 00000000000..02cf6ba9358
--- /dev/null
+++ b/gdb/features/loongarch/lbt.c
@@ -0,0 +1,19 @@ 
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: lbt.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_loongarch_lbt (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lbt");
+  tdesc_create_reg (feature, "scr0", regnum++, 1, "general", 64, "uint64");
+  tdesc_create_reg (feature, "scr1", regnum++, 1, "general", 64, "uint64");
+  tdesc_create_reg (feature, "scr2", regnum++, 1, "general", 64, "uint64");
+  tdesc_create_reg (feature, "scr3", regnum++, 1, "general", 64, "uint64");
+  tdesc_create_reg (feature, "eflags", regnum++, 1, "general", 32, "uint32");
+  tdesc_create_reg (feature, "ftop", regnum++, 1, "general", 32, "uint32");
+  return regnum;
+}
diff --git a/gdb/features/loongarch/lbt.xml b/gdb/features/loongarch/lbt.xml
new file mode 100644
index 00000000000..d01311dfab6
--- /dev/null
+++ b/gdb/features/loongarch/lbt.xml
@@ -0,0 +1,16 @@ 
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.lbt">
+  <reg name="scr0" bitsize="64" type="uint64" group="general"/>
+  <reg name="scr1" bitsize="64" type="uint64" group="general"/>
+  <reg name="scr2" bitsize="64" type="uint64" group="general"/>
+  <reg name="scr3" bitsize="64" type="uint64" group="general"/>
+  <reg name="eflags" bitsize="32" type="uint32" group="general"/>
+  <reg name="ftop" bitsize="32" type="uint32" group="general"/>
+</feature>
diff --git a/gdb/loongarch-linux-nat.c b/gdb/loongarch-linux-nat.c
index 40231d5d753..d981a7dc506 100644
--- a/gdb/loongarch-linux-nat.c
+++ b/gdb/loongarch-linux-nat.c
@@ -146,6 +146,60 @@  store_fpregs_to_thread (struct regcache *regcache, int regnum, pid_t tid)
     }
 }
 
+/* Fill GDB's register array with the lbt register values
+   from the current thread.  */
+
+static void
+fetch_lbt_from_thread (struct regcache *regcache, int regnum, pid_t tid)
+{
+  gdb_byte regset[LOONGARCH_LBT_REGS_SIZE];
+
+  if (regnum == -1
+      || (regnum >= LOONGARCH_FIRST_SCR_REGNUM
+	  && regnum <= LOONGARCH_LAST_SCR_REGNUM))
+  {
+    struct iovec iov;
+
+    iov.iov_base = regset;
+    iov.iov_len = LOONGARCH_LBT_REGS_SIZE;
+
+    if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, (long) &iov) < 0)
+      perror_with_name (_("Couldn't get NT_LARCH_LBT registers"));
+    else
+      loongarch_lbtregset.supply_regset (nullptr, regcache, -1,
+					 regset, LOONGARCH_LBT_REGS_SIZE);
+  }
+}
+
+/* Store to the current thread the valid lbt register values
+   in the GDB's register array.  */
+
+static void
+store_lbt_to_thread (struct regcache *regcache, int regnum, pid_t tid)
+{
+  gdb_byte regset[LOONGARCH_LBT_REGS_SIZE];
+
+  if (regnum == -1
+      || (regnum >= LOONGARCH_FIRST_SCR_REGNUM
+	  && regnum <= LOONGARCH_LAST_SCR_REGNUM))
+  {
+    struct iovec iov;
+
+    iov.iov_base = regset;
+    iov.iov_len = LOONGARCH_LBT_REGS_SIZE;
+
+    if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, (long) &iov) < 0)
+      perror_with_name (_("Couldn't get NT_LARCH_LBT registers"));
+    else
+      {
+	loongarch_lbtregset.collect_regset (nullptr, regcache, regnum,
+					    regset, LOONGARCH_LBT_REGS_SIZE);
+	if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LBT, (long) &iov) < 0)
+	  perror_with_name (_("Couldn't set NT_LARCH_LBT registers"));
+      }
+  }
+}
+
 /* Implement the "fetch_registers" target_ops method.  */
 
 void
@@ -156,6 +210,7 @@  loongarch_linux_nat_target::fetch_registers (struct regcache *regcache,
 
   fetch_gregs_from_thread(regcache, regnum, tid);
   fetch_fpregs_from_thread(regcache, regnum, tid);
+  fetch_lbt_from_thread (regcache, regnum, tid);
 }
 
 /* Implement the "store_registers" target_ops method.  */
@@ -168,6 +223,7 @@  loongarch_linux_nat_target::store_registers (struct regcache *regcache,
 
   store_gregs_to_thread (regcache, regnum, tid);
   store_fpregs_to_thread(regcache, regnum, tid);
+  store_lbt_to_thread (regcache, regnum, tid);
 }
 
 /* Return the address in the core dump or inferior of register REGNO.  */
diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c
index ebd26d5e90e..d5dbcfbd80f 100644
--- a/gdb/loongarch-linux-tdep.c
+++ b/gdb/loongarch-linux-tdep.c
@@ -215,6 +215,107 @@  const struct regset loongarch_fpregset =
   loongarch_fill_fpregset,
 };
 
+/* Unpack an elf_gregset_t into GDB's register cache.  */
+
+static void
+loongarch_supply_lbtregset (const struct regset *regset,
+			    struct regcache *regcache, int regnum,
+			    const void *regs, size_t len)
+{
+  int scrsize = register_size (regcache->arch (), LOONGARCH_FIRST_SCR_REGNUM);
+  int eflagssize = register_size (regcache->arch (), LOONGARCH_EFLAGS_REGNUM);
+  const gdb_byte *buf = nullptr;
+
+  if (regnum == -1)
+    {
+      for (int i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
+	{
+	  buf = (const gdb_byte *) regs + scrsize * i;
+	  regcache->raw_supply (LOONGARCH_FIRST_SCR_REGNUM + i,
+				(const void *) buf);
+	}
+
+      buf = (const gdb_byte*) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
+      regcache->raw_supply (LOONGARCH_EFLAGS_REGNUM, (const void *) buf);
+
+      buf = (const gdb_byte*) regs
+	    + scrsize * LOONGARCH_LINUX_NUM_SCR
+	    + eflagssize;
+      regcache->raw_supply (LOONGARCH_FTOP_REGNUM, (const void *) buf);
+    }
+  else if (regnum >= LOONGARCH_FIRST_SCR_REGNUM
+	   && regnum <= LOONGARCH_LAST_SCR_REGNUM)
+    {
+      buf = (const gdb_byte*) regs
+	    + scrsize * (regnum - LOONGARCH_FIRST_SCR_REGNUM);
+      regcache->raw_supply (regnum, (const void *) buf);
+    }
+  else if (regnum == LOONGARCH_EFLAGS_REGNUM)
+    {
+      buf = (const gdb_byte*) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
+      regcache->raw_supply (regnum, (const void *) buf);
+    }
+  else if (regnum == LOONGARCH_FTOP_REGNUM)
+    {
+      buf = (const gdb_byte*) regs
+	    + scrsize * LOONGARCH_LINUX_NUM_SCR
+	    + eflagssize;
+      regcache->raw_supply (regnum, (const void *) buf);
+    }
+}
+
+/* Pack the GDB's register cache value into an elf_gregset_t.  */
+
+static void
+loongarch_fill_lbtregset (const struct regset *regset,
+			  const struct regcache *regcache, int regnum,
+			  void *regs, size_t len)
+{
+  int scrsize = register_size (regcache->arch (), LOONGARCH_FIRST_SCR_REGNUM);
+  int eflagssize = register_size (regcache->arch (), LOONGARCH_EFLAGS_REGNUM);
+  gdb_byte *buf = nullptr;
+
+  if (regnum == -1)
+    {
+      for (int i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
+	{
+	  buf = (gdb_byte *) regs + scrsize * i;
+	  regcache->raw_collect (LOONGARCH_FIRST_SCR_REGNUM + i, (void *) buf);
+	}
+
+      buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
+      regcache->raw_collect (LOONGARCH_EFLAGS_REGNUM, (void *) buf);
+
+      buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR + eflagssize;
+      regcache->raw_collect (LOONGARCH_FTOP_REGNUM, (void *) buf);
+    }
+  else if (regnum >= LOONGARCH_FIRST_SCR_REGNUM
+	   && regnum <= LOONGARCH_LAST_SCR_REGNUM)
+    {
+      buf = (gdb_byte *) regs + scrsize * (regnum - LOONGARCH_FIRST_SCR_REGNUM);
+      regcache->raw_collect (regnum, (void *) buf);
+    }
+  else if (regnum == LOONGARCH_EFLAGS_REGNUM)
+    {
+      buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
+      regcache->raw_collect (regnum, (void *) buf);
+    }
+ else if (regnum == LOONGARCH_FTOP_REGNUM)
+    {
+      buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR + eflagssize;
+      regcache->raw_collect (regnum, (void *) buf);
+    }
+}
+
+/* Define the lbt register regset.  */
+
+const struct regset loongarch_lbtregset =
+{
+  nullptr,
+  loongarch_supply_lbtregset,
+  loongarch_fill_lbtregset,
+};
+
 /* Implement the "init" method of struct tramp_frame.  */
 
 #define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET	128
@@ -269,10 +370,16 @@  loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
   int fcsrsize = register_size (gdbarch, LOONGARCH_FCSR_REGNUM);
   int fpsize = fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
     fccsize * LOONGARCH_LINUX_NUM_FCC + fcsrsize;
+  int scrsize = register_size (gdbarch, LOONGARCH_FIRST_SCR_REGNUM);
+  int eflagssize = register_size (gdbarch, LOONGARCH_EFLAGS_REGNUM);
+  int ftopsize = register_size (gdbarch, LOONGARCH_FTOP_REGNUM);
+  int lbtsize = scrsize * LOONGARCH_LINUX_NUM_SCR + eflagssize + ftopsize;
 
   cb (".reg", LOONGARCH_LINUX_NUM_GREGSET * gprsize,
       LOONGARCH_LINUX_NUM_GREGSET * gprsize, &loongarch_gregset, nullptr, cb_data);
   cb (".reg2", fpsize, fpsize, &loongarch_fpregset, nullptr, cb_data);
+  cb (".reg-loongarch-lbt", lbtsize, lbtsize,
+      &loongarch_lbtregset, nullptr, cb_data);
 }
 
 /* The following value is derived from __NR_rt_sigreturn in
diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c
index 62c6f9b220e..480b05c8dc2 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -1533,6 +1533,23 @@  loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (!valid_p)
     return nullptr;
 
+  const struct tdesc_feature *feature_lbt
+    = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lbt");
+  if (feature_lbt == nullptr)
+    return nullptr;
+
+  /* Validate the description provides the lbt registers and
+     allocate their numbers.  */
+  for (int i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
+    valid_p &= tdesc_numbered_register (feature_lbt, tdesc_data.get (), regnum++,
+					loongarch_cr_normal_name[i] + 1);
+  valid_p &= tdesc_numbered_register (feature_lbt, tdesc_data.get (), regnum++,
+				      "eflags");
+  valid_p &= tdesc_numbered_register (feature_lbt, tdesc_data.get (), regnum++,
+				      "ftop");
+  if (!valid_p)
+    return nullptr;
+
   /* LoongArch code is always little-endian.  */
   info.byte_order_for_code = BFD_ENDIAN_LITTLE;
 
diff --git a/gdb/loongarch-tdep.h b/gdb/loongarch-tdep.h
index dc80cef468b..14aa1fe7098 100644
--- a/gdb/loongarch-tdep.h
+++ b/gdb/loongarch-tdep.h
@@ -30,6 +30,7 @@ 
 /* Register set definitions.  */
 extern const struct regset loongarch_gregset;
 extern const struct regset loongarch_fpregset;
+extern const struct regset loongarch_lbtregset;
 
 /* Target-dependent structure in gdbarch.  */
 struct loongarch_gdbarch_tdep : gdbarch_tdep_base
diff --git a/gdbserver/linux-loongarch-low.cc b/gdbserver/linux-loongarch-low.cc
index ead2e76d25d..2c7c853ed41 100644
--- a/gdbserver/linux-loongarch-low.cc
+++ b/gdbserver/linux-loongarch-low.cc
@@ -102,6 +102,12 @@  loongarch_fill_gregset (struct regcache *regcache, void *buf)
   collect_register (regcache, LOONGARCH_ORIG_A0_REGNUM, *regset + LOONGARCH_ORIG_A0_REGNUM);
   collect_register (regcache, LOONGARCH_PC_REGNUM, *regset + LOONGARCH_PC_REGNUM);
   collect_register (regcache, LOONGARCH_BADV_REGNUM, *regset + LOONGARCH_BADV_REGNUM);
+  for (i = LOONGARCH_FIRST_SCR_REGNUM; i < LOONGARCH_LAST_SCR_REGNUM; i++)
+    collect_register (regcache, i, *regset + i);
+  collect_register (regcache, LOONGARCH_EFLAGS_REGNUM,
+		    *regset + LOONGARCH_EFLAGS_REGNUM);
+  collect_register (regcache, LOONGARCH_FTOP_REGNUM,
+		    *regset + LOONGARCH_FTOP_REGNUM);
 }
 
 /* Supply GPRs from BUF into REGCACHE.  */
@@ -118,6 +124,10 @@  loongarch_store_gregset (struct regcache *regcache, const void *buf)
   supply_register (regcache, LOONGARCH_ORIG_A0_REGNUM, *regset + LOONGARCH_ORIG_A0_REGNUM);
   supply_register (regcache, LOONGARCH_PC_REGNUM, *regset + LOONGARCH_PC_REGNUM);
   supply_register (regcache, LOONGARCH_BADV_REGNUM, *regset + LOONGARCH_BADV_REGNUM);
+  for (i = LOONGARCH_FIRST_SCR_REGNUM; i < LOONGARCH_LAST_SCR_REGNUM; i++)
+    supply_register (regcache, i, *regset + i);
+  supply_register (regcache, LOONGARCH_EFLAGS_REGNUM, *regset + LOONGARCH_EFLAGS_REGNUM);
+  supply_register (regcache, LOONGARCH_FTOP_REGNUM, *regset + LOONGARCH_FTOP_REGNUM);
 }
 
 /* Collect FPRs from REGCACHE into BUF.  */