From a933b0182800f6798e1e644d1793d70adbbc4918 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Thu, 17 Apr 2025 23:21:28 -0300 Subject: [PATCH] Convert Aarch64 SVE feature to use variable-size registers --- gdb/aarch64-linux-nat.c | 24 ++--- gdb/aarch64-linux-tdep.c | 97 ++++++++++++++---- gdb/aarch64-tdep.c | 117 ++++++++++++++-------- gdb/aarch64-tdep.h | 14 +-- gdb/arch/aarch64.c | 6 +- gdb/arch/aarch64.h | 11 +- gdb/features/Makefile | 1 + gdb/features/aarch64-sve.c | 167 ++++++++++++++----------------- gdb/features/aarch64-sve.xml | 141 ++++++++++++++++++++++++++ gdbserver/linux-aarch64-low.cc | 6 +- gdbserver/linux-aarch64-tdesc.cc | 6 +- 11 files changed, 400 insertions(+), 190 deletions(-) create mode 100644 gdb/features/aarch64-sve.xml diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index b5caf004caf..a9b02de99b0 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -586,7 +586,7 @@ aarch64_fetch_registers (struct regcache *regcache, int regno) /* We attempt to fetch SVE registers if there is support for either SVE or SME (due to the SSVE state of SME). */ - if (tdep->has_sve () || tdep->has_sme ()) + if (tdep->has_sve || tdep->has_sme ()) fetch_sveregs_from_thread (regcache); else fetch_fpregs_from_thread (regcache); @@ -610,10 +610,10 @@ aarch64_fetch_registers (struct regcache *regcache, int regno) else if (regno < AARCH64_V0_REGNUM) fetch_gregs_from_thread (regcache); /* SVE register? */ - else if ((tdep->has_sve () || tdep->has_sme ()) + else if ((tdep->has_sve || tdep->has_sme ()) && regno < AARCH64_SVE_VG_REGNUM) fetch_sveregs_from_thread (regcache); - else if (tdep->has_sve () && regno == AARCH64_SVE_VG_REGNUM) + else if (tdep->has_sve && regno == AARCH64_SVE_VG_REGNUM) fetch_sve_vg_from_thread (regcache); /* FPSIMD register? */ else if (regno <= AARCH64_FPCR_REGNUM) @@ -694,7 +694,7 @@ aarch64_store_registers (struct regcache *regcache, int regno) /* We attempt to store SVE registers if there is support for either SVE or SME (due to the SSVE state of SME). */ - if (tdep->has_sve () || tdep->has_sme ()) + if (tdep->has_sve || tdep->has_sme ()) store_sveregs_to_thread (regcache); else store_fpregs_to_thread (regcache); @@ -715,10 +715,10 @@ aarch64_store_registers (struct regcache *regcache, int regno) else if (regno < AARCH64_V0_REGNUM) store_gregs_to_thread (regcache); /* SVE register? */ - else if ((tdep->has_sve () || tdep->has_sme ()) + else if ((tdep->has_sve || tdep->has_sme ()) && regno < AARCH64_SVE_VG_REGNUM) store_sveregs_to_thread (regcache); - else if (tdep->has_sve () && regno == AARCH64_SVE_VG_REGNUM) + else if (tdep->has_sve && regno == AARCH64_SVE_VG_REGNUM) store_sve_vg_to_thread (regcache); /* FPSIMD register? */ else if (regno <= AARCH64_FPCR_REGNUM) @@ -911,7 +911,7 @@ aarch64_linux_nat_target::read_description () /* SVE/SSVE check. Reading VQ may return either the regular vector length or the streaming vector length, depending on whether streaming mode is active or not. */ - features.vq = aarch64_sve_get_vq (tid); + features.sve = aarch64_sve_get_vq (tid) != 0; features.pauth = hwcap & AARCH64_HWCAP_PACA; features.mte = hwcap2 & HWCAP2_MTE; features.tls = aarch64_tls_register_count (tid); @@ -1025,19 +1025,19 @@ aarch64_linux_nat_target::thread_architecture (ptid_t ptid) the tdep. */ aarch64_gdbarch_tdep *tdep = gdbarch_tdep (inf->arch ()); - uint64_t vq = aarch64_sve_get_vq (ptid.lwp ()); + bool sve = aarch64_sve_get_vq (ptid.lwp ()) != 0; uint64_t svq = aarch64_za_get_svq (ptid.lwp ()); - if (vq == tdep->vq && svq == tdep->sme_svq) + if (sve == tdep->has_sve && svq == tdep->sme_svq) return inf->arch (); /* We reach here if any vector length for the thread is different from its value at process start. Lookup gdbarch via info (potentially creating a - new one) by using a target description that corresponds to the new vq/svq - value and the current architecture features. */ + new one) by using a target description that corresponds to the new + vector/matrix state and the current architecture features. */ const struct target_desc *tdesc = gdbarch_target_desc (inf->arch ()); aarch64_features features = aarch64_features_from_target_desc (tdesc); - features.vq = vq; + features.sve = sve; features.svq = svq; /* Check for the SME2 feature. */ diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 9cee3554187..2ddbebba78c 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -60,6 +60,7 @@ #include "elf/common.h" #include "elf/aarch64.h" #include "arch/aarch64-insn.h" +#include "target-descriptions.h" /* For std::pow */ #include @@ -275,7 +276,8 @@ read_aarch64_ctx (CORE_ADDR ctx_addr, enum bfd_endian byte_order, static void aarch64_linux_restore_vregs (struct gdbarch *gdbarch, struct trad_frame_cache *cache, - CORE_ADDR fpsimd_context) + CORE_ADDR fpsimd_context, + ULONGEST vl) { /* WARNING: SIMD state is laid out in memory in target-endian format. @@ -335,7 +337,7 @@ aarch64_linux_restore_vregs (struct gdbarch *gdbarch, num_regs + AARCH64_B0_REGNUM + i, {buf, B_REGISTER_SIZE}); - if (tdep->has_sve ()) + if (tdep->has_sve) trad_frame_set_reg_value_bytes (cache, num_regs + AARCH64_SVE_V0_REGNUM + i, {buf, V_REGISTER_SIZE}); @@ -356,22 +358,22 @@ aarch64_linux_restore_vregs (struct gdbarch *gdbarch, trad_frame_set_reg_addr (cache, num_regs + AARCH64_B0_REGNUM + i, offset); - if (tdep->has_sve ()) + if (tdep->has_sve) trad_frame_set_reg_addr (cache, num_regs + AARCH64_SVE_V0_REGNUM + i, offset); } - if (tdep->has_sve ()) + if (tdep->has_sve) { /* If SVE is supported for this target, zero out the Z registers then copy the first 16 bytes of each of the V registers to the associated Z register. Otherwise the Z registers will contain uninitialized data. */ - std::vector z_buffer (tdep->vq * 16); + std::vector z_buffer (vl); /* We have already handled the endianness swap above, so we don't need to worry about it here. */ - memcpy (z_buffer.data (), buf, V_REGISTER_SIZE); + memcpy (z_buffer.data (), buf, vl); trad_frame_set_reg_value_bytes (cache, AARCH64_SVE_Z0_REGNUM + i, z_buffer); @@ -403,8 +405,8 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, CORE_ADDR section_end = signal_frame.section_end; uint32_t size, magic; bool extra_found = false; - enum bfd_endian byte_order - = gdbarch_byte_order (get_frame_arch (this_frame)); + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); while ((magic = read_aarch64_ctx (section, byte_order, &size)) != 0 && size != 0) @@ -423,6 +425,11 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, /* Check if the section is followed by a full SVE dump, and set sve_regs if it is. */ gdb_byte buf[4]; + aarch64_gdbarch_tdep *tdep + = gdbarch_tdep (gdbarch); + + if (!tdep->has_sve) + break; /* Extract the vector length. */ if (target_read_memory (section + AARCH64_SVE_CONTEXT_VL_OFFSET, @@ -436,6 +443,10 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, signal_frame.vl = extract_unsigned_integer (buf, 2, byte_order); + if (signal_frame.vl == 0) + error (_ ("Invalid vector length in signal frame %" PRIu64 "."), + signal_frame.vl); + /* Extract the flags to check if we are in streaming mode. */ if (target_read_memory (section + AARCH64_SVE_CONTEXT_FLAGS_OFFSET, @@ -598,7 +609,7 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); /* Restore the SVE / FPSIMD registers. */ - if (tdep->has_sve () && signal_frame.sve_section != 0) + if (tdep->has_sve && signal_frame.sve_section != 0) { ULONGEST vq = sve_vq_from_vl (signal_frame.vl); CORE_ADDR sve_regs = signal_frame.sve_section; @@ -648,8 +659,9 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, fpsimd + AARCH64_FPSIMD_FPCR_OFFSET); /* If there was no SVE section then set up the V registers. */ - if (!tdep->has_sve () || signal_frame.sve_section == 0) - aarch64_linux_restore_vregs (gdbarch, this_cache, fpsimd); + if (!tdep->has_sve || signal_frame.sve_section == 0) + aarch64_linux_restore_vregs (gdbarch, this_cache, fpsimd, + tdep->has_sve ? signal_frame.vl : 0); } /* Restore the SME registers. */ @@ -726,7 +738,7 @@ aarch64_linux_sigframe_prev_arch (const frame_info_ptr &this_frame, const struct target_desc *tdesc = gdbarch_target_desc (get_frame_arch (this_frame)); aarch64_features features = aarch64_features_from_target_desc (tdesc); - features.vq = sve_vq_from_vl (signal_frame.vl); + features.sve = signal_frame.vl != 0; features.svq = (uint8_t) sve_vq_from_vl (signal_frame.svl); struct gdbarch_info info; @@ -735,6 +747,46 @@ aarch64_linux_sigframe_prev_arch (const frame_info_ptr &this_frame, return gdbarch_find_by_info (info); } +/* Implements the "prev_tdesc_parameter" method of struct tramp_frame. */ + +static value * +aarch64_linux_sigframe_prev_tdesc_parameter (const frame_info_ptr &this_frame, + void **this_frame_cache, + unsigned int parameter_id) +{ + gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct aarch64_linux_sigframe signal_frame; + ULONGEST parameter_value; + + aarch64_linux_read_signal_frame_info (this_frame, signal_frame); + + if (tdep->param_sve_vector_length != UINT_MAX + && parameter_id == tdep->param_sve_vector_length) + { + /* In the XML, vector_length is used in bitsize fields, but internally + GDB expects the size in bytes. */ + parameter_value = signal_frame.vl; + } + else if (tdep->param_sve_predicate_length != UINT_MAX + && parameter_id == tdep->param_sve_predicate_length) + { + /* In the XML, predicate_length is used in bitsize fields, but internally + GDB expects the size in bytes. */ + parameter_value = sve_vg_from_vl (signal_frame.vl); + } + else + return nullptr; + + value *result = value::allocate (tdesc_parameter_type (gdbarch, + parameter_id)); + + store_unsigned_integer (result->contents_raw (), byte_order, parameter_value); + + return result; +} + static const struct tramp_frame aarch64_linux_rt_sigframe = { SIGTRAMP_FRAME, @@ -752,6 +804,7 @@ static const struct tramp_frame aarch64_linux_rt_sigframe = aarch64_linux_sigframe_init, nullptr, /* validate */ aarch64_linux_sigframe_prev_arch, /* prev_arch */ + aarch64_linux_sigframe_prev_tdesc_parameter, }; /* Register maps. */ @@ -1053,9 +1106,12 @@ collect_sve_regset (const struct regset *regset, gdb_byte *header = (gdb_byte *) buf; struct gdbarch *gdbarch = regcache->arch (); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - uint64_t vq = tdep->vq; + ULONGEST vg; + // FIXME: Remove this cast. + enum register_status vg_status + = const_cast (regcache)->raw_read (AARCH64_SVE_VG_REGNUM, &vg); + gdb_assert (vg_status == REG_VALID); gdb_assert (buf != NULL); gdb_assert (size > SVE_HEADER_SIZE); @@ -1067,7 +1123,7 @@ collect_sve_regset (const struct regset *regset, store_unsigned_integer (header + SVE_HEADER_MAX_SIZE_OFFSET, SVE_HEADER_MAX_SIZE_LENGTH, byte_order, max_size); store_unsigned_integer (header + SVE_HEADER_VL_OFFSET, SVE_HEADER_VL_LENGTH, - byte_order, sve_vl_from_vq (vq)); + byte_order, sve_vl_from_vg (vg)); uint16_t max_vl = SVE_CORE_DUMMY_MAX_VL; store_unsigned_integer (header + SVE_HEADER_MAX_VL_OFFSET, SVE_HEADER_MAX_VL_LENGTH, byte_order, @@ -1434,14 +1490,15 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, cb (".reg", AARCH64_LINUX_SIZEOF_GREGSET, AARCH64_LINUX_SIZEOF_GREGSET, &aarch64_linux_gregset, NULL, cb_data); - if (tdep->has_sve ()) + if (tdep->has_sve) { /* Create this on the fly in order to handle vector register sizes. */ + // FIXME: Don't use maximum VQ. const struct regcache_map_entry sve_regmap[] = { - { 32, AARCH64_SVE_Z0_REGNUM, (int) (tdep->vq * 16) }, - { 16, AARCH64_SVE_P0_REGNUM, (int) (tdep->vq * 16 / 8) }, - { 1, AARCH64_SVE_FFR_REGNUM, (int) (tdep->vq * 16 / 8) }, + { 32, AARCH64_SVE_Z0_REGNUM, (int)(AARCH64_MAX_SVE_VQ * 16) }, + { 16, AARCH64_SVE_P0_REGNUM, (int)(AARCH64_MAX_SVE_VQ * 16 / 8) }, + { 1, AARCH64_SVE_FFR_REGNUM, (int)(AARCH64_MAX_SVE_VQ * 16 / 8) }, { 1, AARCH64_FPSR_REGNUM, 4 }, { 1, AARCH64_FPCR_REGNUM, 4 }, { 0 } @@ -1624,7 +1681,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, Otherwise the SVE section is considered active. This guarantees we will have the correct target description with the correct SVE vector length. */ - features.vq = aarch64_linux_core_read_vq_from_sections (gdbarch, abfd); + features.sve = aarch64_linux_core_read_vq_from_sections (gdbarch, abfd) != 0; features.pauth = hwcap & AARCH64_HWCAP_PACA; features.mte = hwcap2 & HWCAP2_MTE; diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 19d9f1d745c..b72a3d5aa9f 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -2994,7 +2994,7 @@ aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum) if (is_w_pseudo_register (gdbarch, regnum)) return w_name[regnum - tdep->w_pseudo_base]; - if (tdep->has_sve ()) + if (tdep->has_sve) { static const char *const sve_v_name[] = { @@ -3050,7 +3050,7 @@ aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum) if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32) return aarch64_vnb_type (gdbarch); - if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM + if (tdep->has_sve && p_regnum >= AARCH64_SVE_V0_REGNUM && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM) return aarch64_vnv_type (gdbarch); @@ -3090,7 +3090,7 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum, return group == all_reggroup || group == vector_reggroup; else if (p_regnum >= AARCH64_B0_REGNUM && p_regnum < AARCH64_B0_REGNUM + 32) return group == all_reggroup || group == vector_reggroup; - else if (tdep->has_sve () && p_regnum >= AARCH64_SVE_V0_REGNUM + else if (tdep->has_sve && p_regnum >= AARCH64_SVE_V0_REGNUM && p_regnum < AARCH64_SVE_V0_REGNUM + AARCH64_V_REGS_NUM) return group == all_reggroup || group == vector_reggroup; else if (is_sme_pseudo_register (gdbarch, regnum)) @@ -3285,7 +3285,7 @@ aarch64_pseudo_read_value (gdbarch *gdbarch, const frame_info_ptr &next_frame, return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num, pseudo_offset - AARCH64_B0_REGNUM); - if (tdep->has_sve () && pseudo_offset >= AARCH64_SVE_V0_REGNUM + if (tdep->has_sve && pseudo_offset >= AARCH64_SVE_V0_REGNUM && pseudo_offset < AARCH64_SVE_V0_REGNUM + 32) return aarch64_pseudo_read_value_1 (next_frame, pseudo_reg_num, pseudo_offset - AARCH64_SVE_V0_REGNUM); @@ -3428,7 +3428,7 @@ aarch64_pseudo_write (gdbarch *gdbarch, const frame_info_ptr &next_frame, return aarch64_pseudo_write_1 (gdbarch, next_frame, pseudo_offset - AARCH64_B0_REGNUM, buf); - if (tdep->has_sve () && pseudo_offset >= AARCH64_SVE_V0_REGNUM + if (tdep->has_sve && pseudo_offset >= AARCH64_SVE_V0_REGNUM && pseudo_offset < AARCH64_SVE_V0_REGNUM + 32) return aarch64_pseudo_write_1 (gdbarch, next_frame, pseudo_offset - AARCH64_SVE_V0_REGNUM, buf); @@ -3944,10 +3944,6 @@ aarch64_displaced_step_hw_singlestep (struct gdbarch *gdbarch) const target_desc * aarch64_read_description (const aarch64_features &features) { - if (features.vq > AARCH64_MAX_SVE_VQ) - error (_("VQ is %" PRIu64 ", maximum supported value is %d"), features.vq, - AARCH64_MAX_SVE_VQ); - struct target_desc *tdesc = tdesc_aarch64_map[features]; if (tdesc == NULL) @@ -3959,27 +3955,6 @@ aarch64_read_description (const aarch64_features &features) return tdesc; } -/* Return the VQ used when creating the target description TDESC. */ - -static uint64_t -aarch64_get_tdesc_vq (const struct target_desc *tdesc) -{ - const struct tdesc_feature *feature_sve; - - if (!tdesc_has_registers (tdesc)) - return 0; - - feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve"); - - if (feature_sve == nullptr) - return 0; - - uint64_t vl = tdesc_register_bitsize (feature_sve, - aarch64_sve_register_names[0]) / 8; - return sve_vq_from_vl (vl); -} - - /* Return the svq (streaming vector quotient) used when creating the target description TDESC. */ @@ -4016,7 +3991,8 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc) if (tdesc == nullptr) return features; - features.vq = aarch64_get_tdesc_vq (tdesc); + features.sve + = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve") != nullptr; /* We need to look for a couple pauth feature name variations. */ features.pauth @@ -4315,6 +4291,52 @@ aarch64_remove_non_address_bits (struct gdbarch *gdbarch, CORE_ADDR pointer) return aarch64_remove_top_bits (pointer, mask); } +static void +aarch64_fetch_tdesc_parameter (gdbarch *gdbarch, readable_regcache *regcache, + unsigned int parameter_id) +{ + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->param_sve_vector_length != UINT_MAX + && parameter_id == tdep->param_sve_vector_length) + { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + register_status status; + gdb_byte buf[8]; + + status = regcache->raw_read (AARCH64_SVE_VG_REGNUM, buf); + if (status != REG_VALID) + return; + + ULONGEST vg = extract_unsigned_integer (buf, byte_order); + ULONGEST vl = sve_vl_from_vg (vg); + + /* In the XML, vector_length is used in bitsize fields, but internally + GDB expects the size in bytes. */ + store_unsigned_integer (buf, byte_order, vl); + regcache->supply_parameter (parameter_id, buf); + } + else if (tdep->param_sve_predicate_length != UINT_MAX + && parameter_id == tdep->param_sve_predicate_length) + { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + register_status status; + gdb_byte buf[8]; + + status = regcache->raw_read (AARCH64_SVE_VG_REGNUM, buf); + if (status != REG_VALID) + return; + + ULONGEST vg = extract_unsigned_integer (buf, byte_order); + ULONGEST predicate_length = vg; + + /* In the XML, predicate_length is used in bitsize fields, but internally + GDB expects the size in bytes. */ + store_unsigned_integer (buf, byte_order, predicate_length); + regcache->supply_parameter (parameter_id, buf); + } +} + /* Given NAMES, a vector of strings, initialize it with all the SME pseudo-register names for the current streaming vector length. */ @@ -4360,13 +4382,11 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) int i, num_regs = 0, num_pseudo_regs = 0; int first_pauth_regnum = -1, ra_sign_state_offset = -1; int first_mte_regnum = -1, first_tls_regnum = -1; - uint64_t vq = aarch64_get_tdesc_vq (info.target_desc); + bool has_sve = (info.target_desc == nullptr ? false + : tdesc_find_feature (info.target_desc, + "org.gnu.gdb.aarch64.sve") != nullptr); uint64_t svq = aarch64_get_tdesc_svq (info.target_desc); - if (vq > AARCH64_MAX_SVE_VQ) - internal_error (_("VQ out of bounds: %s (max %d)"), - pulongest (vq), AARCH64_MAX_SVE_VQ); - if (svq > AARCH64_MAX_SVE_VQ) internal_error (_("Streaming vector quotient (svq) out of bounds: %s" " (max %d)"), @@ -4379,18 +4399,17 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { aarch64_gdbarch_tdep *tdep = gdbarch_tdep (best_arch->gdbarch); - if (tdep && tdep->vq == vq && tdep->sme_svq == svq) + if (tdep && tdep->has_sve == has_sve && tdep->sme_svq == svq) return best_arch->gdbarch; } /* Ensure we always have a target descriptor, and that it is for the given VQ value. */ const struct target_desc *tdesc = info.target_desc; - if (!tdesc_has_registers (tdesc) || vq != aarch64_get_tdesc_vq (tdesc) - || svq != aarch64_get_tdesc_svq (tdesc)) + if (!tdesc_has_registers (tdesc)) { aarch64_features features; - features.vq = vq; + features.sve = has_sve; features.svq = svq; tdesc = aarch64_read_description (features); } @@ -4605,7 +4624,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->lowest_pc = 0x20; tdep->jb_pc = -1; /* Longjump support not enabled by default. */ tdep->jb_elt_size = 8; - tdep->vq = vq; + tdep->has_sve = feature_sve != nullptr; tdep->pauth_reg_base = first_pauth_regnum; tdep->pauth_reg_count = pauth_masks; tdep->ra_sign_state_regnum = -1; @@ -4851,6 +4870,19 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) register_aarch64_ravenscar_ops (gdbarch); + tdesc_setup_parameters (gdbarch, tdesc); + + std::optional param_id + = tdesc_parameter_id (gdbarch, "org.gnu.gdb.aarch64.sve", "vector_length"); + if (param_id.has_value ()) + tdep->param_sve_vector_length = *param_id; + param_id = tdesc_parameter_id (gdbarch, "org.gnu.gdb.aarch64.sve", + "predicate_length"); + if (param_id.has_value ()) + tdep->param_sve_predicate_length = *param_id; + + set_gdbarch_fetch_tdesc_parameter (gdbarch, aarch64_fetch_tdesc_parameter); + return gdbarch; } @@ -4865,6 +4897,9 @@ aarch64_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, _("aarch64_dump_tdep: Lowest pc = 0x%s\n"), paddress (gdbarch, tdep->lowest_pc)); + gdb_printf (file, _ ("aarch64_dump_tdep: has_sve = %s\n"), + tdep->has_sve ? "true" : "false"); + /* SME fields. */ gdb_printf (file, _("aarch64_dump_tdep: sme_tile_type_q = %s\n"), host_address_to_string (tdep->sme_tile_type_q)); diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 3b8dcc26545..4e5a71598f6 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -100,14 +100,14 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base int (*aarch64_syscall_record) (struct regcache *regcache, unsigned long svc_number) = nullptr; - /* The VQ value for SVE targets, or zero if SVE is not supported. */ - uint64_t vq = 0; + /* Whether SVE is supported. */ + bool has_sve = false; - /* Returns true if the target supports SVE. */ - bool has_sve () const - { - return vq != 0; - } + /* Internal ID of tdesc parameter for SVE vector_length, in bits. */ + unsigned int param_sve_vector_length = UINT_MAX; + + /* Internal ID of tdesc parameter for SVE predicate_length, in bits. */ + unsigned int param_sve_predicate_length = UINT_MAX; int pauth_reg_base = 0; /* Number of pauth masks. */ diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c index 3e1ca054734..cbf897d2838 100644 --- a/gdb/arch/aarch64.c +++ b/gdb/arch/aarch64.c @@ -42,10 +42,10 @@ aarch64_create_target_description (const aarch64_features &features) regnum = create_feature_aarch64_core (tdesc.get (), regnum); - if (features.vq == 0) - regnum = create_feature_aarch64_fpu (tdesc.get (), regnum); + if (features.sve) + regnum = create_feature_aarch64_sve (tdesc.get (), regnum); else - regnum = create_feature_aarch64_sve (tdesc.get (), regnum, features.vq); + regnum = create_feature_aarch64_fpu (tdesc.get (), regnum); if (features.pauth) regnum = create_feature_aarch64_pauth (tdesc.get (), regnum); diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h index ee18b74b80f..f7c89e7aeae 100644 --- a/gdb/arch/aarch64.h +++ b/gdb/arch/aarch64.h @@ -26,12 +26,7 @@ used to select register sets. */ struct aarch64_features { - /* A non zero VQ value indicates both the presence of SVE and the - Vector Quotient - the number of 128-bit chunks in an SVE Z - register. - - The maximum value for VQ is 16 (5 bits). */ - uint64_t vq = 0; + bool sve = false; bool pauth = false; bool mte = false; @@ -55,7 +50,7 @@ struct aarch64_features inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs) { - return lhs.vq == rhs.vq + return lhs.sve == rhs.sve && lhs.pauth == rhs.pauth && lhs.mte == rhs.mte && lhs.tls == rhs.tls @@ -72,7 +67,7 @@ namespace std { std::size_t h; - h = features.vq; + h = features.sve; h = h << 1 | features.pauth; h = h << 1 | features.mte; /* Shift by two bits for now. We may need to increase this in the future diff --git a/gdb/features/Makefile b/gdb/features/Makefile index 7a8c7999733..bd3a7fd492e 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -203,6 +203,7 @@ FEATURE_XMLFILES = aarch64-core.xml \ aarch64-fpu.xml \ aarch64-pauth.xml \ aarch64-mte.xml \ + aarch64-sve.xml \ arc/v1-core.xml \ arc/v1-aux.xml \ arc/v2-core.xml \ diff --git a/gdb/features/aarch64-sve.c b/gdb/features/aarch64-sve.c index 0b15881f073..af82084e714 100644 --- a/gdb/features/aarch64-sve.c +++ b/gdb/features/aarch64-sve.c @@ -1,76 +1,62 @@ -/* Copyright (C) 2018-2025 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: aarch64-sve.xml */ #include "gdbsupport/tdesc.h" -/* This function is NOT auto generated from xml. Create the aarch64 with SVE - feature into RESULT, where SCALE is the number of 128 bit chunks in a Z - register. */ - static int -create_feature_aarch64_sve (struct target_desc *result, long regnum, - uint64_t scale) +create_feature_aarch64_sve (struct target_desc *result, long regnum) { struct tdesc_feature *feature; - tdesc_type *element_type, *field_type; - tdesc_type_with_fields *type_with_fields; feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.sve"); - + tdesc_type *param_type; + param_type = tdesc_named_type (feature, "uint64"); + const tdesc_parameter ¶m_vector_length = tdesc_create_parameter (*feature, "vector_length", param_type); + param_type = tdesc_named_type (feature, "uint64"); + const tdesc_parameter ¶m_predicate_length = tdesc_create_parameter (*feature, "predicate_length", param_type); + tdesc_type *element_type; element_type = tdesc_named_type (feature, "uint128"); - tdesc_create_vector (feature, "svevqu", element_type, scale); + tdesc_create_vector (feature, "svevqu", element_type, param_vector_length); element_type = tdesc_named_type (feature, "int128"); - tdesc_create_vector (feature, "svevqs", element_type, scale); + tdesc_create_vector (feature, "svevqs", element_type, param_vector_length); element_type = tdesc_named_type (feature, "ieee_double"); - tdesc_create_vector (feature, "svevdf", element_type, 2 * scale); + tdesc_create_vector (feature, "svevdf", element_type, param_vector_length); element_type = tdesc_named_type (feature, "uint64"); - tdesc_create_vector (feature, "svevdu", element_type, 2 * scale); + tdesc_create_vector (feature, "svevdu", element_type, param_vector_length); element_type = tdesc_named_type (feature, "int64"); - tdesc_create_vector (feature, "svevds", element_type, 2 * scale); + tdesc_create_vector (feature, "svevds", element_type, param_vector_length); element_type = tdesc_named_type (feature, "ieee_single"); - tdesc_create_vector (feature, "svevsf", element_type, 4 * scale); + tdesc_create_vector (feature, "svevsf", element_type, param_vector_length); element_type = tdesc_named_type (feature, "uint32"); - tdesc_create_vector (feature, "svevsu", element_type, 4 * scale); + tdesc_create_vector (feature, "svevsu", element_type, param_vector_length); element_type = tdesc_named_type (feature, "int32"); - tdesc_create_vector (feature, "svevss", element_type, 4 * scale); + tdesc_create_vector (feature, "svevss", element_type, param_vector_length); element_type = tdesc_named_type (feature, "ieee_half"); - tdesc_create_vector (feature, "svevhf", element_type, 8 * scale); + tdesc_create_vector (feature, "svevhf", element_type, param_vector_length); element_type = tdesc_named_type (feature, "uint16"); - tdesc_create_vector (feature, "svevhu", element_type, 8 * scale); + tdesc_create_vector (feature, "svevhu", element_type, param_vector_length); element_type = tdesc_named_type (feature, "int16"); - tdesc_create_vector (feature, "svevhs", element_type, 8 * scale); + tdesc_create_vector (feature, "svevhs", element_type, param_vector_length); element_type = tdesc_named_type (feature, "uint8"); - tdesc_create_vector (feature, "svevbu", element_type, 16 * scale); + tdesc_create_vector (feature, "svevbu", element_type, param_vector_length); element_type = tdesc_named_type (feature, "int8"); - tdesc_create_vector (feature, "svevbs", element_type, 16 * scale); + tdesc_create_vector (feature, "svevbs", element_type, param_vector_length); + tdesc_type_with_fields *type_with_fields; type_with_fields = tdesc_create_union (feature, "svevnq"); + tdesc_type *field_type; field_type = tdesc_named_type (feature, "svevqu"); tdesc_add_field (type_with_fields, "u", field_type); field_type = tdesc_named_type (feature, "svevqs"); @@ -118,10 +104,9 @@ create_feature_aarch64_sve (struct target_desc *result, long regnum, field_type = tdesc_named_type (feature, "svevnb"); tdesc_add_field (type_with_fields, "b", field_type); - field_type = tdesc_named_type (feature, "uint8"); - tdesc_create_vector (feature, "svep", field_type, 2 * scale); + element_type = tdesc_named_type (feature, "uint8"); + tdesc_create_vector (feature, "svep", element_type, param_predicate_length); - /* FPSR register type */ type_with_fields = tdesc_create_flags (feature, "fpsr_flags", 4); tdesc_add_flag (type_with_fields, 0, "IOC"); tdesc_add_flag (type_with_fields, 1, "DZC"); @@ -135,7 +120,6 @@ create_feature_aarch64_sve (struct target_desc *result, long regnum, tdesc_add_flag (type_with_fields, 30, "Z"); tdesc_add_flag (type_with_fields, 31, "N"); - /* FPCR register type */ type_with_fields = tdesc_create_flags (feature, "fpcr_flags", 4); tdesc_add_flag (type_with_fields, 0, "FIZ"); tdesc_add_flag (type_with_fields, 1, "AH"); @@ -155,57 +139,58 @@ create_feature_aarch64_sve (struct target_desc *result, long regnum, tdesc_add_flag (type_with_fields, 25, "DN"); tdesc_add_flag (type_with_fields, 26, "AHP"); - tdesc_create_reg (feature, "z0", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z1", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z2", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z3", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z4", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z5", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z6", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z7", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z8", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z9", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z10", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z11", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z12", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z13", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z14", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z15", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z16", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z17", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z18", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z19", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z20", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z21", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z22", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z23", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z24", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z25", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z26", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z27", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z28", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z29", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z30", regnum++, 1, NULL, 128 * scale, "svev"); - tdesc_create_reg (feature, "z31", regnum++, 1, NULL, 128 * scale, "svev"); + regnum = 34; + tdesc_create_reg (feature, "z0", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z1", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z2", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z3", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z4", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z5", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z6", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z7", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z8", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z9", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z10", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z11", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z12", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z13", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z14", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z15", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z16", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z17", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z18", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z19", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z20", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z21", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z22", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z23", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z24", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z25", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z26", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z27", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z28", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z29", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z30", regnum++, 1, NULL, param_vector_length, "svev"); + tdesc_create_reg (feature, "z31", regnum++, 1, NULL, param_vector_length, "svev"); tdesc_create_reg (feature, "fpsr", regnum++, 1, NULL, 32, "fpsr_flags"); tdesc_create_reg (feature, "fpcr", regnum++, 1, NULL, 32, "fpcr_flags"); - tdesc_create_reg (feature, "p0", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p1", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p2", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p3", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p4", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p5", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p6", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p7", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p8", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p9", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p10", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p11", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p12", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p13", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p14", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "p15", regnum++, 1, NULL, 16 * scale, "svep"); - tdesc_create_reg (feature, "ffr", regnum++, 1, NULL, 16 * scale, "svep"); + tdesc_create_reg (feature, "p0", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p1", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p2", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p3", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p4", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p5", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p6", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p7", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p8", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p9", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p10", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p11", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p12", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p13", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p14", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "p15", regnum++, 1, NULL, param_predicate_length, "svep"); + tdesc_create_reg (feature, "ffr", regnum++, 1, NULL, param_predicate_length, "svep"); tdesc_create_reg (feature, "vg", regnum++, 1, NULL, 64, "int"); return regnum; } diff --git a/gdb/features/aarch64-sve.xml b/gdb/features/aarch64-sve.xml new file mode 100644 index 00000000000..6ced6d50f50 --- /dev/null +++ b/gdb/features/aarch64-sve.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc index 2eb3af659ad..0aa626c5414 100644 --- a/gdbserver/linux-aarch64-low.cc +++ b/gdbserver/linux-aarch64-low.cc @@ -882,11 +882,11 @@ aarch64_adjust_register_sets (const struct aarch64_features &features) break; case NT_FPREGSET: /* This is unavailable when SVE is present. */ - if (features.vq == 0) + if (!features.sve) regset->size = sizeof (struct user_fpsimd_state); break; case NT_ARM_SVE: - if (features.vq > 0) + if (features.sve) regset->size = SVE_PT_SIZE (AARCH64_MAX_SVE_VQ, SVE_PT_REGS_SVE); break; case NT_ARM_PAC_MASK: @@ -934,7 +934,7 @@ aarch64_target::low_arch_setup () struct aarch64_features features; int pid = current_thread->id.pid (); - features.vq = aarch64_sve_get_vq (tid); + features.sve = aarch64_sve_get_vq (tid) != 0; /* A-profile PAC is 64-bit only. */ features.pauth = linux_get_hwcap (pid, 8) & AARCH64_HWCAP_PACA; /* A-profile MTE is 64-bit only. */ diff --git a/gdbserver/linux-aarch64-tdesc.cc b/gdbserver/linux-aarch64-tdesc.cc index cbd049dbd24..84cd8712f25 100644 --- a/gdbserver/linux-aarch64-tdesc.cc +++ b/gdbserver/linux-aarch64-tdesc.cc @@ -37,10 +37,6 @@ aarch64_linux_read_description (const aarch64_features &features) initialised. */ static gdb::unordered_map tdesc_aarch64_map; - if (features.vq > AARCH64_MAX_SVE_VQ) - error (_("VQ is %" PRIu64 ", maximum supported value is %d"), features.vq, - AARCH64_MAX_SVE_VQ); - if (features.svq > AARCH64_MAX_SVE_VQ) error (_("Streaming svq is %" PRIu8 ", maximum supported value is %d"), features.svq, @@ -60,7 +56,7 @@ aarch64_linux_read_description (const aarch64_features &features) expedited_registers.push_back ("sp"); expedited_registers.push_back ("pc"); - if (features.vq > 0) + if (features.sve) expedited_registers.push_back ("vg"); if (features.svq > 0) expedited_registers.push_back ("svg"); -- 2.47.2