diff options
author | Feiyang Chen <chenfeiyang@loongson.cn> | 2024-01-25 16:32:36 +0800 |
---|---|---|
committer | Tiezhu Yang <yangtiezhu@loongson.cn> | 2024-02-06 18:40:19 +0800 |
commit | e4d74c01e77365f1327e4e567e7579cdd3bf74f6 (patch) | |
tree | 57a80ffa2ea61b4754b9d71f89fcee012966bf05 /gdb | |
parent | 1e9569f383a3d5a88ee07d0c2401bd95613c222e (diff) | |
download | gdb-e4d74c01e77365f1327e4e567e7579cdd3bf74f6.zip gdb-e4d74c01e77365f1327e4e567e7579cdd3bf74f6.tar.gz gdb-e4d74c01e77365f1327e4e567e7579cdd3bf74f6.tar.bz2 |
gdb: LoongArch: Add LBT extension support
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>
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/arch/loongarch.c | 4 | ||||
-rw-r--r-- | gdb/arch/loongarch.h | 8 | ||||
-rw-r--r-- | gdb/features/Makefile | 1 | ||||
-rw-r--r-- | gdb/features/loongarch/lbt.c | 19 | ||||
-rw-r--r-- | gdb/features/loongarch/lbt.xml | 16 | ||||
-rw-r--r-- | gdb/loongarch-linux-nat.c | 66 | ||||
-rw-r--r-- | gdb/loongarch-linux-tdep.c | 107 | ||||
-rw-r--r-- | gdb/loongarch-tdep.c | 18 | ||||
-rw-r--r-- | gdb/loongarch-tdep.h | 1 |
9 files changed, 240 insertions, 0 deletions
diff --git a/gdb/arch/loongarch.c b/gdb/arch/loongarch.c index e9995c9..22f2d39 100644 --- a/gdb/arch/loongarch.c +++ b/gdb/arch/loongarch.c @@ -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; } diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h index d166f9d..4b7ab05 100644 --- a/gdb/arch/loongarch.h +++ b/gdb/arch/loongarch.h @@ -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 diff --git a/gdb/features/Makefile b/gdb/features/Makefile index 7c33c09..ddf4ec2 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -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 index 0000000..869c862 --- /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, "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 index 0000000..6526ee6 --- /dev/null +++ b/gdb/features/loongarch/lbt.xml @@ -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> diff --git a/gdb/loongarch-linux-nat.c b/gdb/loongarch-linux-nat.c index 85d0a96..9bceb8a 100644 --- a/gdb/loongarch-linux-nat.c +++ b/gdb/loongarch-linux-nat.c @@ -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. */ diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c index 726b671..0e82c09 100644 --- a/gdb/loongarch-linux-tdep.c +++ b/gdb/loongarch-linux-tdep.c @@ -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); } diff --git a/gdb/loongarch-tdep.c b/gdb/loongarch-tdep.c index f56e80f..0f4622a 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -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; diff --git a/gdb/loongarch-tdep.h b/gdb/loongarch-tdep.h index 6e0e798..bfe3988 100644 --- a/gdb/loongarch-tdep.h +++ b/gdb/loongarch-tdep.h @@ -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 |