* [PATCH] gdb: LoongArch: Support LBT registers
@ 2023-08-25 10:11 Feiyang Chen
2023-08-29 2:49 ` Kevin Buettner
0 siblings, 1 reply; 2+ messages in thread
From: Feiyang Chen @ 2023-08-25 10:11 UTC (permalink / raw)
To: yangtiezhu
Cc: Feiyang Chen, chris.chenfeiyang, gdb-patches, zhoubinbin, chenhuacai
Add LBT registers ($scrx, $eflags, $ftop) support for LoongArch.
Co-authored-by: Binbin Zhou <zhoubinbin@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 | 54 ++++++++++++++++++
gdb/loongarch-linux-tdep.c | 98 ++++++++++++++++++++++++++++++++
gdb/loongarch-tdep.c | 15 +++++
gdb/loongarch-tdep.h | 1 +
gdbserver/linux-loongarch-low.cc | 8 +++
10 files changed, 223 insertions(+)
create mode 100644 gdb/features/loongarch/lbt.c
create mode 100644 gdb/features/loongarch/lbt.xml
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..73f3d64fb16 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_SCR_REGNUM = LOONGARCH_FCSR_REGNUM + LOONGARCH_LINUX_NUM_SCR,
+ LOONGARCH_EFLAGS_REGNUM = LOONGARCH_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..184a6715103 100644
--- a/gdb/loongarch-linux-nat.c
+++ b/gdb/loongarch-linux-nat.c
@@ -146,6 +146,58 @@ 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_SCR_REGNUM))
+ {
+ struct iovec iov;
+
+ iov.iov_base = regset;
+ iov.iov_len = LOONGARCH_LBT_REGS_SIZE;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_LOONGARCH_LBT, (long) &iov) < 0)
+ perror_with_name (_("Couldn't get NT_LOONGARCH_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_SCR_REGNUM))
+ {
+ struct iovec iov;
+
+ iov.iov_base = regset;
+ iov.iov_len = LOONGARCH_LBT_REGS_SIZE;
+
+ if (ptrace (PTRACE_GETREGSET, tid, NT_LOONGARCH_LBT, (long) &iov) < 0)
+ perror_with_name (_("Couldn't get NT_LOONGARCH_LBT registers"));
+ else
+ {
+ loongarch_lbtregset.collect_regset (nullptr, regcache, regnum,
+ regset, LOONGARCH_LBT_REGS_SIZE);
+ if (ptrace (PTRACE_SETREGSET, tid, NT_LOONGARCH_LBT, (long) &iov) < 0)
+ perror_with_name (_("Couldn't set NT_LOONGARCH_LBT registers"));
+ }
+ }
+}
+
/* Implement the "fetch_registers" target_ops method. */
void
@@ -156,6 +208,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 +221,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..62fd0aba268 100644
--- a/gdb/loongarch-linux-tdep.c
+++ b/gdb/loongarch-linux-tdep.c
@@ -215,6 +215,99 @@ 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_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_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 +362,15 @@ 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..c463115e95a 100644
--- a/gdb/loongarch-tdep.c
+++ b/gdb/loongarch-tdep.c
@@ -1533,6 +1533,21 @@ 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..66957789844 100644
--- a/gdbserver/linux-loongarch-low.cc
+++ b/gdbserver/linux-loongarch-low.cc
@@ -102,6 +102,10 @@ 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_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 +122,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_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. */
--
2.39.3
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] gdb: LoongArch: Support LBT registers
2023-08-25 10:11 [PATCH] gdb: LoongArch: Support LBT registers Feiyang Chen
@ 2023-08-29 2:49 ` Kevin Buettner
0 siblings, 0 replies; 2+ messages in thread
From: Kevin Buettner @ 2023-08-29 2:49 UTC (permalink / raw)
To: Feiyang Chen
Cc: gdb-patches, yangtiezhu, chris.chenfeiyang, zhoubinbin, chenhuacai
I have one nit regarding an enum name...
On Fri, 25 Aug 2023 18:11:13 +0800
Feiyang Chen <chenfeiyang@loongson.cn> wrote:
> diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h
> index d0a63dc2ac5..73f3d64fb16 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_SCR_REGNUM = LOONGARCH_FCSR_REGNUM + LOONGARCH_LINUX_NUM_SCR,
Instead of LOONGARCH_SCR_REGNUM, I recommend that it be named
LOONGARCH_LAST_SCR_REGNUM instead. This fits in with its usage in the
range tests, e.g. this one from loongarch_supply_lbtregset:
> + else if (regnum >= LOONGARCH_FIRST_SCR_REGNUM && regnum <= LOONGARCH_SCR_REGNUM)
> + {
> + buf = (const gdb_byte*) regs + scrsize * (regnum - LOONGARCH_FIRST_SCR_REGNUM);
> + regcache->raw_supply (regnum, (const void *) buf);
> + }
Naming it LOONGARCH_SCR_REGNUM suggested to me that the index in
question was for the (one and only) SCR register, but that's clearly
not the case since there are 4 of them.
Also, it appears to me that source code corresponding to some of the
lines in your patch will exceed 80 characters, so those should be
adjusted as well. See:
https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Column_limits
Kevin
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-08-29 2:49 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-25 10:11 [PATCH] gdb: LoongArch: Support LBT registers Feiyang Chen
2023-08-29 2:49 ` Kevin Buettner
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).