From: Ezra Sitorus Date: Mon, 17 Nov 2025 12:45:58 +0000 (+0000) Subject: gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb867c384fefad86b59e2a2ea3e5a1230813f2c2;p=thirdparty%2Fbinutils-gdb.git gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux The Floating Point Mode Register controls the behaviours of FP8 instructions. This patch add FPMR to GDB if it is enabled on the target. Approved-By: Luis Machado --- diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 89ecedda57d..503a41c973d 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -604,6 +604,48 @@ store_gcsregs_to_thread (regcache *regcache) perror_with_name (_("Unable to store GCS registers")); } +/* Fill GDB's REGCACHE with the FPMR register set content from the + thread associated with REGCACHE. */ + +static void +fetch_fpmr_from_thread (struct regcache *regcache) +{ + aarch64_gdbarch_tdep *tdep + = gdbarch_tdep (regcache->arch ()); + + int tid = regcache->ptid ().lwp (); + + struct iovec iov; + uint64_t val; + iov.iov_base = &val; + iov.iov_len = sizeof (val); + + if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_FPMR, &iov) < 0) + perror_with_name (_("Unable to fetch FPMR register set")); + regcache->raw_supply (tdep->fpmr_regnum, &val); +} + +/* Store the NT_ARM_FPMR register set contents from GDB's REGCACHE to the + thread associated with REGCACHE. */ + +static void +store_fpmr_to_thread (struct regcache *regcache) +{ + aarch64_gdbarch_tdep *tdep + = gdbarch_tdep (regcache->arch ()); + + int tid = regcache->ptid ().lwp (); + + struct iovec iov; + uint64_t val; + iov.iov_base = &val; + iov.iov_len = sizeof (val); + + regcache->raw_collect (tdep->fpmr_regnum, (char *) &val); + if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_FPMR, &iov) < 0) + perror_with_name (_("Unable to store FPMR register set")); +} + /* The AArch64 version of the "fetch_registers" target_ops method. Fetch REGNO from the target and place the result into REGCACHE. */ @@ -642,6 +684,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno) if (tdep->has_gcs_linux ()) fetch_gcsregs_from_thread (regcache); + + if (tdep->has_fpmr ()) + fetch_fpmr_from_thread (regcache); } /* General purpose register? */ else if (regno < AARCH64_V0_REGNUM) @@ -679,6 +724,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno) && (regno == tdep->gcs_reg_base || regno == tdep->gcs_linux_reg_base || regno == tdep->gcs_linux_reg_base + 1)) fetch_gcsregs_from_thread (regcache); + /* FPMR? */ + else if (tdep->has_fpmr () && (regno == tdep->fpmr_regnum)) + fetch_fpmr_from_thread (regcache); } /* A version of the "fetch_registers" target_ops method used when running @@ -753,6 +801,9 @@ aarch64_store_registers (struct regcache *regcache, int regno) if (tdep->has_gcs_linux ()) store_gcsregs_to_thread (regcache); + + if (tdep->has_fpmr ()) + store_fpmr_to_thread (regcache); } /* General purpose register? */ else if (regno < AARCH64_V0_REGNUM) @@ -784,6 +835,9 @@ aarch64_store_registers (struct regcache *regcache, int regno) && (regno == tdep->gcs_reg_base || regno == tdep->gcs_linux_reg_base || regno == tdep->gcs_linux_reg_base + 1)) store_gcsregs_to_thread (regcache); + /* FPMR? */ + else if (tdep->has_fpmr () && regno == tdep->fpmr_regnum) + store_fpmr_to_thread (regcache); /* PAuth registers are read-only. */ } @@ -969,6 +1023,9 @@ aarch64_linux_nat_target::read_description () if ((hwcap2 & HWCAP2_SME2) || (hwcap2 & HWCAP2_SME2P1)) features.sme2 = supports_zt_registers (tid); + /* Check for FPMR. */ + features.fpmr = hwcap2 & HWCAP2_FPMR; + return aarch64_read_description (features); } diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 048be4f3532..10b44d978af 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -1712,6 +1712,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, features.pauth = hwcap & AARCH64_HWCAP_PACA; features.gcs = features.gcs_linux = hwcap & HWCAP_GCS; features.mte = hwcap2 & HWCAP2_MTE; + features.fpmr = hwcap2 & HWCAP2_FPMR; /* Handle the TLS section. */ asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls"); diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 89142e0a214..0bb23944297 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -4140,6 +4140,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc) features.gcs_linux = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs.linux") != nullptr); + /* Check for FPMR feature. */ + features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr") + != nullptr); + return features; } @@ -4550,6 +4554,16 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) num_pseudo_regs += 32; /* add the Bn scalar register pseudos */ } + int fpmr_regnum = -1; + const struct tdesc_feature *feature_fpmr + = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr"); + if (feature_fpmr != nullptr) + { + fpmr_regnum = num_regs++; + valid_p &= tdesc_numbered_register (feature_fpmr, tdesc_data.get (), + fpmr_regnum, "fpmr"); + } + int first_sme_regnum = -1; int first_sme2_regnum = -1; int first_sme_pseudo_regnum = -1; @@ -4749,6 +4763,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->tls_register_count = tls_register_count; tdep->gcs_reg_base = first_gcs_regnum; tdep->gcs_linux_reg_base = first_gcs_linux_regnum; + tdep->fpmr_regnum = fpmr_regnum; /* Set the SME register set details. The pseudo-registers will be adjusted later. */ diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 99e7d26ce4a..9acd29b2d88 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -207,6 +207,15 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base { return gcs_linux_reg_base != -1; } + + /* First FPMR register. This is -1 if FPMR is not supported. */ + int fpmr_regnum = -1; + + bool + has_fpmr () const + { + return fpmr_regnum != -1; + } }; const target_desc *aarch64_read_description (const aarch64_features &features); diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c index dff2bc16003..622138f43b5 100644 --- a/gdb/arch/aarch64.c +++ b/gdb/arch/aarch64.c @@ -20,6 +20,7 @@ #include "../features/aarch64-core.c" #include "../features/aarch64-fpu.c" +#include "../features/aarch64-fpmr.c" #include "../features/aarch64-sve.c" #include "../features/aarch64-pauth.c" #include "../features/aarch64-mte.c" @@ -73,6 +74,9 @@ aarch64_create_target_description (const aarch64_features &features) if (features.gcs_linux) regnum = create_feature_aarch64_gcs_linux (tdesc.get (), regnum); + if (features.fpmr) + regnum = create_feature_aarch64_fpmr (tdesc.get (), regnum); + return tdesc.release (); } diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h index 0fcdba7fb7d..bcbf47dc3a3 100644 --- a/gdb/arch/aarch64.h +++ b/gdb/arch/aarch64.h @@ -34,6 +34,7 @@ struct aarch64_features uint64_t vq = 0; bool pauth = false; bool mte = false; + bool fpmr = false; /* A positive TLS value indicates the number of TLS registers available. */ uint8_t tls = 0; @@ -68,7 +69,8 @@ inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs) && lhs.svq == rhs.svq && lhs.sme2 == rhs.sme2 && lhs.gcs == rhs.gcs - && lhs.gcs_linux == rhs.gcs_linux; + && lhs.gcs_linux == rhs.gcs_linux + && lhs.fpmr == rhs.fpmr; } namespace std @@ -98,6 +100,8 @@ namespace std h = h << 1 | features.gcs; h = h << 1 | features.gcs_linux; + /* FPMR feature. */ + h = h << 1 | features.fpmr; return h; } }; @@ -242,4 +246,9 @@ enum aarch64_regnum /* Size of the SME2 ZT0 register in bytes. */ #define AARCH64_SME2_ZT0_SIZE 64 +/* Feature check for Floating Point Mode Register. */ +#ifndef HWCAP2_FPMR +#define HWCAP2_FPMR (1ULL << 48) +#endif /* HWCAP2_FPMR */ + #endif /* GDB_ARCH_AARCH64_H */ diff --git a/gdb/features/Makefile b/gdb/features/Makefile index c98e31bc9b6..74a027d931f 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -202,6 +202,7 @@ $(outdir)/%.dat: %.xml number-regs.xsl sort-regs.xsl gdbserver-regs.xsl # For targets with feature based target descriptions, # the set of xml files we'll generate .c files for GDB from. FEATURE_XMLFILES = aarch64-core.xml \ + aarch64-fpmr.xml \ aarch64-fpu.xml \ aarch64-pauth.xml \ aarch64-mte.xml \ diff --git a/gdb/features/aarch64-fpmr.c b/gdb/features/aarch64-fpmr.c new file mode 100644 index 00000000000..a372b12530b --- /dev/null +++ b/gdb/features/aarch64-fpmr.c @@ -0,0 +1,44 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: aarch64-fpmr.xml */ + +#include "gdbsupport/tdesc.h" + +static int +create_feature_aarch64_fpmr (struct target_desc *result, long regnum) +{ + struct tdesc_feature *feature; + + feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.fpmr"); + tdesc_type_with_fields *type_with_fields; + type_with_fields = tdesc_create_enum (feature, "fp8_fmt", 3); + tdesc_add_enum_value (type_with_fields, 0, "E5M2"); + tdesc_add_enum_value (type_with_fields, 1, "E4M3"); + + type_with_fields = tdesc_create_enum (feature, "osc", 1); + tdesc_add_enum_value (type_with_fields, 0, "Inf/NaN"); + tdesc_add_enum_value (type_with_fields, 1, "MaxNormal"); + + type_with_fields = tdesc_create_enum (feature, "osm", 1); + tdesc_add_enum_value (type_with_fields, 0, "Inf"); + tdesc_add_enum_value (type_with_fields, 1, "MaxNormal"); + + type_with_fields = tdesc_create_flags (feature, "fpmr_flags", 8); + tdesc_type *field_type; + field_type = tdesc_named_type (feature, "fp8_fmt"); + tdesc_add_typed_bitfield (type_with_fields, "F8S1", 0, 2, field_type); + field_type = tdesc_named_type (feature, "fp8_fmt"); + tdesc_add_typed_bitfield (type_with_fields, "F8S2", 3, 5, field_type); + field_type = tdesc_named_type (feature, "fp8_fmt"); + tdesc_add_typed_bitfield (type_with_fields, "F8D", 6, 8, field_type); + field_type = tdesc_named_type (feature, "osm"); + tdesc_add_typed_bitfield (type_with_fields, "OSM", 14, 14, field_type); + field_type = tdesc_named_type (feature, "osc"); + tdesc_add_typed_bitfield (type_with_fields, "OSC", 15, 15, field_type); + tdesc_add_bitfield (type_with_fields, "LSCALE", 16, 22); + field_type = tdesc_named_type (feature, "int8"); + tdesc_add_typed_bitfield (type_with_fields, "NSCALE", 24, 31, field_type); + tdesc_add_bitfield (type_with_fields, "LSCALE2", 32, 37); + + tdesc_create_reg (feature, "fpmr", regnum++, 1, NULL, 64, "fpmr_flags"); + return regnum; +} diff --git a/gdb/features/aarch64-fpmr.xml b/gdb/features/aarch64-fpmr.xml new file mode 100644 index 00000000000..3e888432786 --- /dev/null +++ b/gdb/features/aarch64-fpmr.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +