From ea3352172ec868b821fa34b31ba8128bde735405 Mon Sep 17 00:00:00 2001 From: Feiyang Chen Date: Tue, 2 Aug 2022 17:16:56 +0800 Subject: [PATCH] gdb/gdbserver: LoongArch: Improve implementation of fcc registers The current implementation of the fcc register is referenced to the user_fp_state structure of the kernel uapi [1]. struct user_fp_state { uint64_t fpr[32]; uint64_t fcc; uint32_t fcsr; }; But it is mistakenly defined as a 64-bit fputype register, resulting in a confusing output of "info register". (gdb) info register ... fcc {f = 0x0, d = 0x0} {f = 0, d = 0} ... According to "Condition Flag Register" in "LoongArch Reference Manual" [2], there are 8 condition flag registers of size 1. Use 8 registers of uint8 to make it easier for users to view the fcc register groups. (gdb) info register ... fcc0 0x1 1 fcc1 0x0 0 fcc2 0x0 0 fcc3 0x0 0 fcc4 0x0 0 fcc5 0x0 0 fcc6 0x0 0 fcc7 0x0 0 ... [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/loongarch/include/uapi/asm/ptrace.h [2] https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_condition_flag_register Signed-off-by: Feiyang Chen Signed-off-by: Tiezhu Yang --- gdb/arch/loongarch.h | 7 ++-- gdb/features/loongarch/fpu.c | 9 +++++- gdb/features/loongarch/fpu.xml | 9 +++++- gdb/loongarch-linux-tdep.c | 55 +++++++++++++++++++++++++++++--- gdb/loongarch-tdep.c | 6 ++-- gdbserver/linux-loongarch-low.cc | 24 ++++++++++++++ 6 files changed, 99 insertions(+), 11 deletions(-) diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h index 799595b3e60..eae061f7f47 100644 --- a/gdb/arch/loongarch.h +++ b/gdb/arch/loongarch.h @@ -37,9 +37,10 @@ enum loongarch_regnum LOONGARCH_ARG_REGNUM = 8, /* r4-r11: general-purpose argument registers. f0-f7: floating-point argument registers. */ LOONGARCH_FIRST_FP_REGNUM = LOONGARCH_LINUX_NUM_GREGSET, - LOONGARCH_FCC_REGNUM = LOONGARCH_FIRST_FP_REGNUM + 32, - LOONGARCH_FCSR_REGNUM = LOONGARCH_FCC_REGNUM + 1, - LOONGARCH_LINUX_NUM_FPREGSET = 34, + LOONGARCH_LINUX_NUM_FPREGSET = 32, + 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, }; enum loongarch_fputype diff --git a/gdb/features/loongarch/fpu.c b/gdb/features/loongarch/fpu.c index ea3e1dd9980..183ed54989f 100644 --- a/gdb/features/loongarch/fpu.c +++ b/gdb/features/loongarch/fpu.c @@ -49,7 +49,14 @@ create_feature_loongarch_fpu (struct target_desc *result, long regnum) tdesc_create_reg (feature, "f29", regnum++, 1, "float", 64, "fputype"); tdesc_create_reg (feature, "f30", regnum++, 1, "float", 64, "fputype"); tdesc_create_reg (feature, "f31", regnum++, 1, "float", 64, "fputype"); - tdesc_create_reg (feature, "fcc", regnum++, 1, "float", 64, "fputype"); + tdesc_create_reg (feature, "fcc0", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc1", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc2", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc3", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc4", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc5", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc6", regnum++, 1, "float", 8, "uint8"); + tdesc_create_reg (feature, "fcc7", regnum++, 1, "float", 8, "uint8"); tdesc_create_reg (feature, "fcsr", regnum++, 1, "float", 32, "uint32"); return regnum; } diff --git a/gdb/features/loongarch/fpu.xml b/gdb/features/loongarch/fpu.xml index a61057ec442..e81e3382e7d 100644 --- a/gdb/features/loongarch/fpu.xml +++ b/gdb/features/loongarch/fpu.xml @@ -45,6 +45,13 @@ - + + + + + + + + diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c index 3a81ff31972..883245bec7e 100644 --- a/gdb/loongarch-linux-tdep.c +++ b/gdb/loongarch-linux-tdep.c @@ -123,6 +123,7 @@ loongarch_supply_fpregset (const struct regset *r, { const gdb_byte *buf = nullptr; int fprsize = register_size (regcache->arch (), LOONGARCH_FIRST_FP_REGNUM); + int fccsize = register_size (regcache->arch (), LOONGARCH_FIRST_FCC_REGNUM); if (regnum == -1) { @@ -131,12 +132,33 @@ loongarch_supply_fpregset (const struct regset *r, buf = (const gdb_byte *)fprs + fprsize * i; regcache->raw_supply (LOONGARCH_FIRST_FP_REGNUM + i, (const void *)buf); } + for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++) + { + buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * i; + regcache->raw_supply (LOONGARCH_FIRST_FCC_REGNUM + i, (const void *)buf); + } + buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC; + regcache->raw_supply (LOONGARCH_FCSR_REGNUM, (const void *)buf); } - else if (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum <= LOONGARCH_FCSR_REGNUM) + else if (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum < LOONGARCH_FIRST_FCC_REGNUM) { buf = (const gdb_byte *)fprs + fprsize * (regnum - LOONGARCH_FIRST_FP_REGNUM); regcache->raw_supply (regnum, (const void *)buf); } + else if (regnum >= LOONGARCH_FIRST_FCC_REGNUM && regnum < LOONGARCH_FCSR_REGNUM) + { + buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * (regnum - LOONGARCH_FIRST_FCC_REGNUM); + regcache->raw_supply (regnum, (const void *)buf); + } + else if (regnum == LOONGARCH_FCSR_REGNUM) + { + buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC; + regcache->raw_supply (regnum, (const void *)buf); + } } /* Pack the GDB's register cache value into an elf_fpregset_t. */ @@ -147,6 +169,7 @@ loongarch_fill_fpregset (const struct regset *r, { gdb_byte *buf = nullptr; int fprsize = register_size (regcache->arch (), LOONGARCH_FIRST_FP_REGNUM); + int fccsize = register_size (regcache->arch (), LOONGARCH_FIRST_FCC_REGNUM); if (regnum == -1) { @@ -155,12 +178,33 @@ loongarch_fill_fpregset (const struct regset *r, buf = (gdb_byte *)fprs + fprsize * i; regcache->raw_collect (LOONGARCH_FIRST_FP_REGNUM + i, (void *)buf); } + for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++) + { + buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * i; + regcache->raw_collect (LOONGARCH_FIRST_FCC_REGNUM + i, (void *)buf); + } + buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC; + regcache->raw_collect (LOONGARCH_FCSR_REGNUM, (void *)buf); } - else if (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum <= LOONGARCH_FCSR_REGNUM) + else if (regnum >= LOONGARCH_FIRST_FP_REGNUM && regnum < LOONGARCH_FIRST_FCC_REGNUM) { buf = (gdb_byte *)fprs + fprsize * (regnum - LOONGARCH_FIRST_FP_REGNUM); regcache->raw_collect (regnum, (void *)buf); } + else if (regnum >= LOONGARCH_FIRST_FCC_REGNUM && regnum < LOONGARCH_FCSR_REGNUM) + { + buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * (regnum - LOONGARCH_FIRST_FCC_REGNUM); + regcache->raw_collect (regnum, (void *)buf); + } + else if (regnum == LOONGARCH_FCSR_REGNUM) + { + buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC; + regcache->raw_collect (regnum, (void *)buf); + } } /* Define the FP register regset. */ @@ -221,11 +265,14 @@ loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch, { int gprsize = register_size (gdbarch, 0); int fprsize = register_size (gdbarch, LOONGARCH_FIRST_FP_REGNUM); + int fccsize = register_size (gdbarch, LOONGARCH_FIRST_FCC_REGNUM); + int fcsrsize = register_size (gdbarch, LOONGARCH_FCSR_REGNUM); + int fpsize = fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC + fcsrsize; cb (".reg", LOONGARCH_LINUX_NUM_GREGSET * gprsize, LOONGARCH_LINUX_NUM_GREGSET * gprsize, &loongarch_gregset, nullptr, cb_data); - cb (".reg2", LOONGARCH_LINUX_NUM_FPREGSET * fprsize, - LOONGARCH_LINUX_NUM_FPREGSET * fprsize, &loongarch_fpregset, nullptr, cb_data); + cb (".reg2", fpsize, fpsize, &loongarch_fpregset, 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 85a1dd70ebd..e63ff01854d 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -1428,10 +1428,12 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Validate the description provides the fpu registers and allocate their numbers. */ regnum = LOONGARCH_FIRST_FP_REGNUM; - for (int i = 0; i < 32; i++) + for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++) valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, loongarch_f_normal_name[i] + 1); - valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, "fcc"); + for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++) + valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, + loongarch_c_normal_name[i] + 1); valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data.get (), regnum++, "fcsr"); if (!valid_p) return nullptr; diff --git a/gdbserver/linux-loongarch-low.cc b/gdbserver/linux-loongarch-low.cc index 7180f315b11..cccf1ba780b 100644 --- a/gdbserver/linux-loongarch-low.cc +++ b/gdbserver/linux-loongarch-low.cc @@ -127,12 +127,24 @@ loongarch_fill_fpregset (struct regcache *regcache, void *buf) { gdb_byte *regbuf = nullptr; int fprsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FP_REGNUM); + int fccsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FCC_REGNUM); for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++) { regbuf = (gdb_byte *)buf + fprsize * i; collect_register (regcache, LOONGARCH_FIRST_FP_REGNUM + i, regbuf); } + + for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++) + { + regbuf = (gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * i; + collect_register (regcache, LOONGARCH_FIRST_FCC_REGNUM + i, regbuf); + } + + regbuf = (gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC; + collect_register (regcache, LOONGARCH_FCSR_REGNUM, regbuf); } /* Supply FPRs from BUF into REGCACHE. */ @@ -142,12 +154,24 @@ loongarch_store_fpregset (struct regcache *regcache, const void *buf) { const gdb_byte *regbuf = nullptr; int fprsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FP_REGNUM); + int fccsize = register_size (regcache->tdesc, LOONGARCH_FIRST_FCC_REGNUM); for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++) { regbuf = (const gdb_byte *)buf + fprsize * i; supply_register (regcache, LOONGARCH_FIRST_FP_REGNUM + i, regbuf); } + + for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++) + { + regbuf = (const gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * i; + supply_register (regcache, LOONGARCH_FIRST_FCC_REGNUM + i, regbuf); + } + + regbuf = (const gdb_byte *)buf + fprsize * LOONGARCH_LINUX_NUM_FPREGSET + + fccsize * LOONGARCH_LINUX_NUM_FCC; + supply_register (regcache, LOONGARCH_FCSR_REGNUM, regbuf); } /* LoongArch/Linux regsets. */ -- 2.30.2