* [PATCH v2 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
2025-10-07 12:31 [PATCH v2 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
@ 2025-10-07 12:31 ` Ezra.Sitorus
2025-10-11 11:35 ` Luis
2025-10-07 12:31 ` [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
` (4 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Ezra.Sitorus @ 2025-10-07 12:31 UTC (permalink / raw)
To: gdb-patches; +Cc: luis.machado.foss, thiago.bauermann, Ezra Sitorus
From: Ezra Sitorus <ezra.sitorus@arm.com>
The Floating Point Mode Register controls the behaviours of FP8
instructions. This patch add FPMR to GDB if it is enabled on the
target.
---
Changes from v1->v2:
* Addressed comments/whitespace/formatting issues.
* gdb/arch/aarch64.h: operator() takes fpmr into account now.
* Defined HWCAP2_FPMR in gdb/arch/aarch64.h
Ezra
gdb/aarch64-linux-nat.c | 57 +++++++++++++++++++++++++++++++++++
gdb/aarch64-linux-tdep.c | 1 +
gdb/aarch64-tdep.c | 18 ++++++++++-
gdb/aarch64-tdep.h | 9 ++++++
gdb/arch/aarch64.c | 4 +++
gdb/arch/aarch64.h | 12 +++++++-
gdb/features/Makefile | 1 +
gdb/features/aarch64-fpmr.c | 44 +++++++++++++++++++++++++++
gdb/features/aarch64-fpmr.xml | 53 ++++++++++++++++++++++++++++++++
9 files changed, 197 insertions(+), 2 deletions(-)
create mode 100644 gdb/features/aarch64-fpmr.c
create mode 100644 gdb/features/aarch64-fpmr.xml
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<aarch64_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<aarch64_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 500ac77d75a..6c720ce8427 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -4140,9 +4140,14 @@ 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;
}
+
/* Implement the "cannot_store_register" gdbarch method. */
static int
@@ -4448,11 +4453,12 @@ static struct gdbarch *
aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
const struct tdesc_feature *feature_core, *feature_fpu, *feature_sve;
- const struct tdesc_feature *feature_pauth;
+ const struct tdesc_feature *feature_pauth, *feature_fpmr;
bool valid_p = true;
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;
+ int fpmr_regnum = -1;
uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
uint64_t svq = aarch64_get_tdesc_svq (info.target_desc);
@@ -4550,6 +4556,14 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
num_pseudo_regs += 32; /* add the Bn scalar register pseudos */
}
+ 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;
@@ -4761,6 +4775,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Set the SME2 register set details. */
tdep->sme2_zt0_regnum = first_sme2_regnum;
+ /* Set the FPMR regnum. */
+ tdep->fpmr_regnum = fpmr_regnum;
set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
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 679d845df74..8f4ba9c9e0c 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
@@ -94,6 +96,9 @@ namespace std
/* SME2 feature. */
h = h << 1 | features.sme2;
+
+ /* FPMR feature. */
+ h = h << 1 | features.fpmr;
return h;
}
};
@@ -238,4 +243,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 d17c349b6cf..ed1b8bf119c 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -201,6 +201,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..8be2eec58bb
--- /dev/null
+++ b/gdb/features/aarch64-fpmr.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2025 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.aarch64.fpmr">
+ <!-- FP8 format for F8S1, F8S2 and F8D fields. This is either E5M2 or E4M3. -->
+ <enum id="fp8_fmt" size="3">
+ <evalue name="E5M2" value="0"/>
+ <evalue name="E4M3" value="1"/>
+ </enum>
+
+ <!-- Overflow saturation for FP8 convert instructions. Specifies the result
+ when a floating-point Overflow exception is detected. -->
+ <enum id="osc" size="1">
+ <!-- Infinity or NaN is generated. -->
+ <evalue name="Inf/NaN" value="0"/>
+ <!-- Maximum normal number is generated. -->
+ <evalue name="MaxNormal" value="1"/>
+ </enum>
+
+ <!-- Overflow saturation for FP8 multiplication instructions. Specifies the
+ result when a floating-point Overflow exception is detected. -->
+ <enum id="osm" size="1">
+ <!-- Infinity generated. -->
+ <evalue name="Inf" value="0"/>
+ <!-- Maximum normal number is generated. -->
+ <evalue name="MaxNormal" value="1"/>
+ </enum>
+
+ <flags id="fpmr_flags" size="8">
+ <!-- SRC1 Format. -->
+ <field name="F8S1" start="0" end="2" type="fp8_fmt"/>
+ <!-- SRC2 Format. -->
+ <field name="F8S2" start="3" end="5" type="fp8_fmt"/>
+ <!-- F8D Format. -->
+ <field name="F8D" start="6" end="8" type="fp8_fmt"/>
+ <!-- OSM. -->
+ <field name="OSM" start="14" end="14" type="osm"/>
+ <!-- OSC. -->
+ <field name="OSC" start="15" end="15" type="osc"/>
+ <!-- LSCALE. -->
+ <field name="LSCALE" start="16" end="22"/>
+ <!-- NSCALE. -->
+ <field name="NSCALE" start="24" end="31" type="int8"/>
+ <!-- LSCALE2. -->
+ <field name="LSCALE2" start="32" end="37"/>
+ </flags>
+ <reg name="fpmr" bitsize="64" type="fpmr_flags"/>
+</feature>
--
2.45.2
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
2025-10-07 12:31 ` [PATCH v2 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
@ 2025-10-11 11:35 ` Luis
0 siblings, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-11 11:35 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> The Floating Point Mode Register controls the behaviours of FP8
> instructions. This patch add FPMR to GDB if it is enabled on the
> target.
> ---
> Changes from v1->v2:
> * Addressed comments/whitespace/formatting issues.
> * gdb/arch/aarch64.h: operator() takes fpmr into account now.
> * Defined HWCAP2_FPMR in gdb/arch/aarch64.h
>
> Ezra
>
> gdb/aarch64-linux-nat.c | 57 +++++++++++++++++++++++++++++++++++
> gdb/aarch64-linux-tdep.c | 1 +
> gdb/aarch64-tdep.c | 18 ++++++++++-
> gdb/aarch64-tdep.h | 9 ++++++
> gdb/arch/aarch64.c | 4 +++
> gdb/arch/aarch64.h | 12 +++++++-
> gdb/features/Makefile | 1 +
> gdb/features/aarch64-fpmr.c | 44 +++++++++++++++++++++++++++
> gdb/features/aarch64-fpmr.xml | 53 ++++++++++++++++++++++++++++++++
> 9 files changed, 197 insertions(+), 2 deletions(-)
> create mode 100644 gdb/features/aarch64-fpmr.c
> create mode 100644 gdb/features/aarch64-fpmr.xml
>
> 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<aarch64_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<aarch64_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 500ac77d75a..6c720ce8427 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -4140,9 +4140,14 @@ 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;
> }
>
> +
Spurious blank line.
> /* Implement the "cannot_store_register" gdbarch method. */
>
> static int
> @@ -4448,11 +4453,12 @@ static struct gdbarch *
> aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> {
> const struct tdesc_feature *feature_core, *feature_fpu, *feature_sve;
> - const struct tdesc_feature *feature_pauth;
> + const struct tdesc_feature *feature_pauth, *feature_fpmr;
> bool valid_p = true;
> 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;
> + int fpmr_regnum = -1;
Nit, but you can move the above initialization closer to where it is
used. Same for feature_fpmr above.
> uint64_t vq = aarch64_get_tdesc_vq (info.target_desc);
> uint64_t svq = aarch64_get_tdesc_svq (info.target_desc);
>
> @@ -4550,6 +4556,14 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> num_pseudo_regs += 32; /* add the Bn scalar register pseudos */
> }
>
> + 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;
> @@ -4761,6 +4775,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> /* Set the SME2 register set details. */
> tdep->sme2_zt0_regnum = first_sme2_regnum;
>
> + /* Set the FPMR regnum. */
> + tdep->fpmr_regnum = fpmr_regnum;
Nit. Make the above assignment part of the same block of assignments to
tdep values above instead of making it part of the block that sets the
gdbarch hooks below. It provides some visual separation and makes the
code easier to read.
> set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
> set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
>
> 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 679d845df74..8f4ba9c9e0c 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
> @@ -94,6 +96,9 @@ namespace std
>
> /* SME2 feature. */
> h = h << 1 | features.sme2;
> +
> + /* FPMR feature. */
> + h = h << 1 | features.fpmr;
> return h;
> }
> };
> @@ -238,4 +243,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 d17c349b6cf..ed1b8bf119c 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -201,6 +201,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..8be2eec58bb
> --- /dev/null
> +++ b/gdb/features/aarch64-fpmr.xml
> @@ -0,0 +1,53 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2025 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.aarch64.fpmr">
> + <!-- FP8 format for F8S1, F8S2 and F8D fields. This is either E5M2 or E4M3. -->
Formatting. Two spaces after period. Please check the rest of the patch
for these.
> + <enum id="fp8_fmt" size="3">
> + <evalue name="E5M2" value="0"/>
> + <evalue name="E4M3" value="1"/>
> + </enum>
> +
> + <!-- Overflow saturation for FP8 convert instructions. Specifies the result
> + when a floating-point Overflow exception is detected. -->
s/Overflow/overflow?
> + <enum id="osc" size="1">
> + <!-- Infinity or NaN is generated. -->
> + <evalue name="Inf/NaN" value="0"/>
> + <!-- Maximum normal number is generated. -->
> + <evalue name="MaxNormal" value="1"/>
> + </enum>
> +
> + <!-- Overflow saturation for FP8 multiplication instructions. Specifies the
> + result when a floating-point Overflow exception is detected. -->
s/Overflow/overflow?
> + <enum id="osm" size="1">
> + <!-- Infinity generated. -->
> + <evalue name="Inf" value="0"/>
> + <!-- Maximum normal number is generated. -->
> + <evalue name="MaxNormal" value="1"/>
> + </enum>
> +
> + <flags id="fpmr_flags" size="8">
> + <!-- SRC1 Format. -->
> + <field name="F8S1" start="0" end="2" type="fp8_fmt"/>
> + <!-- SRC2 Format. -->
> + <field name="F8S2" start="3" end="5" type="fp8_fmt"/>
> + <!-- F8D Format. -->
> + <field name="F8D" start="6" end="8" type="fp8_fmt"/>
> + <!-- OSM. -->
> + <field name="OSM" start="14" end="14" type="osm"/>
> + <!-- OSC. -->
> + <field name="OSC" start="15" end="15" type="osc"/>
> + <!-- LSCALE. -->
> + <field name="LSCALE" start="16" end="22"/>
> + <!-- NSCALE. -->
> + <field name="NSCALE" start="24" end="31" type="int8"/>
> + <!-- LSCALE2. -->
> + <field name="LSCALE2" start="32" end="37"/>
> + </flags>
> + <reg name="fpmr" bitsize="64" type="fpmr_flags"/>
> +</feature>
Otherwise this looks ok with these nits fixed.
Reviewed-By: Luis Machado <luis.machado.foss@gmail.com>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
2025-10-07 12:31 [PATCH v2 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
2025-10-07 12:31 ` [PATCH v2 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
@ 2025-10-07 12:31 ` Ezra.Sitorus
2025-10-11 11:50 ` Luis
2025-10-07 12:31 ` [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
` (3 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Ezra.Sitorus @ 2025-10-07 12:31 UTC (permalink / raw)
To: gdb-patches; +Cc: luis.machado.foss, thiago.bauermann, Ezra Sitorus
From: Ezra Sitorus <ezra.sitorus@arm.com>
Support FPMR in gdbserver.
---
Changes from v1->v2:
* Updated comments
* Use HWCAP2_FPMR in aarch64_target::low_arch_setup
Ezra
gdbserver/linux-aarch64-low.cc | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 9d3ac803e7b..73db8f52ed5 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -248,6 +248,26 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
supply_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr);
}
+/* Fill BUF with the FPMR register from the regcache. */
+
+static void
+aarch64_fill_fpmr_regset (struct regcache *regcache, void *buf)
+{
+ uint64_t *fpmr = (uint64_t *) buf;
+ int fpmr_regnum = find_regno (regcache->tdesc, "fpmr");
+ collect_register (regcache, fpmr_regnum, fpmr);
+}
+
+/* Store the FPMR register to regcache. */
+
+static void
+aarch64_store_fpmr_regset (struct regcache *regcache, const void *buf)
+{
+ uint64_t *fpmr = (uint64_t *) buf;
+ int fpmr_regnum = find_regno (regcache->tdesc, "fpmr");
+ supply_register (regcache, fpmr_regnum, fpmr);
+}
+
/* Store the pauth registers to regcache. */
static void
@@ -879,6 +899,10 @@ static struct regset_info aarch64_regsets[] =
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TAGGED_ADDR_CTRL,
0, OPTIONAL_REGS,
aarch64_fill_mteregset, aarch64_store_mteregset },
+ /* Floating Point Mode Register (FPMR). */
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_FPMR,
+ 0, OPTIONAL_REGS,
+ aarch64_fill_fpmr_regset, aarch64_store_fpmr_regset },
/* TLS register. */
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
0, OPTIONAL_REGS,
@@ -954,6 +978,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
if (features.gcs_linux)
regset->size = sizeof (user_gcs);
break;
+ case NT_ARM_FPMR:
+ if (features.fpmr)
+ regset->size = sizeof (uint64_t);
+ break;
default:
gdb_assert_not_reached ("Unknown register set found.");
}
@@ -986,6 +1014,7 @@ aarch64_target::low_arch_setup ()
features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
features.tls = aarch64_tls_register_count (tid);
features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) & HWCAP_GCS;
+ features.fpmr = linux_get_hwcap2 (pid, 8) & HWCAP2_FPMR;
/* Scalable Matrix Extension feature and size check. */
if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
--
2.45.2
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
2025-10-07 12:31 ` [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
@ 2025-10-11 11:50 ` Luis
2025-10-13 13:40 ` Richard Earnshaw
0 siblings, 1 reply; 16+ messages in thread
From: Luis @ 2025-10-11 11:50 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Support FPMR in gdbserver.
Nit. Make it "Add support for FPMR register set in gdbserver."
It is a bit more descriptive.
> ---
> Changes from v1->v2:
> * Updated comments
> * Use HWCAP2_FPMR in aarch64_target::low_arch_setup
>
> Ezra
>
> gdbserver/linux-aarch64-low.cc | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index 9d3ac803e7b..73db8f52ed5 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -248,6 +248,26 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
> supply_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr);
> }
>
> +/* Fill BUF with the FPMR register from the regcache. */
> +
> +static void
> +aarch64_fill_fpmr_regset (struct regcache *regcache, void *buf)
> +{
> + uint64_t *fpmr = (uint64_t *) buf;
> + int fpmr_regnum = find_regno (regcache->tdesc, "fpmr");
> + collect_register (regcache, fpmr_regnum, fpmr);
> +}
> +
> +/* Store the FPMR register to regcache. */
> +
> +static void
> +aarch64_store_fpmr_regset (struct regcache *regcache, const void *buf)
> +{
> + uint64_t *fpmr = (uint64_t *) buf;
> + int fpmr_regnum = find_regno (regcache->tdesc, "fpmr");
> + supply_register (regcache, fpmr_regnum, fpmr);
> +}
> +
> /* Store the pauth registers to regcache. */
>
> static void
> @@ -879,6 +899,10 @@ static struct regset_info aarch64_regsets[] =
> { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TAGGED_ADDR_CTRL,
> 0, OPTIONAL_REGS,
> aarch64_fill_mteregset, aarch64_store_mteregset },
> + /* Floating Point Mode Register (FPMR). */
> + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_FPMR,
> + 0, OPTIONAL_REGS,
> + aarch64_fill_fpmr_regset, aarch64_store_fpmr_regset },
> /* TLS register. */
> { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
> 0, OPTIONAL_REGS,
> @@ -954,6 +978,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
> if (features.gcs_linux)
> regset->size = sizeof (user_gcs);
> break;
> + case NT_ARM_FPMR:
> + if (features.fpmr)
> + regset->size = sizeof (uint64_t);
> + break;
> default:
> gdb_assert_not_reached ("Unknown register set found.");
> }
> @@ -986,6 +1014,7 @@ aarch64_target::low_arch_setup ()
> features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
> features.tls = aarch64_tls_register_count (tid);
> features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) & HWCAP_GCS;
> + features.fpmr = linux_get_hwcap2 (pid, 8) & HWCAP2_FPMR;
>
> /* Scalable Matrix Extension feature and size check. */
> if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
This one looks OK and should be fine to push once we have the rest of
the series OK-ed
Approved-By: Luis Machado <luis.machado.foss@gmail.com>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
2025-10-11 11:50 ` Luis
@ 2025-10-13 13:40 ` Richard Earnshaw
2025-10-13 14:53 ` Ezra Sitorus
0 siblings, 1 reply; 16+ messages in thread
From: Richard Earnshaw @ 2025-10-13 13:40 UTC (permalink / raw)
To: Luis, Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 11/10/2025 12:50, Luis wrote:
> On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
>> From: Ezra Sitorus <ezra.sitorus@arm.com>
>>
>> Support FPMR in gdbserver.
>
> Nit. Make it "Add support for FPMR register set in gdbserver."
>
> It is a bit more descriptive.
But grammatically wrong, since FPMR is short for Floating Point Mode
Register. So then you'd have:
Add support for the floating point mode register register set in
gdbserver!!!!
R.
>
>> ---
>> Changes from v1->v2:
>> * Updated comments
>> * Use HWCAP2_FPMR in aarch64_target::low_arch_setup
>>
>> Ezra
>>
>> gdbserver/linux-aarch64-low.cc | 29 +++++++++++++++++++++++++++++
>> 1 file changed, 29 insertions(+)
>>
>> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-
>> low.cc
>> index 9d3ac803e7b..73db8f52ed5 100644
>> --- a/gdbserver/linux-aarch64-low.cc
>> +++ b/gdbserver/linux-aarch64-low.cc
>> @@ -248,6 +248,26 @@ aarch64_store_fpregset (struct regcache
>> *regcache, const void *buf)
>> supply_register (regcache, AARCH64_FPCR_REGNUM, ®set->fpcr);
>> }
>> +/* Fill BUF with the FPMR register from the regcache. */
>> +
>> +static void
>> +aarch64_fill_fpmr_regset (struct regcache *regcache, void *buf)
>> +{
>> + uint64_t *fpmr = (uint64_t *) buf;
>> + int fpmr_regnum = find_regno (regcache->tdesc, "fpmr");
>> + collect_register (regcache, fpmr_regnum, fpmr);
>> +}
>> +
>> +/* Store the FPMR register to regcache. */
>> +
>> +static void
>> +aarch64_store_fpmr_regset (struct regcache *regcache, const void *buf)
>> +{
>> + uint64_t *fpmr = (uint64_t *) buf;
>> + int fpmr_regnum = find_regno (regcache->tdesc, "fpmr");
>> + supply_register (regcache, fpmr_regnum, fpmr);
>> +}
>> +
>> /* Store the pauth registers to regcache. */
>> static void
>> @@ -879,6 +899,10 @@ static struct regset_info aarch64_regsets[] =
>> { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TAGGED_ADDR_CTRL,
>> 0, OPTIONAL_REGS,
>> aarch64_fill_mteregset, aarch64_store_mteregset },
>> + /* Floating Point Mode Register (FPMR). */
>> + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_FPMR,
>> + 0, OPTIONAL_REGS,
>> + aarch64_fill_fpmr_regset, aarch64_store_fpmr_regset },
>> /* TLS register. */
>> { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
>> 0, OPTIONAL_REGS,
>> @@ -954,6 +978,10 @@ aarch64_adjust_register_sets (const struct
>> aarch64_features &features)
>> if (features.gcs_linux)
>> regset->size = sizeof (user_gcs);
>> break;
>> + case NT_ARM_FPMR:
>> + if (features.fpmr)
>> + regset->size = sizeof (uint64_t);
>> + break;
>> default:
>> gdb_assert_not_reached ("Unknown register set found.");
>> }
>> @@ -986,6 +1014,7 @@ aarch64_target::low_arch_setup ()
>> features.mte = linux_get_hwcap2 (pid, 8) & HWCAP2_MTE;
>> features.tls = aarch64_tls_register_count (tid);
>> features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) &
>> HWCAP_GCS;
>> + features.fpmr = linux_get_hwcap2 (pid, 8) & HWCAP2_FPMR;
>> /* Scalable Matrix Extension feature and size check. */
>> if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
>
> This one looks OK and should be fine to push once we have the rest of
> the series OK-ed
>
> Approved-By: Luis Machado <luis.machado.foss@gmail.com>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
2025-10-13 13:40 ` Richard Earnshaw
@ 2025-10-13 14:53 ` Ezra Sitorus
2025-10-16 22:01 ` Luis
0 siblings, 1 reply; 16+ messages in thread
From: Ezra Sitorus @ 2025-10-13 14:53 UTC (permalink / raw)
To: Richard Earnshaw; +Cc: Luis, gdb-patches, thiago.bauermann
On Mon, Oct 13, 2025 at 02:40:07PM +0100, Richard Earnshaw wrote:
> On 11/10/2025 12:50, Luis wrote:
> > On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> > > From: Ezra Sitorus <ezra.sitorus@arm.com>
> > >
> > > Support FPMR in gdbserver.
> >
> > Nit. Make it "Add support for FPMR register set in gdbserver."
> >
> > It is a bit more descriptive.
>
> But grammatically wrong, since FPMR is short for Floating Point Mode
> Register. So then you'd have:
>
> Add support for the floating point mode register register set in
> gdbserver!!!!
>
> R.
>
> >
I agree with Richard that it should just be FPMR but I think FPMR register
set makes sense too. Linux kernel has REGSET_FPMR, as well as REGSET_GPR
and REGSET_FPR. Maybe you're meant to think something along the lines of a
'register set called FPMR, which only has the FPMR'?
Which means something like this:
> > > +/* Fill BUF with the FPMR register from the regcache.� */
> > > +
> > > +static void
> > > +aarch64_fill_fpmr_regset (struct regcache *regcache, void *buf)
should just be:
Fill BUF with the FPMR from the regcache.
but this works too:
Fill BUF with the FPMR register set from the regcache.
Ezra
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
2025-10-13 14:53 ` Ezra Sitorus
@ 2025-10-16 22:01 ` Luis
0 siblings, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-16 22:01 UTC (permalink / raw)
To: Ezra Sitorus; +Cc: Richard Earnshaw, gdb-patches, thiago.bauermann
[-- Attachment #1: Type: text/plain, Size: 1746 bytes --]
On Mon, Oct 13, 2025, 15:53 Ezra Sitorus <ezra.sitorus@arm.com> wrote:
> On Mon, Oct 13, 2025 at 02:40:07PM +0100, Richard Earnshaw wrote:
> > On 11/10/2025 12:50, Luis wrote:
> > > On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> > > > From: Ezra Sitorus <ezra.sitorus@arm.com>
> > > >
> > > > Support FPMR in gdbserver.
> > >
> > > Nit. Make it "Add support for FPMR register set in gdbserver."
> > >
> > > It is a bit more descriptive.
> >
> > But grammatically wrong, since FPMR is short for Floating Point Mode
> > Register. So then you'd have:
> >
> > Add support for the floating point mode register register set in
> > gdbserver!!!!
> >
> > R.
> >
> > >
>
> I agree with Richard that it should just be FPMR but I think FPMR register
> set makes sense too. Linux kernel has REGSET_FPMR, as well as REGSET_GPR
> and REGSET_FPR. Maybe you're meant to think something along the lines of a
> 'register set called FPMR, which only has the FPMR'?
>
I meant FPMR the register set exposed by the Linux Kernel via ptrace.
That's what these changes are dealing with.
But either way is fine by me. You could use:
"Add support for FPMR in gdbserver."
> Which means something like this:
>
> > > > +/* Fill BUF with the FPMR register from the regcache.� */
> > > > +
> > > > +static void
> > > > +aarch64_fill_fpmr_regset (struct regcache *regcache, void *buf)
>
> should just be:
>
> Fill BUF with the FPMR from the regcache.
>
> but this works too:
>
> Fill BUF with the FPMR register set from the regcache.
>
Technically it is the register set we're dealing with, but it has a single
register. Again, as long as it is clear I'm fine either way. It is a minor
detail.
> Ezra
>
[-- Attachment #2: Type: text/html, Size: 3065 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr
2025-10-07 12:31 [PATCH v2 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
2025-10-07 12:31 ` [PATCH v2 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
2025-10-07 12:31 ` [PATCH v2 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
@ 2025-10-07 12:31 ` Ezra.Sitorus
2025-10-11 11:57 ` Luis
2025-10-11 12:15 ` Luis
2025-10-07 12:31 ` [PATCH v2 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
` (2 subsequent siblings)
5 siblings, 2 replies; 16+ messages in thread
From: Ezra.Sitorus @ 2025-10-07 12:31 UTC (permalink / raw)
To: gdb-patches; +Cc: luis.machado.foss, thiago.bauermann, Ezra Sitorus
From: Ezra Sitorus <ezra.sitorus@arm.com>
Add support for FPMR in signal frames and restore contents of FPMR.
---
Changes from v1->v2:
* Addressed comments/whitespace/formatting issues
Ezra
gdb/aarch64-linux-tdep.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 10b44d978af..e905be40a8d 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -167,6 +167,7 @@
#define AARCH64_TPIDR2_MAGIC 0x54504902
#define AARCH64_ZT_MAGIC 0x5a544e01
#define AARCH64_GCS_MAGIC 0x47435300
+#define AARCH64_FPMR_MAGIC 0x46504d52
/* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */
#define AARCH64_EXTRA_DATAP_OFFSET 8
@@ -213,6 +214,9 @@
/* features_enabled value offset in the GCS signal frame context. */
#define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16
+/* FPMR constants. */
+#define AARCH64_FPMR_OFFSET 8
+
/* Holds information about the signal frame. */
struct aarch64_linux_sigframe
{
@@ -260,6 +264,12 @@ struct aarch64_linux_sigframe
uint64_t gcspr;
/* Flags indicating which GCS features are enabled for the thread. */
uint64_t gcs_features_enabled;
+
+ /* True if we have an FPMR entry in the signal context, false otherwise. */
+ bool fpmr_available = false;
+ /* The Floating Point Mode Register. */
+ CORE_ADDR fpmr = 0;
+
};
/* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
@@ -576,6 +586,22 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
section += size;
break;
}
+ case AARCH64_FPMR_MAGIC:
+ {
+ gdb_byte buf[8];
+ if (target_read_memory (section + AARCH64_FPMR_OFFSET,
+ buf, 8) != 0)
+ {
+ warning (_("Failed to read the FPMR section address from the"
+ " signal frame context."));
+ section += size;
+ break;
+ }
+ signal_frame.fpmr = extract_unsigned_integer (buf, 8, byte_order);
+ signal_frame.fpmr_available = true;
+ section += size;
+ break;
+ }
case AARCH64_EXTRA_MAGIC:
{
/* Extra is always the last valid section in reserved and points to
@@ -739,6 +765,13 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
}
}
+ /* Handle FPMR. */
+ if (tdep->has_fpmr () && signal_frame.fpmr_available != 0)
+ {
+ trad_frame_set_reg_value (this_cache, tdep->fpmr_regnum,
+ signal_frame.fpmr);
+ }
+
/* Restore the tpidr2 register, if the target supports it and if there is
an entry for it. */
if (signal_frame.tpidr2_section != 0 && tdep->has_tls ()
@@ -791,6 +824,7 @@ aarch64_linux_sigframe_prev_arch (const frame_info_ptr &this_frame,
aarch64_features features = aarch64_features_from_target_desc (tdesc);
features.vq = sve_vq_from_vl (signal_frame.vl);
features.svq = (uint8_t) sve_vq_from_vl (signal_frame.svl);
+ features.fpmr = signal_frame.fpmr_available;
struct gdbarch_info info;
info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);
--
2.45.2
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr
2025-10-07 12:31 ` [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
@ 2025-10-11 11:57 ` Luis
2025-10-11 12:15 ` Luis
1 sibling, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-11 11:57 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Add support for FPMR in signal frames and restore contents of FPMR.
> ---
> Changes from v1->v2:
> * Addressed comments/whitespace/formatting issues
>
> Ezra
>
> gdb/aarch64-linux-tdep.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 10b44d978af..e905be40a8d 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -167,6 +167,7 @@
> #define AARCH64_TPIDR2_MAGIC 0x54504902
> #define AARCH64_ZT_MAGIC 0x5a544e01
> #define AARCH64_GCS_MAGIC 0x47435300
> +#define AARCH64_FPMR_MAGIC 0x46504d52
>
> /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */
> #define AARCH64_EXTRA_DATAP_OFFSET 8
> @@ -213,6 +214,9 @@
> /* features_enabled value offset in the GCS signal frame context. */
> #define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16
>
> +/* FPMR constants. */
Formatting. Two spaces after period.
> +#define AARCH64_FPMR_OFFSET 8
> +
> /* Holds information about the signal frame. */
> struct aarch64_linux_sigframe
> {
> @@ -260,6 +264,12 @@ struct aarch64_linux_sigframe
> uint64_t gcspr;
> /* Flags indicating which GCS features are enabled for the thread. */
> uint64_t gcs_features_enabled;
> +
> + /* True if we have an FPMR entry in the signal context, false otherwise. */
> + bool fpmr_available = false;
> + /* The Floating Point Mode Register. */
> + CORE_ADDR fpmr = 0;
> +
> };
>
> /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
> @@ -576,6 +586,22 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
> section += size;
> break;
> }
> + case AARCH64_FPMR_MAGIC:
> + {
> + gdb_byte buf[8];
> + if (target_read_memory (section + AARCH64_FPMR_OFFSET,
> + buf, 8) != 0)
> + {
> + warning (_("Failed to read the FPMR section address from the"
> + " signal frame context."));
> + section += size;
> + break;
> + }
> + signal_frame.fpmr = extract_unsigned_integer (buf, 8, byte_order);
> + signal_frame.fpmr_available = true;
> + section += size;
> + break;
> + }
> case AARCH64_EXTRA_MAGIC:
> {
> /* Extra is always the last valid section in reserved and points to
> @@ -739,6 +765,13 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
> }
> }
>
> + /* Handle FPMR. */
> + if (tdep->has_fpmr () && signal_frame.fpmr_available != 0)
> + {
> + trad_frame_set_reg_value (this_cache, tdep->fpmr_regnum,
> + signal_frame.fpmr);
> + }
> +
> /* Restore the tpidr2 register, if the target supports it and if there is
> an entry for it. */
> if (signal_frame.tpidr2_section != 0 && tdep->has_tls ()
> @@ -791,6 +824,7 @@ aarch64_linux_sigframe_prev_arch (const frame_info_ptr &this_frame,
> aarch64_features features = aarch64_features_from_target_desc (tdesc);
> features.vq = sve_vq_from_vl (signal_frame.vl);
> features.svq = (uint8_t) sve_vq_from_vl (signal_frame.svl);
> + features.fpmr = signal_frame.fpmr_available;
>
> struct gdbarch_info info;
> info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);
Otherwise looks good to me with the nit fixed.
Approved-By: Luis Machado <luis.machado.foss@gmail.com>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr
2025-10-07 12:31 ` [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
2025-10-11 11:57 ` Luis
@ 2025-10-11 12:15 ` Luis
1 sibling, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-11 12:15 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Add support for FPMR in signal frames and restore contents of FPMR.
> ---
> Changes from v1->v2:
> * Addressed comments/whitespace/formatting issues
>
> Ezra
>
> gdb/aarch64-linux-tdep.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 10b44d978af..e905be40a8d 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -167,6 +167,7 @@
> #define AARCH64_TPIDR2_MAGIC 0x54504902
> #define AARCH64_ZT_MAGIC 0x5a544e01
> #define AARCH64_GCS_MAGIC 0x47435300
> +#define AARCH64_FPMR_MAGIC 0x46504d52
>
> /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */
> #define AARCH64_EXTRA_DATAP_OFFSET 8
> @@ -213,6 +214,9 @@
> /* features_enabled value offset in the GCS signal frame context. */
> #define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16
>
> +/* FPMR constants. */
> +#define AARCH64_FPMR_OFFSET 8
> +
> /* Holds information about the signal frame. */
> struct aarch64_linux_sigframe
> {
> @@ -260,6 +264,12 @@ struct aarch64_linux_sigframe
> uint64_t gcspr;
> /* Flags indicating which GCS features are enabled for the thread. */
> uint64_t gcs_features_enabled;
> +
> + /* True if we have an FPMR entry in the signal context, false otherwise. */
> + bool fpmr_available = false;
> + /* The Floating Point Mode Register. */
> + CORE_ADDR fpmr = 0;
> +
> };
>
> /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
> @@ -576,6 +586,22 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
> section += size;
> break;
> }
> + case AARCH64_FPMR_MAGIC:
> + {
> + gdb_byte buf[8];
> + if (target_read_memory (section + AARCH64_FPMR_OFFSET,
> + buf, 8) != 0)
> + {
> + warning (_("Failed to read the FPMR section address from the"
> + " signal frame context."));
> + section += size;
> + break;
> + }
> + signal_frame.fpmr = extract_unsigned_integer (buf, 8, byte_order);
> + signal_frame.fpmr_available = true;
> + section += size;
> + break;
> + }
> case AARCH64_EXTRA_MAGIC:
> {
> /* Extra is always the last valid section in reserved and points to
> @@ -739,6 +765,13 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
> }
> }
>
> + /* Handle FPMR. */
Sorry, missed this one. The above indentation is off. Please fix it.
> + if (tdep->has_fpmr () && signal_frame.fpmr_available != 0)
> + {
> + trad_frame_set_reg_value (this_cache, tdep->fpmr_regnum,
> + signal_frame.fpmr);
> + }
> +
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 4/5] gdb/aarch64: core file support for FPMR
2025-10-07 12:31 [PATCH v2 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
` (2 preceding siblings ...)
2025-10-07 12:31 ` [PATCH v2 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
@ 2025-10-07 12:31 ` Ezra.Sitorus
2025-10-11 12:03 ` Luis
2025-10-07 12:31 ` [PATCH v2 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
2025-10-11 12:05 ` [PATCH v2 0/5] gdb/aarch64: Support for FPMR Luis
5 siblings, 1 reply; 16+ messages in thread
From: Ezra.Sitorus @ 2025-10-07 12:31 UTC (permalink / raw)
To: gdb-patches; +Cc: luis.machado.foss, thiago.bauermann, Ezra Sitorus
From: Ezra Sitorus <ezra.sitorus@arm.com>
Add support for FPMR dumps/reads for core files.
---
Changes from v1->v2:
* Addressed comments/whitespace/formatting issues.
Ezra
gdb/aarch64-linux-tdep.c | 66 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index e905be40a8d..5b4bc56210f 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1518,6 +1518,55 @@ aarch64_linux_collect_zt_regset (const struct regset *regset,
AARCH64_SME2_ZT0_SIZE);
}
+/* Supply register REGNUM from BUF to REGCACHE, using the register map
+ in REGSET. If REGNUM is -1, do this for all registers in REGSET.
+ If BUF is NULL, set the registers to "unavailable" status. */
+
+static void
+aarch64_linux_supply_fpmr_regset (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *buf, size_t size)
+{
+ /* Read the FPMR note from a core file into the register buffer. */
+
+ /* Make sure the buffer contains at least the expected amount of data we are
+ supposed to get. */
+ gdb_assert (size >= sizeof (uint64_t));
+
+ /* Handle an empty buffer. */
+ if (buf == nullptr)
+ return regcache->supply_regset (regset, regnum, nullptr, size);
+
+ aarch64_gdbarch_tdep *tdep
+ = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+ /* Supply the FPMR register contents. */
+ regcache->raw_supply (tdep->fpmr_regnum, buf);
+}
+
+/* Collect register REGNUM from REGCACHE to BUF, using the register
+ map in REGSET. If REGNUM is -1, do this for all registers in
+ REGSET. */
+
+static void
+aarch64_linux_collect_fpmr_regset (const struct regset *regset,
+ const struct regcache *regcache, int regnum,
+ void *buf, size_t size)
+{
+ /* Read the FPMR contents from the register buffer into the core
+ file section. */
+
+ /* Make sure the buffer can hold the data we need to return. */
+ gdb_assert (size >= sizeof (uint64_t));
+ gdb_assert (buf != nullptr);
+
+ aarch64_gdbarch_tdep *tdep
+ = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+ /* Dump the register cache contents for the FPMR to the buffer. */
+ regcache->collect_regset (regset, tdep->fpmr_regnum, buf, sizeof (uint64_t));
+}
+
/* Implement the "iterate_over_regset_sections" gdbarch method. */
static void
@@ -1635,6 +1684,23 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
}
}
+ if (tdep->has_fpmr ())
+ {
+ const struct regcache_map_entry fpmr_regmap[] =
+ {
+ { 1, tdep->fpmr_regnum, sizeof (uint64_t) }
+ };
+
+ const struct regset aarch64_linux_fpmr_regset =
+ {
+ fpmr_regmap, aarch64_linux_supply_fpmr_regset,
+ aarch64_linux_collect_fpmr_regset
+ };
+
+ cb (".reg-aarch-fpmr", sizeof (uint64_t), sizeof (uint64_t),
+ &aarch64_linux_fpmr_regset, "FPMR", cb_data);
+ }
+
if (tdep->has_pauth ())
{
/* Create this on the fly in order to handle the variable location. */
--
2.45.2
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 4/5] gdb/aarch64: core file support for FPMR
2025-10-07 12:31 ` [PATCH v2 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
@ 2025-10-11 12:03 ` Luis
0 siblings, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-11 12:03 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Add support for FPMR dumps/reads for core files.
> ---
> Changes from v1->v2:
> * Addressed comments/whitespace/formatting issues.
>
> Ezra
>
> gdb/aarch64-linux-tdep.c | 66 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 66 insertions(+)
>
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index e905be40a8d..5b4bc56210f 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1518,6 +1518,55 @@ aarch64_linux_collect_zt_regset (const struct regset *regset,
> AARCH64_SME2_ZT0_SIZE);
> }
>
> +/* Supply register REGNUM from BUF to REGCACHE, using the register map
> + in REGSET. If REGNUM is -1, do this for all registers in REGSET.
> + If BUF is NULL, set the registers to "unavailable" status. */
> +
> +static void
> +aarch64_linux_supply_fpmr_regset (const struct regset *regset,
> + struct regcache *regcache, int regnum,
> + const void *buf, size_t size)
> +{
> + /* Read the FPMR note from a core file into the register buffer. */
> +
> + /* Make sure the buffer contains at least the expected amount of data we are
> + supposed to get. */
> + gdb_assert (size >= sizeof (uint64_t));
> +
> + /* Handle an empty buffer. */
> + if (buf == nullptr)
> + return regcache->supply_regset (regset, regnum, nullptr, size);
> +
> + aarch64_gdbarch_tdep *tdep
> + = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> +
> + /* Supply the FPMR register contents. */
> + regcache->raw_supply (tdep->fpmr_regnum, buf);
> +}
> +
> +/* Collect register REGNUM from REGCACHE to BUF, using the register
> + map in REGSET. If REGNUM is -1, do this for all registers in
> + REGSET. */
> +
> +static void
> +aarch64_linux_collect_fpmr_regset (const struct regset *regset,
> + const struct regcache *regcache, int regnum,
> + void *buf, size_t size)
> +{
> + /* Read the FPMR contents from the register buffer into the core
> + file section. */
> +
> + /* Make sure the buffer can hold the data we need to return. */
> + gdb_assert (size >= sizeof (uint64_t));
> + gdb_assert (buf != nullptr);
> +
> + aarch64_gdbarch_tdep *tdep
> + = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> +
> + /* Dump the register cache contents for the FPMR to the buffer. */
> + regcache->collect_regset (regset, tdep->fpmr_regnum, buf, sizeof (uint64_t));
> +}
> +
> /* Implement the "iterate_over_regset_sections" gdbarch method. */
>
> static void
> @@ -1635,6 +1684,23 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
> }
> }
>
> + if (tdep->has_fpmr ())
> + {
> + const struct regcache_map_entry fpmr_regmap[] =
> + {
> + { 1, tdep->fpmr_regnum, sizeof (uint64_t) }
> + };
> +
> + const struct regset aarch64_linux_fpmr_regset =
> + {
> + fpmr_regmap, aarch64_linux_supply_fpmr_regset,
> + aarch64_linux_collect_fpmr_regset
> + };
> +
> + cb (".reg-aarch-fpmr", sizeof (uint64_t), sizeof (uint64_t),
> + &aarch64_linux_fpmr_regset, "FPMR", cb_data);
> + }
> +
> if (tdep->has_pauth ())
> {
> /* Create this on the fly in order to handle the variable location. */
Given the FPMR register set only has a single register, do you really
need custom supply/collect functions for it? See the example of the MTE
register set, where we just provide the register set but use the generic
collect/supply functions.
I think we could do the same for FPMR here, unless there is a reason for
the custom functions, which I'm not seeing at the moment.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 5/5] gdb/aarch64: Tests for fpmr
2025-10-07 12:31 [PATCH v2 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
` (3 preceding siblings ...)
2025-10-07 12:31 ` [PATCH v2 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
@ 2025-10-07 12:31 ` Ezra.Sitorus
2025-10-11 12:53 ` Luis
2025-10-11 12:05 ` [PATCH v2 0/5] gdb/aarch64: Support for FPMR Luis
5 siblings, 1 reply; 16+ messages in thread
From: Ezra.Sitorus @ 2025-10-07 12:31 UTC (permalink / raw)
To: gdb-patches; +Cc: luis.machado.foss, thiago.bauermann, Ezra Sitorus
From: Ezra Sitorus <ezra.sitorus@arm.com>
Add tests for FPMR support in gdb/gdbserver. These tests check
availability of FPMR, reading/writing to FPMR, core file generation and
preservation under sighandler frame unwinding.
A run of the full gdb testsuite has been done on aarch64-none-linux-gnu
without FPMR support. I have run the gdb.arch tests on Shrinkwrap with
FPMR support.
---
Changes from v1->v2:
* Removed fpmr modification functions to make the tests easier to
follow.
* Test writing to fpmr in aarch64-fpmr.exp from outside the inferior
program.
* Rewrite allow_aarch64_fpmr_tests to follow allow_aarch64_sve_tests.
Ezra
gdb/testsuite/gdb.arch/aarch64-fpmr-core.c | 40 ++++++
gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp | 97 +++++++++++++++
.../gdb.arch/aarch64-fpmr-sighandler.c | 55 ++++++++
.../gdb.arch/aarch64-fpmr-sighandler.exp | 77 ++++++++++++
gdb/testsuite/gdb.arch/aarch64-fpmr.c | 117 ++++++++++++++++++
gdb/testsuite/gdb.arch/aarch64-fpmr.exp | 72 +++++++++++
gdb/testsuite/lib/gdb.exp | 66 ++++++++++
7 files changed, 524 insertions(+)
create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr.c
create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr.exp
diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
new file mode 100644
index 00000000000..785fbd42d5c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
@@ -0,0 +1,40 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2008-2025 Free Software Foundation, Inc.
+
+ 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+
+uint64_t crash_address = 0;
+
+void
+set_fpmr (uint64_t value)
+{
+ register uint64_t x0_val asm ("x0") = value;
+ /* msr fpmr, x0 */
+ __asm__ volatile (".inst 0xd51b4440" : : );
+}
+
+int
+main (void)
+{
+ set_fpmr (0x3fff7fc049);
+
+ /* Check FPMR */
+
+ *((uint64_t *) crash_address) = 0xDEAD; /* crash point */
+
+ return 1;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
new file mode 100644
index 00000000000..6f8ee996d27
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
@@ -0,0 +1,97 @@
+# Copyright (C) 2018-2025 Free Software Foundation, Inc.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+# This file is part of the gdb testsuite.
+
+# Test generating and reading a core file with FPMR.
+
+proc check_fpmr_core_file { core_filename } {
+ # Load the core file.
+ if [gdb_test "core $core_filename" \
+ [multi_line \
+ "Core was generated by .*" \
+ "Program terminated with signal SIGSEGV, Segmentation fault\\." \
+ "#0 ${::hex} in main \\(.*\\) at .*" \
+ ".* \\*\\(\\(uint64_t \\*\\) crash_address\\) = 0xDEAD.*"] \
+ "load core file"] {
+ untested "failed to generate core file"
+ return -1
+ }
+
+ # Check the value of FPMR in the core file.
+ gdb_test "print/x \$fpmr" " = 0x3fff7fc049" \
+ "fpmr contents from core file"
+}
+
+require is_aarch64_target
+require allow_aarch64_fpmr_tests
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+set binfile [standard_output_file ${testfile}]
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+set crash_breakpoint "crash point"
+gdb_breakpoint [gdb_get_line_number $crash_breakpoint]
+gdb_continue_to_breakpoint $crash_breakpoint
+
+gdb_test "print/x \$fpmr" " = 0x3fff7fc049" \
+ "fpmr contents from core file"
+
+gdb_test "continue" \
+[multi_line \
+ "Program received signal SIGSEGV, Segmentation fault\\." \
+ "${::hex} in main \\(\\).* at .*" \
+ ".* \\*\\(\\(uint64_t \\*\\) crash_address\\) = 0xDEAD.*"] \
+ "run to crash"
+
+# Generate the gcore core file.
+set gcore_filename [standard_output_file "${testfile}.gcore"]
+set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"]
+
+# Generate a native core file.
+set core_filename [core_find ${binfile}]
+set core_generated [expr {$core_filename != ""}]
+
+# At this point we have a couple core files, the gcore one generated by GDB
+# and the native one generated by the Linux Kernel. Make sure GDB can read
+# both correctly.
+
+if {$gcore_generated} {
+ clean_restart
+ gdb_load ${binfile}
+ with_test_prefix "gcore corefile" {
+ check_fpmr_core_file $gcore_filename
+ }
+} else {
+ fail "gcore corefile not generated"
+}
+
+if {$core_generated} {
+ clean_restart
+ gdb_load ${binfile}
+ with_test_prefix "native corefile" {
+ check_fpmr_core_file $core_filename
+ }
+} else {
+ untested "native corefile not generated"
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
new file mode 100644
index 00000000000..bbdfbb0597c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
@@ -0,0 +1,55 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2008-2025 Free Software Foundation, Inc.
+
+ 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void
+set_fpmr (uint64_t value)
+{
+ register uint64_t x0_val asm ("x0") = value;
+ /* msr fpmr, x0 */
+ __asm__ volatile (".inst 0xd51b4440" : : );
+}
+
+void
+handler (int sig)
+{
+ set_fpmr (0xff008041);
+ exit(0);
+}
+
+int
+main ()
+{
+ /* Ensure all the signals aren't blocked. */
+ sigset_t newset;
+ sigemptyset (&newset);
+ sigprocmask (SIG_SETMASK, &newset, NULL);
+
+ signal (SIGILL, handler);
+
+ set_fpmr (0x3fff7fc049);
+
+ /* 0x06000000 : Cause an illegal instruction. Value undefined as per ARM
+ Architecture Reference Manual ARMv8, Section C4.1. */
+ __asm __volatile (".inst 0x06000000");
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
new file mode 100644
index 00000000000..a776976eb7d
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
@@ -0,0 +1,77 @@
+# Copyright 2018-2025 Free Software Foundation, Inc.
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+# This file is part of the gdb testsuite.
+#
+# Test FPMR register set is properly preserved when unwiding sighandler frames.
+
+require is_aarch64_target
+require allow_aarch64_fpmr_tests
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+set reg_main_value "0x3fff7fc049"
+set reg_handler_value "0xff008041"
+
+proc check_fpmr {value} {
+ gdb_test "print /x \$fpmr" \
+ ".* = {?$value}?" \
+ "check register \$fpmr has value $value"
+}
+
+# Run until end of signal handler
+
+gdb_test "continue" \
+ "Continuing.*Program received signal SIGILL.*" \
+ "continue until signal"
+
+gdb_breakpoint [gdb_get_line_number "exit(0)"]
+gdb_continue_to_breakpoint "exit" ".*exit.*"
+
+set handlerframe [get_current_frame_number]
+set mainframe [expr $handlerframe + 2]
+
+# Check register values
+
+with_test_prefix "handler frame 1st" {
+ check_fpmr $reg_handler_value
+}
+
+# Switch to the frame for main(), and check register values
+
+gdb_test "frame $mainframe" \
+ "#$mainframe.*main ().*" \
+ "set to main frame"
+
+with_test_prefix "main frame" {
+ check_fpmr $reg_main_value
+}
+
+# Switch back to the signal handler frame, and check register values
+
+gdb_test "frame $handlerframe" \
+ "#$handlerframe.*handler \\\(sig=4\\\).*" \
+ "set to signal handler frame"
+
+with_test_prefix "handler frame 2nd" {
+ check_fpmr $reg_handler_value
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr.c b/gdb/testsuite/gdb.arch/aarch64-fpmr.c
new file mode 100644
index 00000000000..f4bf889c3a8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr.c
@@ -0,0 +1,117 @@
+/* This file is part of GDB, the GNU debugger.
+
+ Copyright 2008-2025 Free Software Foundation, Inc.
+
+ 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+
+enum FPM_FORMAT
+{
+ E5M2,
+ E4M3,
+};
+
+enum FPM_OVERFLOW
+{
+ INFNAN,
+ SATURATE,
+};
+
+void
+set_fpmr (uint64_t value)
+{
+ register uint64_t x0_val asm ("x0") = value;
+ __asm__ volatile (".inst 0xd51b4440" : : );
+}
+
+uint64_t
+modify_src1_fmt (uint64_t fpmr, uint64_t fmt)
+{
+ return (fpmr & ~(0x7)) | (fmt & 0x7);
+}
+
+uint64_t
+modify_src2_fmt (uint64_t fpmr, uint64_t fmt)
+{
+ return (fpmr & ~((0x7) << 3)) | ((fmt & 0x7) << 3);
+}
+
+uint64_t
+modify_dst_fmt (uint64_t fpmr, uint64_t fmt)
+{
+ return (fpmr & ~((0x7) << 6)) | ((fmt & 0x7) << 6);
+}
+
+uint64_t
+modify_osm (uint64_t fpmr, uint64_t overflow)
+{
+ return (fpmr & ~((0x1) << 14)) | ((overflow & 0x1) << 14);
+}
+
+uint64_t
+modify_osc (uint64_t fpmr, uint64_t overflow)
+{
+ return (fpmr & ~((0x1) << 15)) | ((overflow & 0x1) << 15);
+}
+
+uint64_t
+modify_lscale (uint64_t fpmr, uint64_t scale)
+{
+ return (fpmr & ~((0x7f) << 16)) | ((scale & 0x7f) << 16);
+}
+
+uint64_t
+modify_nscale (uint64_t fpmr, uint64_t scale)
+{
+ return (fpmr & ~((0xff) << 24)) | ((scale & 0xff) << 24);
+}
+
+uint64_t
+modify_lscale2 (uint64_t fpmr, uint64_t scale)
+{
+ return (fpmr & ~((uint64_t)(0x3f) << 32)) | ((uint64_t)(scale & 0x3f) << 32);
+}
+
+int
+main (void)
+{
+ uint64_t fpmr = 0;
+
+ fpmr = modify_src1_fmt (fpmr, E4M3);
+ set_fpmr (fpmr); /* MODIFY SRC1 */
+
+ fpmr = modify_src2_fmt (fpmr, E4M3);
+ set_fpmr (fpmr); /* MODIFY SRC2 */
+
+ fpmr = modify_dst_fmt (fpmr, E4M3);
+ set_fpmr (fpmr); /* MODIFY DST */
+
+ fpmr = modify_osm (fpmr, SATURATE);
+ set_fpmr (fpmr); /* MODIFY OSM */
+
+ fpmr = modify_osc (fpmr, SATURATE);
+ set_fpmr (fpmr); /* MODIFY OSC */
+
+ fpmr = modify_lscale (fpmr, -1);
+ set_fpmr (fpmr); /* MODIFY LSCALE */
+
+ fpmr = modify_nscale (fpmr, -1);
+ set_fpmr (fpmr); /* MODIFY NSCALE */
+
+ fpmr = modify_lscale2 (fpmr, -1);
+ set_fpmr (fpmr); /* MODIFY LSCALE2 */
+
+ return 1;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr.exp b/gdb/testsuite/gdb.arch/aarch64-fpmr.exp
new file mode 100644
index 00000000000..947d47e981d
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr.exp
@@ -0,0 +1,72 @@
+# Copyright 2023-2025 Free Software Foundation, Inc.
+
+# 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 <http://www.gnu.org/licenses/>. */
+
+# Exercise reading/writing FPMR when it is present.
+
+require is_aarch64_target
+require allow_aarch64_fpmr_tests
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return -1
+}
+
+if ![runto_main] {
+ untested "could not run to main"
+ return -1
+}
+
+gdb_test_multiple "info register \$fpmr" "Test FPMR SRC1 E5M2" {
+ -re ".*\r\n.*\[ F8S1=E5M2 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+ pass "FPMR SRC1 matches E5M2"
+ }
+}
+
+set breakpoints [list "MODIFY SRC1" "MODIFY SRC2" "MODIFY DST" "MODIFY OSM" "MODIFY OSC" "MODIFY LSCALE" "MODIFY NSCALE" "MODIFY LSCALE2"]
+set reg_values [list \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=0 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=0 \]" \
+ ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=63 \]" \
+]
+set pass_messages [list "FPMR SRC1 matches E4M3" "FPMR SRC2 matches E4M3" "FPMR DST matches E4M3" "FPMR OSM matches MaxNormal" "FPMR OSC matches MaxNormal" "FPMR LSCALE matches" "FPMR NSCALE matches" "FPMR LSCALE2 matches"]
+
+for {set i 0} {$i < 8} {incr i} {
+ set bp [lindex $breakpoints $i]
+ gdb_breakpoint [gdb_get_line_number $bp]
+ gdb_continue_to_breakpoint $bp
+
+ gdb_test_multiple "info register \$fpmr" "" {
+ -re [lindex $reg_values $i] {
+ pass [lindex $pass_messages $i]
+ }
+ }
+}
+
+gdb_test_multiple "set \$fpmr=0x0" "" {
+ -re ".*\r\n.*\[ F8S1=E5M2 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+ pass "Reset FPMR to 0 from GDB"
+ }
+}
+
+gdb_test_multiple "set \$fpmr=0x3f007f4008" "" {
+ -re ".*\r\n.*\[ F8S1=E5M2 F8S2=E4M3 F8D=E5M2 OSM=MaxNormal OSC=Inf/NaN LSCALE=127 NSCALE=0 LSCALE2=63 \]" {
+ pass "Write to FPMR from GDB"
+ }
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 930462f63fa..0d0369511bb 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5201,6 +5201,72 @@ proc aarch64_supports_sme_svl { length } {
return 1
}
+# Run a test on the target to see if it supports AArch64 FPMR hardware.
+# Return 1 if so, 0 if it does not. Note this causes a restart of GDB.
+
+gdb_caching_proc allow_aarch64_fpmr_tests {} {
+ global srcdir subdir gdb_prompt inferior_exited_re
+
+ set me "allow_aarch64_fpmr_tests"
+
+ if { ![is_aarch64_target]} {
+ return 0
+ }
+
+ set compile_flags "{additional_flags=-march=armv8-a}"
+
+ # Compile a test program that writes to FPMR.
+ set src {
+ int main() {
+ asm volatile ("msr x0, fpmr");
+ return 0;
+ }
+ }
+ if {![gdb_simple_compile $me $src executable $compile_flags]} {
+ # Try again, but with a raw hex instruction so we don't rely on
+ # assembler support for FPMR.
+
+ set compile_flags "{additional_flags=-march=armv8-a}"
+
+ # Compile a test program reading FPMR.
+ set src {
+ int main() {
+ asm volatile (".word 0xD51B4440");
+ return 0;
+ }
+ }
+
+ if {![gdb_simple_compile $me $src executable $compile_flags]} {
+ return 0
+ }
+ }
+
+ # Compilation succeeded so now run it via gdb.
+ clean_restart
+ gdb_load $obj
+ gdb_run_cmd
+
+ gdb_expect {
+ -re ".*Illegal instruction.*${gdb_prompt} $" {
+ verbose -log "\n$me fpmr support not detected"
+ set allow_fpmr_tests 0
+ }
+ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+ verbose -log "\n$me: fpmr support detected"
+ set allow_fpmr_tests 1
+ }
+ default {
+ warning "\n$me: default case taken"
+ set allow_fpmr_tests 0
+ }
+ }
+ gdb_exit
+ remote_file build delete $obj
+
+ verbose "$me: returning $allow_fpmr_tests" 2
+ return $allow_fpmr_tests
+}
+
# Run a test on the target to see if it supports AArch64 MOPS (Memory
# Operations) extensions. Return 1 if so, 0 if it does not. Note this
# causes a restart of GDB.
--
2.45.2
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 5/5] gdb/aarch64: Tests for fpmr
2025-10-07 12:31 ` [PATCH v2 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
@ 2025-10-11 12:53 ` Luis
0 siblings, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-11 12:53 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
There seems to be a few whitespace issues with this patch. Please check
them with "git diff --check" or "git show --check" and it should show you.
Also, running tclint on your exp files seems to point out these:
gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp:22:5: expected braced word
or word without substitutions in argument interpreted as expr [command-args]
gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp:48:1: expected braced word
or word without substitutions in argument interpreted as expr [command-args]
gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp:28:1: expected braced
word or word without substitutions in argument interpreted as expr
[command-args]
gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp:51:21: expression
with substitutions should be enclosed by braces [unbraced-expr]
gdb/testsuite/gdb.arch/aarch64-fpmr.exp:26:1: expected braced word or
word without substitutions in argument interpreted as expr [command-args]
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Add tests for FPMR support in gdb/gdbserver. These tests check
> availability of FPMR, reading/writing to FPMR, core file generation and
> preservation under sighandler frame unwinding.
>
> A run of the full gdb testsuite has been done on aarch64-none-linux-gnu
> without FPMR support. I have run the gdb.arch tests on Shrinkwrap with
> FPMR support.
> ---
> Changes from v1->v2:
> * Removed fpmr modification functions to make the tests easier to
> follow.
> * Test writing to fpmr in aarch64-fpmr.exp from outside the inferior
> program.
> * Rewrite allow_aarch64_fpmr_tests to follow allow_aarch64_sve_tests.
>
> Ezra
>
> gdb/testsuite/gdb.arch/aarch64-fpmr-core.c | 40 ++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp | 97 +++++++++++++++
> .../gdb.arch/aarch64-fpmr-sighandler.c | 55 ++++++++
> .../gdb.arch/aarch64-fpmr-sighandler.exp | 77 ++++++++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr.c | 117 ++++++++++++++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr.exp | 72 +++++++++++
> gdb/testsuite/lib/gdb.exp | 66 ++++++++++
> 7 files changed, 524 insertions(+)
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr.exp
>
> diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
> new file mode 100644
> index 00000000000..785fbd42d5c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
> @@ -0,0 +1,40 @@
> +/* This file is part of GDB, the GNU debugger.
> +
> + Copyright 2008-2025 Free Software Foundation, Inc.
> +
> + 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 <http://www.gnu.org/licenses/>. */
> +
> +#include <stdint.h>
> +
> +uint64_t crash_address = 0;
> +
> +void
> +set_fpmr (uint64_t value)
> +{
> + register uint64_t x0_val asm ("x0") = value;
> + /* msr fpmr, x0 */
> + __asm__ volatile (".inst 0xd51b4440" : : );
> +}
> +
> +int
> +main (void)
> +{
> + set_fpmr (0x3fff7fc049);
> +
> + /* Check FPMR */
> +
> + *((uint64_t *) crash_address) = 0xDEAD; /* crash point */
> +
> + return 1;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
> new file mode 100644
> index 00000000000..6f8ee996d27
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
> @@ -0,0 +1,97 @@
> +# Copyright (C) 2018-2025 Free Software Foundation, Inc.
> +#
> +# 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 <http://www.gnu.org/licenses/>.
> +
> +# This file is part of the gdb testsuite.
> +
> +# Test generating and reading a core file with FPMR.
> +
> +proc check_fpmr_core_file { core_filename } {
> + # Load the core file.
> + if [gdb_test "core $core_filename" \
> + [multi_line \
> + "Core was generated by .*" \
> + "Program terminated with signal SIGSEGV, Segmentation fault\\." \
> + "#0 ${::hex} in main \\(.*\\) at .*" \
> + ".* \\*\\(\\(uint64_t \\*\\) crash_address\\) = 0xDEAD.*"] \
> + "load core file"] {
> + untested "failed to generate core file"
> + return -1
> + }
> +
> + # Check the value of FPMR in the core file.
> + gdb_test "print/x \$fpmr" " = 0x3fff7fc049" \
> + "fpmr contents from core file"
> +}
> +
> +require is_aarch64_target
> +require allow_aarch64_fpmr_tests
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> + return -1
> +}
> +
> +set binfile [standard_output_file ${testfile}]
> +
> +if ![runto_main] {
> + untested "could not run to main"
I don´t quite recall if we decided to not issue these untested/fail
messages here. Looking at the overall testsuite, looks like we mostly
just return -1.
> + return -1
> +}
> +
> +set crash_breakpoint "crash point"
> +gdb_breakpoint [gdb_get_line_number $crash_breakpoint]
> +gdb_continue_to_breakpoint $crash_breakpoint
> +
> +gdb_test "print/x \$fpmr" " = 0x3fff7fc049" \
> + "fpmr contents from core file"
> +
> +gdb_test "continue" \
> +[multi_line \
> + "Program received signal SIGSEGV, Segmentation fault\\." \
> + "${::hex} in main \\(\\).* at .*" \
> + ".* \\*\\(\\(uint64_t \\*\\) crash_address\\) = 0xDEAD.*"] \
> + "run to crash"
> +
> +# Generate the gcore core file.
> +set gcore_filename [standard_output_file "${testfile}.gcore"]
> +set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"]
> +
> +# Generate a native core file.
> +set core_filename [core_find ${binfile}]
> +set core_generated [expr {$core_filename != ""}]
> +
> +# At this point we have a couple core files, the gcore one generated by GDB
> +# and the native one generated by the Linux Kernel. Make sure GDB can read
> +# both correctly.
> +
> +if {$gcore_generated} {
> + clean_restart
> + gdb_load ${binfile}
> + with_test_prefix "gcore corefile" {
> + check_fpmr_core_file $gcore_filename
> + }
> +} else {
> + fail "gcore corefile not generated"
> +}
> +
> +if {$core_generated} {
> + clean_restart
> + gdb_load ${binfile}
> + with_test_prefix "native corefile" {
> + check_fpmr_core_file $core_filename
> + }
> +} else {
> + untested "native corefile not generated"
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
> new file mode 100644
> index 00000000000..bbdfbb0597c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
> @@ -0,0 +1,55 @@
> +/* This file is part of GDB, the GNU debugger.
> +
> + Copyright 2008-2025 Free Software Foundation, Inc.
> +
> + 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 <http://www.gnu.org/licenses/>. */
> +
> +#include <stdint.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +
> +void
> +set_fpmr (uint64_t value)
> +{
> + register uint64_t x0_val asm ("x0") = value;
> + /* msr fpmr, x0 */
> + __asm__ volatile (".inst 0xd51b4440" : : );
> +}
> +
> +void
> +handler (int sig)
> +{
> + set_fpmr (0xff008041);
> + exit(0);
> +}
> +
> +int
> +main ()
> +{
> + /* Ensure all the signals aren't blocked. */
Nit. Make it "Ensure no signals are blocked.". Makes it clearer.
> + sigset_t newset;
> + sigemptyset (&newset);
> + sigprocmask (SIG_SETMASK, &newset, NULL);
> +
> + signal (SIGILL, handler);
> +
> + set_fpmr (0x3fff7fc049);
> +
> + /* 0x06000000 : Cause an illegal instruction. Value undefined as per ARM
Formatting. Two spaces after period.
And maybe s/Cause/Causes or s/Cause/Execute, depending on what you meant.
> + Architecture Reference Manual ARMv8, Section C4.1. */
> + __asm __volatile (".inst 0x06000000");
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
> new file mode 100644
> index 00000000000..a776976eb7d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
> @@ -0,0 +1,77 @@
> +# Copyright 2018-2025 Free Software Foundation, Inc.
> +#
> +# 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 <http://www.gnu.org/licenses/>.
> +#
> +# This file is part of the gdb testsuite.
> +#
> +# Test FPMR register set is properly preserved when unwiding sighandler frames.
> +
> +require is_aarch64_target
> +require allow_aarch64_fpmr_tests
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> + return -1
> +}
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +set reg_main_value "0x3fff7fc049"
> +set reg_handler_value "0xff008041"
> +
> +proc check_fpmr {value} {
> + gdb_test "print /x \$fpmr" \
> + ".* = {?$value}?" \
> + "check register \$fpmr has value $value"
> +}
> +
> +# Run until end of signal handler
> +
> +gdb_test "continue" \
> + "Continuing.*Program received signal SIGILL.*" \
> + "continue until signal"
> +
> +gdb_breakpoint [gdb_get_line_number "exit(0)"]
> +gdb_continue_to_breakpoint "exit" ".*exit.*"
> +
> +set handlerframe [get_current_frame_number]
> +set mainframe [expr $handlerframe + 2]
> +
> +# Check register values
> +
> +with_test_prefix "handler frame 1st" {
> + check_fpmr $reg_handler_value
> +}
> +
> +# Switch to the frame for main(), and check register values
> +
> +gdb_test "frame $mainframe" \
> + "#$mainframe.*main ().*" \
> + "set to main frame"
> +
> +with_test_prefix "main frame" {
> + check_fpmr $reg_main_value
> +}
> +
> +# Switch back to the signal handler frame, and check register values
> +
> +gdb_test "frame $handlerframe" \
> + "#$handlerframe.*handler \\\(sig=4\\\).*" \
> + "set to signal handler frame"
> +
> +with_test_prefix "handler frame 2nd" {
> + check_fpmr $reg_handler_value
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr.c b/gdb/testsuite/gdb.arch/aarch64-fpmr.c
> new file mode 100644
> index 00000000000..f4bf889c3a8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr.c
> @@ -0,0 +1,117 @@
> +/* This file is part of GDB, the GNU debugger.
> +
> + Copyright 2008-2025 Free Software Foundation, Inc.
> +
> + 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 <http://www.gnu.org/licenses/>. */
> +
> +#include <stdint.h>
> +
> +enum FPM_FORMAT
> +{
> + E5M2,
> + E4M3,
> +};
> +
> +enum FPM_OVERFLOW
> +{
> + INFNAN,
> + SATURATE,
> +};
> +
> +void
> +set_fpmr (uint64_t value)
> +{
> + register uint64_t x0_val asm ("x0") = value;
> + __asm__ volatile (".inst 0xd51b4440" : : );
Add the following here as well?
/* msr fpmr, x0 */
> +}
> +
> +uint64_t
> +modify_src1_fmt (uint64_t fpmr, uint64_t fmt)
> +{
> + return (fpmr & ~(0x7)) | (fmt & 0x7);
> +}
> +
> +uint64_t
> +modify_src2_fmt (uint64_t fpmr, uint64_t fmt)
> +{
> + return (fpmr & ~((0x7) << 3)) | ((fmt & 0x7) << 3);
> +}
> +
> +uint64_t
> +modify_dst_fmt (uint64_t fpmr, uint64_t fmt)
> +{
> + return (fpmr & ~((0x7) << 6)) | ((fmt & 0x7) << 6);
> +}
> +
> +uint64_t
> +modify_osm (uint64_t fpmr, uint64_t overflow)
> +{
> + return (fpmr & ~((0x1) << 14)) | ((overflow & 0x1) << 14);
> +}
> +
> +uint64_t
> +modify_osc (uint64_t fpmr, uint64_t overflow)
> +{
> + return (fpmr & ~((0x1) << 15)) | ((overflow & 0x1) << 15);
> +}
> +
> +uint64_t
> +modify_lscale (uint64_t fpmr, uint64_t scale)
> +{
> + return (fpmr & ~((0x7f) << 16)) | ((scale & 0x7f) << 16);
> +}
> +
> +uint64_t
> +modify_nscale (uint64_t fpmr, uint64_t scale)
> +{
> + return (fpmr & ~((0xff) << 24)) | ((scale & 0xff) << 24);
> +}
> +
> +uint64_t
> +modify_lscale2 (uint64_t fpmr, uint64_t scale)
> +{
> + return (fpmr & ~((uint64_t)(0x3f) << 32)) | ((uint64_t)(scale & 0x3f) << 32);
> +}
> +
> +int
> +main (void)
> +{
> + uint64_t fpmr = 0;
> +
> + fpmr = modify_src1_fmt (fpmr, E4M3);
> + set_fpmr (fpmr); /* MODIFY SRC1 */
> +
> + fpmr = modify_src2_fmt (fpmr, E4M3);
> + set_fpmr (fpmr); /* MODIFY SRC2 */
> +
> + fpmr = modify_dst_fmt (fpmr, E4M3);
> + set_fpmr (fpmr); /* MODIFY DST */
> +
> + fpmr = modify_osm (fpmr, SATURATE);
> + set_fpmr (fpmr); /* MODIFY OSM */
> +
> + fpmr = modify_osc (fpmr, SATURATE);
> + set_fpmr (fpmr); /* MODIFY OSC */
> +
> + fpmr = modify_lscale (fpmr, -1);
> + set_fpmr (fpmr); /* MODIFY LSCALE */
> +
> + fpmr = modify_nscale (fpmr, -1);
> + set_fpmr (fpmr); /* MODIFY NSCALE */
> +
> + fpmr = modify_lscale2 (fpmr, -1);
> + set_fpmr (fpmr); /* MODIFY LSCALE2 */
> +
> + return 1;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-fpmr.exp b/gdb/testsuite/gdb.arch/aarch64-fpmr.exp
> new file mode 100644
> index 00000000000..947d47e981d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr.exp
> @@ -0,0 +1,72 @@
> +# Copyright 2023-2025 Free Software Foundation, Inc.
> +
> +# 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 <http://www.gnu.org/licenses/>. */
> +
> +# Exercise reading/writing FPMR when it is present.
> +
> +require is_aarch64_target
> +require allow_aarch64_fpmr_tests
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> + return -1
> +}
> +
> +if ![runto_main] {
> + untested "could not run to main"
As mentioned above, we should just drop this and return -1 here.
> + return -1
> +}
> +
> +gdb_test_multiple "info register \$fpmr" "Test FPMR SRC1 E5M2" {
> + -re ".*\r\n.*\[ F8S1=E5M2 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> + pass "FPMR SRC1 matches E5M2"
> + }
> +}
> +
> +set breakpoints [list "MODIFY SRC1" "MODIFY SRC2" "MODIFY DST" "MODIFY OSM" "MODIFY OSC" "MODIFY LSCALE" "MODIFY NSCALE" "MODIFY LSCALE2"]
Nit. For simplicity, you might want to drop the "MODIFY" from all of
these and just use the field name, as all of them modify something. And
then update the source file accordingly.
> +set reg_values [list \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=0 NSCALE=0 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=0 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=0 \]" \
> + ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=63 \]" \
> +]
> +set pass_messages [list "FPMR SRC1 matches E4M3" "FPMR SRC2 matches E4M3" "FPMR DST matches E4M3" "FPMR OSM matches MaxNormal" "FPMR OSC matches MaxNormal" "FPMR LSCALE matches" "FPMR NSCALE matches" "FPMR LSCALE2 matches"]
> +
> +for {set i 0} {$i < 8} {incr i} {
> + set bp [lindex $breakpoints $i]
> + gdb_breakpoint [gdb_get_line_number $bp]
> + gdb_continue_to_breakpoint $bp
> +
> + gdb_test_multiple "info register \$fpmr" "" {
> + -re [lindex $reg_values $i] {
> + pass [lindex $pass_messages $i]
> + }
> + }
> +}
> +
> +gdb_test_multiple "set \$fpmr=0x0" "" {
> + -re ".*\r\n.*\[ F8S1=E5M2 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> + pass "Reset FPMR to 0 from GDB"
> + }
> +}
> +
> +gdb_test_multiple "set \$fpmr=0x3f007f4008" "" {
> + -re ".*\r\n.*\[ F8S1=E5M2 F8S2=E4M3 F8D=E5M2 OSM=MaxNormal OSC=Inf/NaN LSCALE=127 NSCALE=0 LSCALE2=63 \]" {
> + pass "Write to FPMR from GDB"
> + }
> +}
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 930462f63fa..0d0369511bb 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -5201,6 +5201,72 @@ proc aarch64_supports_sme_svl { length } {
> return 1
> }
>
> +# Run a test on the target to see if it supports AArch64 FPMR hardware.
Nit. s/AArch64 FPMR hardware/the AArch64 FPMR feature.
> +# Return 1 if so, 0 if it does not. Note this causes a restart of GDB.
> +
> +gdb_caching_proc allow_aarch64_fpmr_tests {} {
> + global srcdir subdir gdb_prompt inferior_exited_re
> +
> + set me "allow_aarch64_fpmr_tests"
> +
> + if { ![is_aarch64_target]} {
> + return 0
> + }
> +
> + set compile_flags "{additional_flags=-march=armv8-a}"
> +
> + # Compile a test program that writes to FPMR.
Here it says "writes"...
> + set src {
> + int main() {
> + asm volatile ("msr x0, fpmr");
> + return 0;
> + }
> + }
> + if {![gdb_simple_compile $me $src executable $compile_flags]} {
> + # Try again, but with a raw hex instruction so we don't rely on
> + # assembler support for FPMR.
> +
> + set compile_flags "{additional_flags=-march=armv8-a}"
> +
> + # Compile a test program reading FPMR.
... but here it says reading. Which one is it?
> + set src {
> + int main() {
> + asm volatile (".word 0xD51B4440");
> + return 0;
> + }
> + }
> +
> + if {![gdb_simple_compile $me $src executable $compile_flags]} {
> + return 0
> + }
> + }
> +
> + # Compilation succeeded so now run it via gdb.
> + clean_restart
> + gdb_load $obj
> + gdb_run_cmd
> +
> + gdb_expect {
> + -re ".*Illegal instruction.*${gdb_prompt} $" {
> + verbose -log "\n$me fpmr support not detected"
> + set allow_fpmr_tests 0
> + }
> + -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
> + verbose -log "\n$me: fpmr support detected"
> + set allow_fpmr_tests 1
> + }
> + default {
> + warning "\n$me: default case taken"
> + set allow_fpmr_tests 0
> + }
> + }
> + gdb_exit
> + remote_file build delete $obj
> +
> + verbose "$me: returning $allow_fpmr_tests" 2
> + return $allow_fpmr_tests
> +}
> +
> # Run a test on the target to see if it supports AArch64 MOPS (Memory
> # Operations) extensions. Return 1 if so, 0 if it does not. Note this
> # causes a restart of GDB.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 0/5] gdb/aarch64: Support for FPMR
2025-10-07 12:31 [PATCH v2 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
` (4 preceding siblings ...)
2025-10-07 12:31 ` [PATCH v2 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
@ 2025-10-11 12:05 ` Luis
5 siblings, 0 replies; 16+ messages in thread
From: Luis @ 2025-10-11 12:05 UTC (permalink / raw)
To: Ezra.Sitorus, gdb-patches; +Cc: thiago.bauermann
On 07/10/2025 13:31, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> The Floating Point Mode Register (FPMR) determines the behaviour of FP8
> instructions. This patch series adds support for this register into gdb.
>
> I've run the full testsuite on aarch64-none-linux-gnu, and ran the
> gdb.arch tests using Shrinkwrap, which allows me to run Linux on a
> model of an Arm system with new features. You can find more information
> here: [1].
>
> In v2:
> * I've addressed the various comments on formatting/whitespaces
> * Testing is simplified - there's less repetition of code. I've also
> removed the remote versions of procedures to run the tests on
> gdbserver remotely.
>
> Ezra
>
> [1]: https://shrinkwrap.docs.arm.com/en/latest/
>
> Ezra Sitorus (5):
> gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
> gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
> gdb/aarch64: signal frame support for fpmr
> gdb/aarch64: core file support for FPMR
> gdb/aarch64: Tests for fpmr
>
> gdb/aarch64-linux-nat.c | 57 +++++++++
> gdb/aarch64-linux-tdep.c | 101 +++++++++++++++
> gdb/aarch64-tdep.c | 18 ++-
> gdb/aarch64-tdep.h | 9 ++
> gdb/arch/aarch64.c | 4 +
> gdb/arch/aarch64.h | 12 +-
> gdb/features/Makefile | 1 +
> gdb/features/aarch64-fpmr.c | 44 +++++++
> gdb/features/aarch64-fpmr.xml | 53 ++++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr-core.c | 40 ++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp | 97 +++++++++++++++
> .../gdb.arch/aarch64-fpmr-sighandler.c | 55 ++++++++
> .../gdb.arch/aarch64-fpmr-sighandler.exp | 77 ++++++++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr.c | 117 ++++++++++++++++++
> gdb/testsuite/gdb.arch/aarch64-fpmr.exp | 72 +++++++++++
> gdb/testsuite/lib/gdb.exp | 66 ++++++++++
> gdbserver/linux-aarch64-low.cc | 29 +++++
> 17 files changed, 850 insertions(+), 2 deletions(-)
> create mode 100644 gdb/features/aarch64-fpmr.c
> create mode 100644 gdb/features/aarch64-fpmr.xml
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-fpmr.exp
>
Thanks for the updated series. We'll need a documentation entry
describing the feature and what it does (to the extent that is
reasonable) and also documentation about the FPMR register set. See the
gdb manual for the documentation on the other AArch64 register sets.
Also, we will need a NEWS entry for the feature. Again, you can find
other examples in the gdb/NEWS file.
^ permalink raw reply [flat|nested] 16+ messages in thread