]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: LoongArch: Add LBT extension support
authorFeiyang Chen <chenfeiyang@loongson.cn>
Thu, 25 Jan 2024 08:32:36 +0000 (16:32 +0800)
committerTiezhu Yang <yangtiezhu@loongson.cn>
Tue, 6 Feb 2024 10:40:19 +0000 (18:40 +0800)
Loongson Binary Translation (LBT) is used to accelerate binary
translation, which contains 4 scratch registers (scr0 to scr3),
x86/ARM eflags (eflags) and x87 fpu stack pointer (ftop). This
patch support gdb to fetch/store these registers.

Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn> # Framework
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> # Detail Optimizes
Signed-off-by: Hui Li <lihui@loongson.cn> # Error Fixes
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
gdb/arch/loongarch.c
gdb/arch/loongarch.h
gdb/features/Makefile
gdb/features/loongarch/lbt.c [new file with mode: 0644]
gdb/features/loongarch/lbt.xml [new file with mode: 0644]
gdb/loongarch-linux-nat.c
gdb/loongarch-linux-tdep.c
gdb/loongarch-tdep.c
gdb/loongarch-tdep.h
gdbserver/linux-loongarch-low.cc

index e9995c9fe0fa416249ea9940b0b46c132d221137..22f2d3936cab7c150afae3aa98a9fac81d1248c8 100644 (file)
@@ -27,6 +27,7 @@
 #include "../features/loongarch/fpu.c"
 #include "../features/loongarch/lsx.c"
 #include "../features/loongarch/lasx.c"
+#include "../features/loongarch/lbt.c"
 
 #ifndef GDBSERVER
 #define STATIC_IN_GDB static
@@ -69,6 +70,9 @@ loongarch_create_target_description (const struct loongarch_gdbarch_features fea
   regnum = create_feature_loongarch_lsx (tdesc.get (), regnum);
   regnum = create_feature_loongarch_lasx (tdesc.get (), regnum);
 
+  /* For now we only support creating scr registers, eflags and ftop.  */
+  regnum = create_feature_loongarch_lbt (tdesc.get (), regnum);
+
   return tdesc;
 }
 
index d166f9d5eb9c51f32b1c5a378a7db634f9303305..4b7ab054ea0acb48fb1f3d3c6d3d12cc93098fa3 100644 (file)
@@ -45,6 +45,12 @@ enum loongarch_regnum
   LOONGARCH_LINUX_NUM_LSXREGSET = 32,
   LOONGARCH_FIRST_LASX_REGNUM = LOONGARCH_FIRST_LSX_REGNUM + LOONGARCH_LINUX_NUM_LSXREGSET,
   LOONGARCH_LINUX_NUM_LASXREGSET = 32,
+
+  LOONGARCH_FIRST_SCR_REGNUM = LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET,
+  LOONGARCH_LINUX_NUM_SCR = 4,
+  LOONGARCH_LAST_SCR_REGNUM = LOONGARCH_FIRST_SCR_REGNUM + LOONGARCH_LINUX_NUM_SCR - 1,
+  LOONGARCH_EFLAGS_REGNUM = LOONGARCH_LAST_SCR_REGNUM + 1,
+  LOONGARCH_FTOP_REGNUM = LOONGARCH_EFLAGS_REGNUM + 1,
 };
 
 enum loongarch_fputype
@@ -53,6 +59,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
index 7c33c0933752015b1046777f5791bef754f5c4dd..ddf4ec295a927fcb524f6e83399a37c75995be6e 100644 (file)
@@ -239,6 +239,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
        loongarch/fpu.xml \
        loongarch/lsx.xml \
        loongarch/lasx.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 (file)
index 0000000..869c862
--- /dev/null
@@ -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, "lbt", 64, "uint64");
+  tdesc_create_reg (feature, "scr1", regnum++, 1, "lbt", 64, "uint64");
+  tdesc_create_reg (feature, "scr2", regnum++, 1, "lbt", 64, "uint64");
+  tdesc_create_reg (feature, "scr3", regnum++, 1, "lbt", 64, "uint64");
+  tdesc_create_reg (feature, "eflags", regnum++, 1, "lbt", 32, "uint32");
+  tdesc_create_reg (feature, "ftop", regnum++, 1, "lbt", 32, "uint32");
+  return regnum;
+}
diff --git a/gdb/features/loongarch/lbt.xml b/gdb/features/loongarch/lbt.xml
new file mode 100644 (file)
index 0000000..6526ee6
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022-2024 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="lbt"/>
+  <reg name="scr1" bitsize="64" type="uint64" group="lbt"/>
+  <reg name="scr2" bitsize="64" type="uint64" group="lbt"/>
+  <reg name="scr3" bitsize="64" type="uint64" group="lbt"/>
+  <reg name="eflags" bitsize="32" type="uint32" group="lbt"/>
+  <reg name="ftop" bitsize="32" type="uint32" group="lbt"/>
+</feature>
index 85d0a9619c0bca94fff403d49a53fcbe3eb3b49e..9bceb8a5953d709b8c0d74cb2f0555a087c51ba6 100644 (file)
@@ -265,6 +265,70 @@ store_lasxregs_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_FTOP_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)
+       {
+         /* If kernel dose not support lbt, just return. */
+         if (errno == EINVAL)
+           return;
+         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_FTOP_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)
+       {
+         /* If kernel dose not support lbt, just return. */
+         if (errno == EINVAL)
+           return;
+         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
@@ -277,6 +341,7 @@ loongarch_linux_nat_target::fetch_registers (struct regcache *regcache,
   fetch_fpregs_from_thread(regcache, regnum, tid);
   fetch_lsxregs_from_thread(regcache, regnum, tid);
   fetch_lasxregs_from_thread(regcache, regnum, tid);
+  fetch_lbt_from_thread (regcache, regnum, tid);
 }
 
 /* Implement the "store_registers" target_ops method.  */
@@ -291,6 +356,7 @@ loongarch_linux_nat_target::store_registers (struct regcache *regcache,
   store_fpregs_to_thread(regcache, regnum, tid);
   store_lsxregs_to_thread(regcache, regnum, tid);
   store_lasxregs_to_thread(regcache, regnum, tid);
+  store_lbt_to_thread (regcache, regnum, tid);
 }
 
 /* Return the address in the core dump or inferior of register REGNO.  */
index 726b6716270a82c40d31ab3a01c67d1260cd5056..0e82c09b4ff23530bd36fae91c623bf44555cd5b 100644 (file)
@@ -338,6 +338,107 @@ const struct regset loongarch_lasxregset =
   loongarch_fill_lasxregset,
 };
 
