From: Hui Li Date: Thu, 25 Jan 2024 08:32:35 +0000 (+0800) Subject: gdb: LoongArch: Add vector extensions support X-Git-Tag: gdb-15-branchpoint~1049 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1e9569f383a3d5a88ee07d0c2401bd95613c222e;p=thirdparty%2Fbinutils-gdb.git gdb: LoongArch: Add vector extensions support Add LoongArch's vector extensions support, which including 128bit LSX (i.e., Loongson SIMD eXtension) and 256bit LASX (i.e., Loongson Advanced SIMD eXtension). This patch support gdb to fetch/store vector registers. Signed-off-by: Hui Li Signed-off-by: Tiezhu Yang --- diff --git a/gdb/arch/loongarch.c b/gdb/arch/loongarch.c index d1a7bad4d58..e9995c9fe0f 100644 --- a/gdb/arch/loongarch.c +++ b/gdb/arch/loongarch.c @@ -25,6 +25,8 @@ #include "../features/loongarch/base32.c" #include "../features/loongarch/base64.c" #include "../features/loongarch/fpu.c" +#include "../features/loongarch/lsx.c" +#include "../features/loongarch/lasx.c" #ifndef GDBSERVER #define STATIC_IN_GDB static @@ -63,6 +65,10 @@ 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 lsx and lasx. */ + regnum = create_feature_loongarch_lsx (tdesc.get (), regnum); + regnum = create_feature_loongarch_lasx (tdesc.get (), regnum); + return tdesc; } diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h index 1fe75d016de..d166f9d5eb9 100644 --- a/gdb/arch/loongarch.h +++ b/gdb/arch/loongarch.h @@ -41,6 +41,10 @@ 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_LSX_REGNUM = LOONGARCH_FCSR_REGNUM + 1, + LOONGARCH_LINUX_NUM_LSXREGSET = 32, + LOONGARCH_FIRST_LASX_REGNUM = LOONGARCH_FIRST_LSX_REGNUM + LOONGARCH_LINUX_NUM_LSXREGSET, + LOONGARCH_LINUX_NUM_LASXREGSET = 32, }; enum loongarch_fputype diff --git a/gdb/features/Makefile b/gdb/features/Makefile index cda6a49d563..7c33c093375 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -237,6 +237,8 @@ FEATURE_XMLFILES = aarch64-core.xml \ loongarch/base32.xml \ loongarch/base64.xml \ loongarch/fpu.xml \ + loongarch/lsx.xml \ + loongarch/lasx.xml \ riscv/rv32e-xregs.xml \ riscv/32bit-cpu.xml \ riscv/32bit-fpu.xml \ diff --git a/gdb/features/loongarch/lasx.c b/gdb/features/loongarch/lasx.c new file mode 100644 index 00000000000..52d486ecb09 --- /dev/null +++ b/gdb/features/loongarch/lasx.c @@ -0,0 +1,85 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: lasx.xml */ + +#include "gdbsupport/tdesc.h" + +static int +create_feature_loongarch_lasx (struct target_desc *result, long regnum) +{ + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lasx"); + tdesc_type *element_type; + element_type = tdesc_named_type (feature, "ieee_single"); + tdesc_create_vector (feature, "v8f32", element_type, 8); + + element_type = tdesc_named_type (feature, "ieee_double"); + tdesc_create_vector (feature, "v4f64", element_type, 4); + + element_type = tdesc_named_type (feature, "int8"); + tdesc_create_vector (feature, "v32i8", element_type, 32); + + element_type = tdesc_named_type (feature, "int16"); + tdesc_create_vector (feature, "v16i16", element_type, 16); + + element_type = tdesc_named_type (feature, "int32"); + tdesc_create_vector (feature, "v8i32", element_type, 8); + + element_type = tdesc_named_type (feature, "int64"); + tdesc_create_vector (feature, "v4i64", element_type, 4); + + element_type = tdesc_named_type (feature, "uint128"); + tdesc_create_vector (feature, "v2ui128", element_type, 2); + + tdesc_type_with_fields *type_with_fields; + type_with_fields = tdesc_create_union (feature, "lasxv"); + tdesc_type *field_type; + field_type = tdesc_named_type (feature, "v8f32"); + tdesc_add_field (type_with_fields, "v8_float", field_type); + field_type = tdesc_named_type (feature, "v4f64"); + tdesc_add_field (type_with_fields, "v4_double", field_type); + field_type = tdesc_named_type (feature, "v32i8"); + tdesc_add_field (type_with_fields, "v32_int8", field_type); + field_type = tdesc_named_type (feature, "v16i16"); + tdesc_add_field (type_with_fields, "v16_int16", field_type); + field_type = tdesc_named_type (feature, "v8i32"); + tdesc_add_field (type_with_fields, "v8_int32", field_type); + field_type = tdesc_named_type (feature, "v4i64"); + tdesc_add_field (type_with_fields, "v4_int64", field_type); + field_type = tdesc_named_type (feature, "v2ui128"); + tdesc_add_field (type_with_fields, "v2_uint128", field_type); + + tdesc_create_reg (feature, "xr0", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr1", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr2", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr3", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr4", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr5", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr6", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr7", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr8", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr9", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr10", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr11", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr12", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr13", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr14", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr15", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr16", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr17", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr18", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr19", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr20", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr21", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr22", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr23", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr24", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr25", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr26", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr27", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr28", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr29", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr30", regnum++, 1, "lasx", 256, "lasxv"); + tdesc_create_reg (feature, "xr31", regnum++, 1, "lasx", 256, "lasxv"); + return regnum; +} diff --git a/gdb/features/loongarch/lasx.xml b/gdb/features/loongarch/lasx.xml new file mode 100644 index 00000000000..753b982c651 --- /dev/null +++ b/gdb/features/loongarch/lasx.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/loongarch/lsx.c b/gdb/features/loongarch/lsx.c new file mode 100644 index 00000000000..0067c2fe385 --- /dev/null +++ b/gdb/features/loongarch/lsx.c @@ -0,0 +1,82 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: lsx.xml */ + +#include "gdbsupport/tdesc.h" + +static int +create_feature_loongarch_lsx (struct target_desc *result, long regnum) +{ + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lsx"); + tdesc_type *element_type; + element_type = tdesc_named_type (feature, "ieee_single"); + tdesc_create_vector (feature, "v4f32", element_type, 4); + + element_type = tdesc_named_type (feature, "ieee_double"); + tdesc_create_vector (feature, "v2f64", element_type, 2); + + element_type = tdesc_named_type (feature, "int8"); + tdesc_create_vector (feature, "v16i8", element_type, 16); + + element_type = tdesc_named_type (feature, "int16"); + tdesc_create_vector (feature, "v8i16", element_type, 8); + + element_type = tdesc_named_type (feature, "int32"); + tdesc_create_vector (feature, "v4i32", element_type, 4); + + element_type = tdesc_named_type (feature, "int64"); + tdesc_create_vector (feature, "v2i64", element_type, 2); + + tdesc_type_with_fields *type_with_fields; + type_with_fields = tdesc_create_union (feature, "lsxv"); + tdesc_type *field_type; + field_type = tdesc_named_type (feature, "v4f32"); + tdesc_add_field (type_with_fields, "v4_float", field_type); + field_type = tdesc_named_type (feature, "v2f64"); + tdesc_add_field (type_with_fields, "v2_double", field_type); + field_type = tdesc_named_type (feature, "v16i8"); + tdesc_add_field (type_with_fields, "v16_int8", field_type); + field_type = tdesc_named_type (feature, "v8i16"); + tdesc_add_field (type_with_fields, "v8_int16", field_type); + field_type = tdesc_named_type (feature, "v4i32"); + tdesc_add_field (type_with_fields, "v4_int32", field_type); + field_type = tdesc_named_type (feature, "v2i64"); + tdesc_add_field (type_with_fields, "v2_int64", field_type); + field_type = tdesc_named_type (feature, "uint128"); + tdesc_add_field (type_with_fields, "uint128", field_type); + + tdesc_create_reg (feature, "vr0", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr1", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr2", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr3", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr4", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr5", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr6", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr7", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr8", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr9", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr10", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr11", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr12", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr13", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr14", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr15", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr16", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr17", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr18", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr19", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr20", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr21", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr22", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr23", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr24", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr25", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr26", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr27", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr28", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr29", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr30", regnum++, 1, "lsx", 128, "lsxv"); + tdesc_create_reg (feature, "vr31", regnum++, 1, "lsx", 128, "lsxv"); + return regnum; +} diff --git a/gdb/features/loongarch/lsx.xml b/gdb/features/loongarch/lsx.xml new file mode 100644 index 00000000000..e19a404dfd5 --- /dev/null +++ b/gdb/features/loongarch/lsx.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/loongarch-linux-nat.c b/gdb/loongarch-linux-nat.c index fe65b5dfa30..85d0a9619c0 100644 --- a/gdb/loongarch-linux-nat.c +++ b/gdb/loongarch-linux-nat.c @@ -146,6 +146,125 @@ store_fpregs_to_thread (struct regcache *regcache, int regnum, pid_t tid) } } +/* Fill GDB's register array with the Loongson SIMD Extension + register values from the current thread. */ + +static void +fetch_lsxregs_from_thread (struct regcache *regcache, int regnum, pid_t tid) +{ + elf_lsxregset_t regset; + + if ((regnum == -1) + || (regnum >= LOONGARCH_FIRST_LSX_REGNUM && regnum < LOONGARCH_FIRST_LASX_REGNUM)) + { + struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; + + if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LSX, (long) &iovec) < 0) + { + /* If kernel dose not support lsx, just return. */ + if (errno == EINVAL) + return; + + perror_with_name (_("Couldn't get NT_LARCH_LSX registers")); + } + else + loongarch_lsxregset.supply_regset (nullptr, regcache, -1, + ®set, sizeof (regset)); + } +} + +/* Store to the current thread the valid Loongson SIMD Extension + register values in the GDB's register array. */ + +static void +store_lsxregs_to_thread (struct regcache *regcache, int regnum, pid_t tid) +{ + elf_lsxregset_t regset; + + if ((regnum == -1) + || (regnum >= LOONGARCH_FIRST_LSX_REGNUM && regnum < LOONGARCH_FIRST_LASX_REGNUM)) + { + struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; + + if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LSX, (long) &iovec) < 0) + { + /* If kernel dose not support lsx, just return. */ + if (errno == EINVAL) + return; + + perror_with_name (_("Couldn't get NT_LARCH_LSX registers")); + } + else + { + loongarch_lsxregset.collect_regset (nullptr, regcache, regnum, + ®set, sizeof (regset)); + if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LSX, (long) &iovec) < 0) + perror_with_name (_("Couldn't set NT_LARCH_LSX registers")); + } + } +} + +/* Fill GDB's register array with the Loongson Advanced SIMD Extension + register values from the current thread. */ + +static void +fetch_lasxregs_from_thread (struct regcache *regcache, int regnum, pid_t tid) +{ + elf_lasxregset_t regset; + + if ((regnum == -1) + || (regnum >= LOONGARCH_FIRST_LASX_REGNUM + && regnum < LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET)) + { + struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; + + if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LASX, (long) &iovec) < 0) + { + /* If kernel dose not support lasx, just return. */ + if (errno == EINVAL) + return; + + perror_with_name (_("Couldn't get NT_LARCH_LSX registers")); + } + else + loongarch_lasxregset.supply_regset (nullptr, regcache, -1, + ®set, sizeof (regset)); + } +} + +/* Store to the current thread the valid Loongson Advanced SIMD Extension + register values in the GDB's register array. */ + +static void +store_lasxregs_to_thread (struct regcache *regcache, int regnum, pid_t tid) +{ + elf_lasxregset_t regset; + + if ((regnum == -1) + || (regnum >= LOONGARCH_FIRST_LASX_REGNUM + && regnum < LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET)) + { + struct iovec iovec = { .iov_base = ®set, .iov_len = sizeof (regset) }; + + if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LASX, (long) &iovec) < 0) + { + /* If kernel dose not support lasx, just return. */ + if (errno == EINVAL) + return; + + perror_with_name (_("Couldn't get NT_LARCH_LSX registers")); + } + else + { + loongarch_lasxregset.collect_regset (nullptr, regcache, regnum, + ®set, sizeof (regset)); + if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LASX, (long) &iovec) < 0) + perror_with_name (_("Couldn't set NT_LARCH_LASX registers")); + } + } +} + + /* Implement the "fetch_registers" target_ops method. */ void @@ -156,6 +275,8 @@ loongarch_linux_nat_target::fetch_registers (struct regcache *regcache, fetch_gregs_from_thread(regcache, regnum, tid); fetch_fpregs_from_thread(regcache, regnum, tid); + fetch_lsxregs_from_thread(regcache, regnum, tid); + fetch_lasxregs_from_thread(regcache, regnum, tid); } /* Implement the "store_registers" target_ops method. */ @@ -168,6 +289,8 @@ loongarch_linux_nat_target::store_registers (struct regcache *regcache, store_gregs_to_thread (regcache, regnum, tid); store_fpregs_to_thread(regcache, regnum, tid); + store_lsxregs_to_thread(regcache, regnum, tid); + store_lasxregs_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 47f36a18931..726b6716270 100644 --- a/gdb/loongarch-linux-tdep.c +++ b/gdb/loongarch-linux-tdep.c @@ -215,6 +215,129 @@ const struct regset loongarch_fpregset = loongarch_fill_fpregset, }; +/* Unpack elf_lsxregset_t into GDB's register cache. */ + +static void +loongarch_supply_lsxregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *lsxrs, size_t len) +{ + int lsxrsize = register_size (regcache->arch (), LOONGARCH_FIRST_LSX_REGNUM); + const gdb_byte *buf = nullptr; + + if (regnum == -1) + { + for (int i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++) + { + buf = (const gdb_byte*) lsxrs + lsxrsize * i; + regcache->raw_supply (LOONGARCH_FIRST_LSX_REGNUM + i, (const void *) buf); + } + + } + else if (regnum >= LOONGARCH_FIRST_LSX_REGNUM && regnum < LOONGARCH_FIRST_LASX_REGNUM) + { + buf = (const gdb_byte*) lsxrs + lsxrsize * (regnum - LOONGARCH_FIRST_LSX_REGNUM); + regcache->raw_supply (regnum, (const void *) buf); + } +} + +/* Pack the GDB's register cache value into an elf_lsxregset_t. */ + +static void +loongarch_fill_lsxregset (const struct regset *regset, + const struct regcache *regcache, int regnum, + void *lsxrs, size_t len) +{ + int lsxrsize = register_size (regcache->arch (), LOONGARCH_FIRST_LSX_REGNUM); + gdb_byte *buf = nullptr; + + if (regnum == -1) + { + for (int i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++) + { + buf = (gdb_byte *) lsxrs + lsxrsize * i; + regcache->raw_collect (LOONGARCH_FIRST_LSX_REGNUM + i, (void *) buf); + } + } + else if (regnum >= LOONGARCH_FIRST_LSX_REGNUM && regnum < LOONGARCH_FIRST_LASX_REGNUM) + { + buf = (gdb_byte *) lsxrs + lsxrsize * (regnum - LOONGARCH_FIRST_LSX_REGNUM); + regcache->raw_collect (regnum, (void *) buf); + } +} + +/* Define the Loongson SIMD Extension register regset. */ + +const struct regset loongarch_lsxregset = +{ + nullptr, + loongarch_supply_lsxregset, + loongarch_fill_lsxregset, +}; + +/* Unpack elf_lasxregset_t into GDB's register cache. */ + +static void +loongarch_supply_lasxregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *lasxrs, size_t len) +{ + int lasxrsize = register_size (regcache->arch (), LOONGARCH_FIRST_LASX_REGNUM); + const gdb_byte *buf = nullptr; + + if (regnum == -1) + { + for (int i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++) + { + buf = (const gdb_byte*) lasxrs + lasxrsize * i; + regcache->raw_supply (LOONGARCH_FIRST_LASX_REGNUM + i, (const void *) buf); + } + + } + else if (regnum >= LOONGARCH_FIRST_LASX_REGNUM + && regnum < LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET) + { + buf = (const gdb_byte*) lasxrs + lasxrsize * (regnum - LOONGARCH_FIRST_LASX_REGNUM); + regcache->raw_supply (regnum, (const void *) buf); + } +} + +/* Pack the GDB's register cache value into an elf_lasxregset_t. */ + +static void +loongarch_fill_lasxregset (const struct regset *regset, + const struct regcache *regcache, int regnum, + void *lasxrs, size_t len) +{ + int lasxrsize = register_size (regcache->arch (), LOONGARCH_FIRST_LASX_REGNUM); + gdb_byte *buf = nullptr; + + if (regnum == -1) + { + for (int i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++) + { + buf = (gdb_byte *) lasxrs + lasxrsize * i; + regcache->raw_collect (LOONGARCH_FIRST_LASX_REGNUM + i, (void *) buf); + } + } + else if (regnum >= LOONGARCH_FIRST_LASX_REGNUM + && regnum < LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET) + + { + buf = (gdb_byte *) lasxrs + lasxrsize * (regnum - LOONGARCH_FIRST_LASX_REGNUM); + regcache->raw_collect (regnum, (void *) buf); + } +} + +/* Define the Loongson Advanced SIMD Extension register regset. */ + +const struct regset loongarch_lasxregset = +{ + nullptr, + loongarch_supply_lasxregset, + loongarch_fill_lasxregset, +}; + /* Implement the "init" method of struct tramp_frame. */ #define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET 128 @@ -269,10 +392,17 @@ 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 lsxrsize = register_size (gdbarch, LOONGARCH_FIRST_LSX_REGNUM); + int lasxrsize = register_size (gdbarch, LOONGARCH_FIRST_LASX_REGNUM); 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-lsx", lsxrsize, lsxrsize, + &loongarch_lsxregset, nullptr, cb_data); + cb (".reg-loongarch-lasx", lasxrsize, lasxrsize, + &loongarch_lasxregset, 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 6d1df8599eb..f56e80f15b8 100644 --- a/gdb/loongarch-tdep.c +++ b/gdb/loongarch-tdep.c @@ -1650,6 +1650,14 @@ loongarch_register_reggroup_p (struct gdbarch *gdbarch, int regnum, if (group == float_reggroup) return 0; + if (LOONGARCH_FIRST_LSX_REGNUM <= regnum + && regnum < LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET) + return group == vector_reggroup; + + /* Only $vrx / $xrx in vector_reggroup */ + if (group == vector_reggroup) + return 0; + int ret = tdesc_register_in_reggroup_p (gdbarch, regnum, group); if (ret != -1) return ret; @@ -1707,6 +1715,34 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) if (!valid_p) return nullptr; + const struct tdesc_feature *feature_lsx + = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lsx"); + if (feature_lsx == nullptr) + return nullptr; + + /* Validate the description provides the lsx registers and + allocate their numbers. */ + regnum = LOONGARCH_FIRST_LSX_REGNUM; + for (int i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++) + valid_p &= tdesc_numbered_register (feature_lsx, tdesc_data.get (), regnum++, + loongarch_v_normal_name[i] + 1); + if (!valid_p) + return nullptr; + + const struct tdesc_feature *feature_lasx + = tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lasx"); + if (feature_lasx == nullptr) + return nullptr; + + /* Validate the description provides the lasx registers and + allocate their numbers. */ + regnum = LOONGARCH_FIRST_LASX_REGNUM; + for (int i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++) + valid_p &= tdesc_numbered_register (feature_lasx, tdesc_data.get (), regnum++, + loongarch_x_normal_name[i] + 1); + 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 06ce2bc3640..6e0e798e6c8 100644 --- a/gdb/loongarch-tdep.h +++ b/gdb/loongarch-tdep.h @@ -30,6 +30,8 @@ /* Register set definitions. */ extern const struct regset loongarch_gregset; extern const struct regset loongarch_fpregset; +extern const struct regset loongarch_lsxregset; +extern const struct regset loongarch_lasxregset; /* 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 c7328b2121e..f33c5a67882 100644 --- a/gdbserver/linux-loongarch-low.cc +++ b/gdbserver/linux-loongarch-low.cc @@ -177,12 +177,64 @@ loongarch_store_fpregset (struct regcache *regcache, const void *buf) supply_register (regcache, LOONGARCH_FCSR_REGNUM, regbuf); } +/* Collect lsx regs from REGCACHE into BUF. */ + +static void +loongarch_fill_lsxregset (struct regcache *regcache, void *buf) +{ + elf_lsxregset_t *regset = (elf_lsxregset_t *) buf; + int i; + + for (i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++) + collect_register (regcache, LOONGARCH_FIRST_LSX_REGNUM + i, *regset + i); +} + +/* Supply lsx regs from BUF into REGCACHE. */ + +static void +loongarch_store_lsxregset (struct regcache *regcache, const void *buf) +{ + const elf_lsxregset_t *regset = (const elf_lsxregset_t *) buf; + int i; + + for (i = 0; i < LOONGARCH_LINUX_NUM_LSXREGSET; i++) + supply_register (regcache, LOONGARCH_FIRST_LSX_REGNUM + i, *regset + i); +} + +/* Collect lasx regs from REGCACHE into BUF. */ + +static void +loongarch_fill_lasxregset (struct regcache *regcache, void *buf) +{ + elf_lasxregset_t *regset = (elf_lasxregset_t *) buf; + int i; + + for (i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++) + collect_register (regcache, LOONGARCH_FIRST_LASX_REGNUM + i, *regset + i); +} + +/* Supply lasx regs from BUF into REGCACHE. */ + +static void +loongarch_store_lasxregset (struct regcache *regcache, const void *buf) +{ + const elf_lasxregset_t *regset = (const elf_lasxregset_t *) buf; + int i; + + for (i = 0; i < LOONGARCH_LINUX_NUM_LASXREGSET; i++) + supply_register (regcache, LOONGARCH_FIRST_LASX_REGNUM + i, *regset + i); +} + /* LoongArch/Linux regsets. */ static struct regset_info loongarch_regsets[] = { { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t), GENERAL_REGS, loongarch_fill_gregset, loongarch_store_gregset }, { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, sizeof (elf_fpregset_t), FP_REGS, loongarch_fill_fpregset, loongarch_store_fpregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LSX, sizeof (elf_lsxregset_t), + 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 }, NULL_REGSET };