+/* Unpack an lbt regset 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 lbt regset.  */
+
+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
@@ -394,6 +495,10 @@ loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
     fccsize * LOONGARCH_LINUX_NUM_FCC + fcsrsize;
   int lsxrsize = register_size (gdbarch, LOONGARCH_FIRST_LSX_REGNUM);
   int lasxrsize = register_size (gdbarch, LOONGARCH_FIRST_LASX_REGNUM);
+  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);
@@ -402,6 +507,8 @@ loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
       &loongarch_lsxregset, nullptr, cb_data);
   cb (".reg-loongarch-lasx", lasxrsize, lasxrsize,
       &loongarch_lasxregset, nullptr, cb_data);
+  cb (".reg-loongarch-lbt", lbtsize, lbtsize,
+      &loongarch_lbtregset, nullptr, cb_data);
 
 }
 
index f56e80f15b8fe54121c1a5bc199656bce9ded2c3..0f4622a55be315f781d7c2594650fd6ea8cd3e7e 100644 (file)
@@ -1743,6 +1743,24 @@ 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.  */
+  regnum = LOONGARCH_FIRST_SCR_REGNUM;
+  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;
 
index 6e0e798e6c8c5de88420a090611aa779203eb1b9..bfe398898c009db09a41ebba3e275894987c8a37 100644 (file)
@@ -32,6 +32,7 @@ extern const struct regset loongarch_gregset;
 extern const struct regset loongarch_fpregset;
 extern const struct regset loongarch_lsxregset;
 extern const struct regset loongarch_lasxregset;
+extern const struct regset loongarch_lbtregset;
 
 /* Target-dependent structure in gdbarch.  */
 struct loongarch_gdbarch_tdep : gdbarch_tdep_base
index f33c5a6788257075cc8859effa8bed97662f553b..f1e1deb878bae135810135262315a2c7dcd2e693 100644 (file)
@@ -225,6 +225,47 @@ loongarch_store_lasxregset (struct regcache *regcache, const void *buf)
     supply_register (regcache, LOONGARCH_FIRST_LASX_REGNUM + i, *regset + i);
 }
 
+/* Collect lbt regs from REGCACHE into BUF.  */
+
+static void
+loongarch_fill_lbtregset (struct regcache *regcache, void *buf)
+{
+  gdb_byte *regbuf = (gdb_byte*)buf;
+  int scrsize = register_size (regcache->tdesc, LOONGARCH_FIRST_SCR_REGNUM);
+  int eflagssize = register_size (regcache->tdesc, LOONGARCH_EFLAGS_REGNUM);
+  int i;
+
+  for (i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
+    collect_register (regcache, LOONGARCH_FIRST_SCR_REGNUM + i, regbuf + scrsize * i);
+
+  collect_register (regcache, LOONGARCH_EFLAGS_REGNUM,
+                   regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize);
+  collect_register (regcache, LOONGARCH_FTOP_REGNUM,
+                   regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize + eflagssize);
+
+}
+
+/* Supply lbt regs from BUF into REGCACHE.  */
+
+static void
+loongarch_store_lbtregset (struct regcache *regcache, const void *buf)
+{
+
+  gdb_byte *regbuf = (gdb_byte*)buf;
+  int scrsize = register_size (regcache->tdesc, LOONGARCH_FIRST_SCR_REGNUM);
+  int eflagssize = register_size (regcache->tdesc, LOONGARCH_EFLAGS_REGNUM);
+  int i;
+
+  for (i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
+    supply_register (regcache, LOONGARCH_FIRST_SCR_REGNUM + i, regbuf + scrsize * i);
+
+  supply_register (regcache, LOONGARCH_EFLAGS_REGNUM,
+                   regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize);
+  supply_register (regcache, LOONGARCH_FTOP_REGNUM,
+                   regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize + eflagssize);
+
+}
+
 /* LoongArch/Linux regsets.  */
 static struct regset_info loongarch_regsets[] = {
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t),
@@ -235,6 +276,8 @@ static struct regset_info loongarch_regsets[] = {
     OPTIONAL_REGS, loongarch_fill_lsxregset, loongarch_store_lsxregset },
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LASX, sizeof (elf_lasxregset_t),
     OPTIONAL_REGS, loongarch_fill_lasxregset, loongarch_store_lasxregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LBT, LOONGARCH_LBT_REGS_SIZE,
+    OPTIONAL_REGS, loongarch_fill_lbtregset, loongarch_store_lbtregset },
   NULL_REGSET
 };