Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] gdb/aarch64: Support for FPMR
@ 2025-09-05 13:17 Ezra.Sitorus
  2025-09-05 13:17 ` [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
                   ` (5 more replies)
  0 siblings, 6 replies; 23+ messages in thread
From: Ezra.Sitorus @ 2025-09-05 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: luis.machado.foss, Ezra Sitorus

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.

This has been tested 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].

This is an RFC becauase there are a few things I'm not clear on - the
main thing being testing. In the final patch I've outlined my thoughts
in the message. 

I'd also appreciate any feedback regarding anything I can do better
here and also if I'm missing anything out.

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                       |  58 ++++++-
 gdb/aarch64-linux-tdep.c                      | 103 ++++++++++++-
 gdb/aarch64-tdep.c                            |  18 ++-
 gdb/aarch64-tdep.h                            |   7 +
 gdb/arch/aarch64.c                            |   4 +
 gdb/arch/aarch64.h                            |   4 +-
 gdb/features/Makefile                         |   1 +
 gdb/features/aarch64-fpmr.c                   |  44 ++++++
 gdb/features/aarch64-fpmr.xml                 |  55 +++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr-core.c    | 109 +++++++++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp  | 143 ++++++++++++++++++
 .../gdb.arch/aarch64-fpmr-sighandler.c        | 134 ++++++++++++++++
 .../gdb.arch/aarch64-fpmr-sighandler.exp      |  75 +++++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr.c         | 117 ++++++++++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr.exp       | 116 ++++++++++++++
 gdb/testsuite/lib/gdb.exp                     |  49 ++++++
 gdbserver/linux-aarch64-low.cc                |  29 ++++
 17 files changed, 1061 insertions(+), 5 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

-- 
2.45.2


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
  2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
@ 2025-09-05 13:17 ` Ezra.Sitorus
  2025-09-07 22:55   ` Luis
  2025-09-10 23:45   ` Thiago Jung Bauermann
  2025-09-05 13:17 ` [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 23+ messages in thread
From: Ezra.Sitorus @ 2025-09-05 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: luis.machado.foss, 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.

Manually validated with Shrinkwrap (Arm FVP).

For this patch:
* Are the FPMR fields useful? What to do if the format is not valid
  (0x2)? What about the OSC/OSM fields with Inf/Nan, are these helpful
  too?
---
 gdb/aarch64-linux-nat.c       | 58 ++++++++++++++++++++++++++++++++++-
 gdb/aarch64-linux-tdep.c      |  2 +-
 gdb/aarch64-tdep.c            | 18 +++++++++--
 gdb/aarch64-tdep.h            |  7 +++++
 gdb/arch/aarch64.c            |  4 +++
 gdb/arch/aarch64.h            |  4 ++-
 gdb/features/Makefile         |  1 +
 gdb/features/aarch64-fpmr.c   | 44 ++++++++++++++++++++++++++
 gdb/features/aarch64-fpmr.xml | 55 +++++++++++++++++++++++++++++++++
 9 files changed, 188 insertions(+), 5 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..b524aa352be 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 content from the
+   thread associated with REGCACHE.  If there is no active FPMR register state,
+   make the FPMR register contents zero.  */
+
+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"));
+    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"));
+}
+
 /* 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);
+  /* FP8/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,7 +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 +1022,9 @@ aarch64_linux_nat_target::read_description ()
   if ((hwcap2 & HWCAP2_SME2) || (hwcap2 & HWCAP2_SME2P1))
     features.sme2 = supports_zt_registers (tid);
 
+  /* Check for FP8/FPMR. */
+  features.fpmr = hwcap2 & (1UL << 48);
+
   return aarch64_read_description (features);
 }
 
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 76bde85188b..acb650db514 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1713,7 +1713,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 & (1UL << 48);
   /* Handle the TLS section.  */
   asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
   if (tls != nullptr)
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 500ac77d75a..33bef91c44e 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -4141,6 +4141,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
 			!= nullptr);
 
   return features;
+
+  /* Check for FPMR feature.  */
+  features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
+		   != nullptr);
 }
 
 /* Implement the "cannot_store_register" gdbarch method.  */
@@ -4448,11 +4452,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 +4555,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;
@@ -4760,7 +4773,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..403743516df 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -207,6 +207,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
   {
     return gcs_linux_reg_base != -1;
   }
+  /* Index of FPMR. This is -1 if FPMR/FP8 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..731d4680248 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
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..1f2f9c0d4cf
--- /dev/null
+++ b/gdb/features/aarch64-fpmr.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009-2025 Free Software Foundation, Inc.
+     Contributed by ARM Ltd.
+
+     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">
+  <enum id="fp8_fmt" size="3">
+    <!-- E5M2 -->
+    <evalue name="E5M2" value="0"/>
+    <!-- E4M3 -->
+    <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] 23+ messages in thread

* [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
  2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
  2025-09-05 13:17 ` [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
@ 2025-09-05 13:17 ` Ezra.Sitorus
  2025-09-07 22:55   ` Luis
  2025-09-10 23:46   ` Thiago Jung Bauermann
  2025-09-05 13:17 ` [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 23+ messages in thread
From: Ezra.Sitorus @ 2025-09-05 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: luis.machado.foss, Ezra Sitorus

From: Ezra Sitorus <ezra.sitorus@arm.com>

Support FPMR in gdbserver.

Manually validated under Shrinkwrap (Arm FVP).
---
 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..e15280c3681 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, &regset->fpcr);
 }
 
+/* Fill BUF with the FPMR 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 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) & (1UL << 48);
 
       /* Scalable Matrix Extension feature and size check.  */
       if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
-- 
2.45.2


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr
  2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
  2025-09-05 13:17 ` [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
  2025-09-05 13:17 ` [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
@ 2025-09-05 13:17 ` Ezra.Sitorus
  2025-09-07 22:56   ` Luis
  2025-09-10 23:47   ` Thiago Jung Bauermann
  2025-09-05 13:17 ` [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 23+ messages in thread
From: Ezra.Sitorus @ 2025-09-05 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: luis.machado.foss, Ezra Sitorus

From: Ezra Sitorus <ezra.sitorus@arm.com>

Add support for FPMR in signal frames and restore contents of FPMR.

Manually validated with Shrinkwrap (Arm FVP).
---
 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 acb650db514..b4911d36410 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -168,6 +168,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
@@ -214,6 +215,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
 {
@@ -261,6 +265,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
@@ -577,6 +587,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
@@ -740,6 +766,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 ()
@@ -792,6 +825,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] 23+ messages in thread

* [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR
  2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
                   ` (2 preceding siblings ...)
  2025-09-05 13:17 ` [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
@ 2025-09-05 13:17 ` Ezra.Sitorus
  2025-09-07 22:56   ` Luis
  2025-09-10 23:48   ` Thiago Jung Bauermann
  2025-09-05 13:17 ` [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
  2025-09-10 23:39 ` [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Thiago Jung Bauermann
  5 siblings, 2 replies; 23+ messages in thread
From: Ezra.Sitorus @ 2025-09-05 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: luis.machado.foss, Ezra Sitorus

From: Ezra Sitorus <ezra.sitorus@arm.com>

Add support for FPMR dumps/reads for core files.

Manually validated with Shrinkwrap (Arm FVP).
---
 gdb/aarch64-linux-tdep.c | 67 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index b4911d36410..731f05bae5a 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1519,6 +1519,56 @@ 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 ZT0 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
@@ -1636,6 +1686,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] 23+ messages in thread

* [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr
  2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
                   ` (3 preceding siblings ...)
  2025-09-05 13:17 ` [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
@ 2025-09-05 13:17 ` Ezra.Sitorus
  2025-09-07 22:56   ` Luis
  2025-09-10 23:53   ` Thiago Jung Bauermann
  2025-09-10 23:39 ` [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Thiago Jung Bauermann
  5 siblings, 2 replies; 23+ messages in thread
From: Ezra.Sitorus @ 2025-09-05 13:17 UTC (permalink / raw)
  To: gdb-patches; +Cc: luis.machado.foss, 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 and core file generation.

For these tests, I have used shrinkwrap for FPMR emulation. I am not
sure on how to do these tests properly as there are some things I'm not
sure about:

* Which board file do I use to test this? I've resorted to adapting
  remote-stdio-gdbserver.exp to use tcp when starting gdbserver
  remotely.
* Do I need to run the whole regression test? This is quite slow, and
  comes up with a lot of failures.
* Since gdbserver doesn't support core files, I've had to adapt
  core_find so that the core file is generated on target (where
  gdbserver runs), but then it's copied over to host (where gdb runs) to
  do the actual test. You can find this on aarch64-fpmr-core.exp
  (remote_core_find). Please let me know if there's a better way of
  doing this, or how I can improve the way I've done it.
* Another issue with the core file test is that sometimes it says all
  the tests pass, but there's 1 unexpected core file or that core files
  can't be generated and I need to do ulimit -c unlimited, despite
  having done that already.
---
 gdb/testsuite/gdb.arch/aarch64-fpmr-core.c    | 109 +++++++++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp  | 143 ++++++++++++++++++
 .../gdb.arch/aarch64-fpmr-sighandler.c        | 134 ++++++++++++++++
 .../gdb.arch/aarch64-fpmr-sighandler.exp      |  75 +++++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr.c         | 117 ++++++++++++++
 gdb/testsuite/gdb.arch/aarch64-fpmr.exp       | 116 ++++++++++++++
 gdb/testsuite/lib/gdb.exp                     |  49 ++++++
 7 files changed, 743 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..95c6f302ad7
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
@@ -0,0 +1,109 @@
+/* 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;
+
+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;
+  /* CHECK SRC1 0 */
+
+  fpmr = modify_src1_fmt (fpmr, E4M3);
+  fpmr = modify_src2_fmt (fpmr, E4M3);
+  fpmr = modify_dst_fmt (fpmr, E4M3);
+  fpmr = modify_osm (fpmr, SATURATE);
+  fpmr = modify_osc (fpmr, SATURATE);
+  fpmr = modify_lscale (fpmr, -1);
+  fpmr = modify_nscale (fpmr, -1);
+  fpmr = modify_lscale2 (fpmr, -1);
+  set_fpmr (fpmr);
+  /* 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..52acfd7291b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
@@ -0,0 +1,143 @@
+# 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"
+}
+
+proc remote_core_find {binfile {deletefiles {}} {arg ""}} {
+    global objdir subdir REMOTE_TMPDIR
+
+    set target_binfile [gdbserver_download_current_prog]
+
+    set destcore "$target_binfile.core"
+    remote_exec target delete $destcore
+
+    set found 0
+    set coredir "${REMOTE_TMPDIR}/coredir.[getpid]"
+    remote_exec target "mkdir $coredir"
+    remote_exec target "(cd ${coredir}; ulimit -c unlimited; ${target_binfile} ${arg}; true) >/dev/null 2>&1"
+    set binfile_basename [file tail $target_binfile]
+    foreach i [list \
+		   ${coredir}/core \
+		   ${coredir}/core.coremaker.c \
+		   ${coredir}/${binfile_basename}.core \
+		   ${coredir}/${binfile_basename}.exe.core] {
+	if [remote_file target exists $i] {
+	    remote_exec target "mv $i $destcore"
+	    set found 1
+	}
+    }
+
+    if { $found == 0 } {
+	set names [glob -nocomplain -directory $coredir core.*]
+	if {[llength $names] == 1} {
+	    set corefile [file join $coredir [lindex $names 0]]
+	    remote_exec target "mv $corefile $destcore"
+	    set found 1
+	}
+    }
+
+    foreach deletefile $deletefiles {
+	remote_file target delete [file join $coredir $deletefile]
+    }
+    remote_exec target "rmdir $coredir"
+
+    if { $found == 0  } {
+	warning "can't generate a core file - core tests suppressed - check ulimit -c"
+	return ""
+    }
+    set native_corefile "${binfile}.core"
+    remote_download host [remote_upload target $destcore] $native_corefile
+
+    return $native_corefile
+}
+
+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 [remote_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 ${binfile}
+	with_test_prefix "gcore corefile" {
+		check_fpmr_core_file $gcore_filename
+	}
+} else {
+	fail "gcore corefile not generated"
+}
+
+if {$core_generated} {
+	clean_restart ${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..4ca68a38072
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
@@ -0,0 +1,134 @@
+/* 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>
+
+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);
+}
+
+void
+handler (int sig)
+{
+  uint64_t fpmr = 0;
+  fpmr = modify_src1_fmt (fpmr, E4M3);
+  fpmr = modify_src2_fmt (fpmr, E5M2);
+  fpmr = modify_dst_fmt (fpmr, E4M3);
+  fpmr = modify_osm (fpmr, INFNAN);
+  fpmr = modify_osc (fpmr, SATURATE);
+  fpmr = modify_lscale (fpmr, 0);
+  fpmr = modify_nscale (fpmr, -1);
+  fpmr = modify_lscale2 (fpmr, 0);
+  set_fpmr (fpmr);
+
+  exit(0);
+}
+
+int
+main ()
+{
+  /* Ensure all the signals aren't blocked.  */
+  sigset_t newset;
+  sigemptyset (&newset);
+  sigprocmask (SIG_SETMASK, &newset, NULL);
+
+  signal (SIGILL, handler);
+
+  uint64_t fpmr = 0;
+
+  fpmr = modify_src1_fmt (fpmr, E5M2);
+  fpmr = modify_src2_fmt (fpmr, E4M3);
+  fpmr = modify_dst_fmt (fpmr, E5M2);
+  fpmr = modify_osm (fpmr, SATURATE);
+  fpmr = modify_osc (fpmr, INFNAN);
+  fpmr = modify_lscale (fpmr, -1);
+  fpmr = modify_nscale (fpmr, 0);
+  fpmr = modify_lscale2 (fpmr, -1);
+  set_fpmr (fpmr);
+
+  /* 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..2ba9818b42c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
@@ -0,0 +1,75 @@
+# 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.
+
+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 "0x3f007f4008"
+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..211f6fdd40a
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-fpmr.exp
@@ -0,0 +1,116 @@
+# 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 there is FPMR.
+
+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 modify_src1_bp "MODIFY SRC1"
+gdb_breakpoint [gdb_get_line_number $modify_src1_bp]
+gdb_continue_to_breakpoint $modify_src1_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+        pass "FPMR SRC1 matches E4M3, SRC2 matches E5M2"
+    }
+}
+
+set modify_src2_bp "MODIFY SRC2"
+gdb_breakpoint [gdb_get_line_number $modify_src2_bp]
+gdb_continue_to_breakpoint $modify_src2_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+        pass "FPMR SRC2 matches E4M3"
+    }
+}
+
+set modify_dst_bp "MODIFY DST"
+gdb_breakpoint [gdb_get_line_number $modify_dst_bp]
+gdb_continue_to_breakpoint $modify_dst_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+        pass "FPMR DST matches E4M3"
+    }
+}
+
+set modify_osm_bp "MODIFY OSM"
+gdb_breakpoint [gdb_get_line_number $modify_osm_bp]
+gdb_continue_to_breakpoint $modify_osm_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+        pass "FPMR OSM matches MaxNormal"
+    }
+}
+
+set modify_osc_bp "MODIFY OSC"
+gdb_breakpoint [gdb_get_line_number $modify_osc_bp]
+gdb_continue_to_breakpoint $modify_osc_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
+        pass "FPMR OSC matches MaxNormal"
+    }
+}
+
+set modify_lscale_bp "MODIFY LSCALE"
+gdb_breakpoint [gdb_get_line_number $modify_lscale_bp]
+gdb_continue_to_breakpoint $modify_lscale_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=0 LSCALE2=0 \]" {
+        pass "FPMR LSCALE matches"
+    }
+}
+
+set modify_nscale_bp "MODIFY NSCALE"
+gdb_breakpoint [gdb_get_line_number $modify_nscale_bp]
+gdb_continue_to_breakpoint $modify_nscale_bp
+
+# GDB does not present bitfields as signed value.
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=0 \]" {
+        pass "FPMR NSCALE matches"
+    }
+}
+
+set modify_lscale2_bp "MODIFY LSCALE2"
+gdb_breakpoint [gdb_get_line_number $modify_lscale2_bp]
+gdb_continue_to_breakpoint $modify_lscale2_bp
+
+gdb_test_multiple "info register \$fpmr" "" {
+    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=63 \]" {
+        pass "FPMR LSCALE2 matches"
+    }
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index ab4506a4455..a6961fb8719 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5266,6 +5266,55 @@ 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 (".inst	0xd51b4440");
+	    return 0;
+	}
+    }
+    if {![gdb_simple_compile $me $src executable $compile_flags]} {
+        return 0
+    }
+
+    # Compilation succeeded so now run it via gdb.
+    clean_restart $obj
+    gdb_run_cmd
+    gdb_expect {
+        -re ".*Illegal instruction.*${gdb_prompt} $" {
+            verbose -log "\n$me fpmr not detected"
+            set allow_fpmr_tests 0
+        }
+        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+            verbose -log "\n$me: fpmr hardware 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] 23+ messages in thread

* Re: [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
  2025-09-05 13:17 ` [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
@ 2025-09-07 22:55   ` Luis
  2025-09-10 23:56     ` Thiago Jung Bauermann
  2025-09-10 23:45   ` Thiago Jung Bauermann
  1 sibling, 1 reply; 23+ messages in thread
From: Luis @ 2025-09-07 22:55 UTC (permalink / raw)
  To: Ezra.Sitorus, gdb-patches

Thanks for the patch. A few comment below.


On 05/09/2025 14:17, 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.
> 
> Manually validated with Shrinkwrap (Arm FVP).
> 
> For this patch:
> * Are the FPMR fields useful? What to do if the format is not valid
>    (0x2)? What about the OSC/OSM fields with Inf/Nan, are these helpful
>    too?

I think that's an implementation choice. Is it of any value to users 
using the debugger to have access to these fields in a clearer manner? 
If not, then it doesn´t seem very useful.

Is gdb allowed to force-change fpmr bits to switch the format being 
used? Is that useful?

> ---
>   gdb/aarch64-linux-nat.c       | 58 ++++++++++++++++++++++++++++++++++-
>   gdb/aarch64-linux-tdep.c      |  2 +-
>   gdb/aarch64-tdep.c            | 18 +++++++++--
>   gdb/aarch64-tdep.h            |  7 +++++
>   gdb/arch/aarch64.c            |  4 +++
>   gdb/arch/aarch64.h            |  4 ++-
>   gdb/features/Makefile         |  1 +
>   gdb/features/aarch64-fpmr.c   | 44 ++++++++++++++++++++++++++
>   gdb/features/aarch64-fpmr.xml | 55 +++++++++++++++++++++++++++++++++
>   9 files changed, 188 insertions(+), 5 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..b524aa352be 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 content from the

s/FPMR register content/FPMR register set content

> +   thread associated with REGCACHE.  If there is no active FPMR register state,
> +   make the FPMR register contents zero.  */

The comment states not having an active FPMR register state. Is that how 
this is implemented? Or is it the usual situation where you either have 
kernel support or you don't. If you do, then you get whatever contents 
the kernel provides, and gdb doesn´t need to bother with it.

The code doesn´t seem to set anything to zero.

> +
> +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"));

Maybe "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

New line between comment and function declaration.

> +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"));

"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);
> +  /* FP8/FPMR? */

For consistency maybe use FPMR only? Is FP8 important in this context?

> +  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,7 +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);
> -

Unrelated removal of blank line.

> +  /* FPMR?  */
> +  else if (tdep->has_fpmr() && regno == tdep->fpmr_regnum)

Formatting: space between function name and parenthesis.

> +    store_fpmr_to_thread (regcache);
>     /* PAuth registers are read-only.  */
>   }
>   
> @@ -969,6 +1022,9 @@ aarch64_linux_nat_target::read_description ()
>     if ((hwcap2 & HWCAP2_SME2) || (hwcap2 & HWCAP2_SME2P1))
>       features.sme2 = supports_zt_registers (tid);
>   
> +  /* Check for FP8/FPMR. */

Use only FPMR?

> +  features.fpmr = hwcap2 & (1UL << 48);
> +

Based on previous issues, I think we need to use 1ULL here due to 32-bit 
arm.

>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 76bde85188b..acb650db514 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1713,7 +1713,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 & (1UL << 48);

Same here, 1ULL.

>     /* Handle the TLS section.  */
>     asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>     if (tls != nullptr)
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index 500ac77d75a..33bef91c44e 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -4141,6 +4141,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>   			!= nullptr);
>   
>     return features;
> +
> +  /* Check for FPMR feature.  */
> +  features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
> +		   != nullptr);
>   }
>   
>   /* Implement the "cannot_store_register" gdbarch method.  */
> @@ -4448,11 +4452,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 +4555,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;
> @@ -4760,7 +4773,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;
> -

Unrelated removal of blank line.

> +  /* 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..403743516df 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -207,6 +207,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>     {
>       return gcs_linux_reg_base != -1;
>     }
> +  /* Index of FPMR. This is -1 if FPMR/FP8 is not supported. */

Keeping the consistency with how the other sets were documented, I´d say:

"First FPMR register.  This is -1 if FPMR is not available."

> +  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..731d4680248 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;
>   }

Do you also need to update the operator() to account for fpmr? It 
computes the hash of the feature based on what features are present.

Unrelated, but looking at the code, it may be the case we missed adding 
gcs and gcs_linux to this operator.

>   
>   namespace std
> 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..1f2f9c0d4cf
> --- /dev/null
> +++ b/gdb/features/aarch64-fpmr.xml
> @@ -0,0 +1,55 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2009-2025 Free Software Foundation, Inc.

If the file wasn´t derived from another, this should be 2025 only.

> +     Contributed by ARM Ltd.

I don´t think we're adding these "Contributed by" entries anymore. From 
the commit log, it should be clear where the contribution came from.

> +
> +     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">
> +  <enum id="fp8_fmt" size="3">
> +    <!-- E5M2 -->

I´d expand the comment a bit. As it is, it isn´t useful. If there isn´t 
anything useful to say about the register, leave it without a comment. 
Same for other cases below where the comment is just the register name.

> +    <evalue name="E5M2" value="0"/>
> +    <!-- E4M3 -->
> +    <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>

A spotted some misc formatting issues, like space between function and 
parenthesis, 2 spaces after period, blank line between function 
declaration and comment. When working through the comment, please make 
sure those get addressed.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
  2025-09-05 13:17 ` [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
@ 2025-09-07 22:55   ` Luis
  2025-09-10 23:46   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Luis @ 2025-09-07 22:55 UTC (permalink / raw)
  To: Ezra.Sitorus, gdb-patches

On 05/09/2025 14:17, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
> 
> Support FPMR in gdbserver.
> 
> Manually validated under Shrinkwrap (Arm FVP).
> ---
>   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..e15280c3681 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, &regset->fpcr);
>   }
>   
> +/* Fill BUF with the FPMR from the regcache.  */

s/FPMR/FPMR register"

> +
> +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 to regcache.  */

s/FPMR/FPMR register

> +
> +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) & (1UL << 48);

s/1UL/1ULL

>   
>         /* Scalable Matrix Extension feature and size check.  */
>         if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr
  2025-09-05 13:17 ` [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
@ 2025-09-07 22:56   ` Luis
  2025-09-11  0:03     ` Thiago Jung Bauermann
  2025-09-10 23:47   ` Thiago Jung Bauermann
  1 sibling, 1 reply; 23+ messages in thread
From: Luis @ 2025-09-07 22:56 UTC (permalink / raw)
  To: Ezra.Sitorus, gdb-patches, Thiago Jung Bauermann

On 05/09/2025 14:17, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
> 
> Add support for FPMR in signal frames and restore contents of FPMR.
> 
> Manually validated with Shrinkwrap (Arm FVP).
> ---
>   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 acb650db514..b4911d36410 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -168,6 +168,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
> @@ -214,6 +215,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
>   {
> @@ -261,6 +265,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
> @@ -577,6 +587,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
> @@ -740,6 +766,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 ()
> @@ -792,6 +825,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;

Unrelated, but looks like we're not handling gcs in 
aarch64_linux_sigframe_prev_arch. Is that something we need to do Thiago?

>   
>     struct gdbarch_info info;
>     info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);

Otherwise, I don't have comments on this patch.

Reviewed-By: Luis Machado <luis.machado.foss@gmail.com>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR
  2025-09-05 13:17 ` [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
@ 2025-09-07 22:56   ` Luis
  2025-09-10 23:48   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Luis @ 2025-09-07 22:56 UTC (permalink / raw)
  To: Ezra.Sitorus, gdb-patches

On 05/09/2025 14:17, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
> 
> Add support for FPMR dumps/reads for core files.
> 
> Manually validated with Shrinkwrap (Arm FVP).
> ---
>   gdb/aarch64-linux-tdep.c | 67 ++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 67 insertions(+)
> 
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index b4911d36410..731f05bae5a 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1519,6 +1519,56 @@ 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 ZT0 register contents.  */

s/ZT0/FPMR

> +  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
> @@ -1636,6 +1686,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.  */

Otherwise I have no further comments.

Reviewed-By: Luis Machado <luis.machado.foss@gmail.com>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr
  2025-09-05 13:17 ` [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
@ 2025-09-07 22:56   ` Luis
  2025-09-16 11:09     ` Ezra Sitorus
  2025-09-10 23:53   ` Thiago Jung Bauermann
  1 sibling, 1 reply; 23+ messages in thread
From: Luis @ 2025-09-07 22:56 UTC (permalink / raw)
  To: Ezra.Sitorus, gdb-patches

Thanks for the patch.

On 05/09/2025 14:17, 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 and core file generation.
> 
> For these tests, I have used shrinkwrap for FPMR emulation. I am not
> sure on how to do these tests properly as there are some things I'm not
> sure about:
> 
> * Which board file do I use to test this? I've resorted to adapting
>    remote-stdio-gdbserver.exp to use tcp when starting gdbserver
>    remotely.

If you have Linux running on the FVP, you need to build gdb/gdbserver 
natively in there or cross-build aarch64-linux versions of gdb/gdbserver 
, copy the binaries over and then invoke the testsuite like so:

make check-gdb RUNTESTFLAGS="--target_board=native-gdbserver"

You'll run gdb's testsuite against gdbserver inside the FVP. It will be 
fairly slow for sure, but that's unfortunately how it goes.

If you want to exercise gdbserver in extended-remote mode, replace 
native-gdbserver with native-extended-gdbserver.

> * Do I need to run the whole regression test? This is quite slow, and
>    comes up with a lot of failures.

It is a good idea to run the entire testsuite at least once to make sure 
things didn't break somewhere. If your change is aarch64-specific, it 
still makes sense to run the entire testsuite (maybe run it on a big 
server to see if things are still sane), but once you know the code is 
OK, you can then focus on the gdb.arch/*aarch64*.exp tests.

> * Since gdbserver doesn't support core files, I've had to adapt
>    core_find so that the core file is generated on target (where
>    gdbserver runs), but then it's copied over to host (where gdb runs) to
>    do the actual test. You can find this on aarch64-fpmr-core.exp
>    (remote_core_find). Please let me know if there's a better way of
>    doing this, or how I can improve the way I've done it.

You don´t need to have those changes.

> * Another issue with the core file test is that sometimes it says all
>    the tests pass, but there's 1 unexpected core file or that core files
>    can't be generated and I need to do ulimit -c unlimited, despite
>    having done that already.

You need to check 2 things, the ulimit -c and the core file pattern in 
/proc/sys/kernel/core_pattern.

I usually use core.%p, and that seems to make the testsuite happy.

> ---
>   gdb/testsuite/gdb.arch/aarch64-fpmr-core.c    | 109 +++++++++++++
>   gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp  | 143 ++++++++++++++++++
>   .../gdb.arch/aarch64-fpmr-sighandler.c        | 134 ++++++++++++++++
>   .../gdb.arch/aarch64-fpmr-sighandler.exp      |  75 +++++++++
>   gdb/testsuite/gdb.arch/aarch64-fpmr.c         | 117 ++++++++++++++
>   gdb/testsuite/gdb.arch/aarch64-fpmr.exp       | 116 ++++++++++++++
>   gdb/testsuite/lib/gdb.exp                     |  49 ++++++
>   7 files changed, 743 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..95c6f302ad7
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
> @@ -0,0 +1,109 @@
> +/* This file is part of GDB, the GNU debugger.
> +
> +   Copyright 2008-2025 Free Software Foundation, Inc.

If this is new, use only 2025. If you've based the code on another 
source file, then you should use the range. Same comment for all the 
other files.

> +
> +   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;
> +
> +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;
> +  /* CHECK SRC1 0 */
> +
> +  fpmr = modify_src1_fmt (fpmr, E4M3);
> +  fpmr = modify_src2_fmt (fpmr, E4M3);
> +  fpmr = modify_dst_fmt (fpmr, E4M3);
> +  fpmr = modify_osm (fpmr, SATURATE);
> +  fpmr = modify_osc (fpmr, SATURATE);
> +  fpmr = modify_lscale (fpmr, -1);
> +  fpmr = modify_nscale (fpmr, -1);
> +  fpmr = modify_lscale2 (fpmr, -1);
> +  set_fpmr (fpmr);
> +  /* 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..52acfd7291b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp

See gdb.arch/aarch64-mte-core.exp for an example on how to test 
core/gcore file generation.

> @@ -0,0 +1,143 @@
> +# 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"
> +}
> +
> +proc remote_core_find {binfile {deletefiles {}} {arg ""}} {
> +    global objdir subdir REMOTE_TMPDIR
> +
> +    set target_binfile [gdbserver_download_current_prog]
> +
> +    set destcore "$target_binfile.core"
> +    remote_exec target delete $destcore
> +
> +    set found 0
> +    set coredir "${REMOTE_TMPDIR}/coredir.[getpid]"
> +    remote_exec target "mkdir $coredir"
> +    remote_exec target "(cd ${coredir}; ulimit -c unlimited; ${target_binfile} ${arg}; true) >/dev/null 2>&1"
> +    set binfile_basename [file tail $target_binfile]
> +    foreach i [list \
> +		   ${coredir}/core \
> +		   ${coredir}/core.coremaker.c \
> +		   ${coredir}/${binfile_basename}.core \
> +		   ${coredir}/${binfile_basename}.exe.core] {
> +	if [remote_file target exists $i] {
> +	    remote_exec target "mv $i $destcore"
> +	    set found 1
> +	}
> +    }
> +
> +    if { $found == 0 } {
> +	set names [glob -nocomplain -directory $coredir core.*]
> +	if {[llength $names] == 1} {
> +	    set corefile [file join $coredir [lindex $names 0]]
> +	    remote_exec target "mv $corefile $destcore"
> +	    set found 1
> +	}
> +    }
> +
> +    foreach deletefile $deletefiles {
> +	remote_file target delete [file join $coredir $deletefile]
> +    }
> +    remote_exec target "rmdir $coredir"
> +
> +    if { $found == 0  } {
> +	warning "can't generate a core file - core tests suppressed - check ulimit -c"
> +	return ""
> +    }
> +    set native_corefile "${binfile}.core"
> +    remote_download host [remote_upload target $destcore] $native_corefile
> +
> +    return $native_corefile
> +}
> +
> +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 [remote_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 ${binfile}
> +	with_test_prefix "gcore corefile" {
> +		check_fpmr_core_file $gcore_filename
> +	}
> +} else {
> +	fail "gcore corefile not generated"
> +}
> +
> +if {$core_generated} {
> +	clean_restart ${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..4ca68a38072
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.c
> @@ -0,0 +1,134 @@
> +/* 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>
> +
> +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);
> +}
> +
> +void
> +handler (int sig)
> +{
> +  uint64_t fpmr = 0;
> +  fpmr = modify_src1_fmt (fpmr, E4M3);
> +  fpmr = modify_src2_fmt (fpmr, E5M2);
> +  fpmr = modify_dst_fmt (fpmr, E4M3);
> +  fpmr = modify_osm (fpmr, INFNAN);
> +  fpmr = modify_osc (fpmr, SATURATE);
> +  fpmr = modify_lscale (fpmr, 0);
> +  fpmr = modify_nscale (fpmr, -1);
> +  fpmr = modify_lscale2 (fpmr, 0);
> +  set_fpmr (fpmr);
> +
> +  exit(0);
> +}
> +
> +int
> +main ()
> +{
> +  /* Ensure all the signals aren't blocked.  */
> +  sigset_t newset;
> +  sigemptyset (&newset);
> +  sigprocmask (SIG_SETMASK, &newset, NULL);
> +
> +  signal (SIGILL, handler);
> +
> +  uint64_t fpmr = 0;
> +
> +  fpmr = modify_src1_fmt (fpmr, E5M2);
> +  fpmr = modify_src2_fmt (fpmr, E4M3);
> +  fpmr = modify_dst_fmt (fpmr, E5M2);
> +  fpmr = modify_osm (fpmr, SATURATE);
> +  fpmr = modify_osc (fpmr, INFNAN);
> +  fpmr = modify_lscale (fpmr, -1);
> +  fpmr = modify_nscale (fpmr, 0);
> +  fpmr = modify_lscale2 (fpmr, -1);
> +  set_fpmr (fpmr);
> +
> +  /* 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..2ba9818b42c
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-sighandler.exp
> @@ -0,0 +1,75 @@
> +# 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.

Add a comment explaining what the test exercises.

> +
> +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 "0x3f007f4008"
> +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..211f6fdd40a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr.exp
> @@ -0,0 +1,116 @@
> +# 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 there is FPMR.

Am I missing something or is gdb.arch/aarch64-fpmr.exp only exercising 
gdb reading the registers written by the testcase and not attempting to 
write to fpmr?

> +
> +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 modify_src1_bp "MODIFY SRC1"
> +gdb_breakpoint [gdb_get_line_number $modify_src1_bp]
> +gdb_continue_to_breakpoint $modify_src1_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> +        pass "FPMR SRC1 matches E4M3, SRC2 matches E5M2"
> +    }
> +}
> +
> +set modify_src2_bp "MODIFY SRC2"
> +gdb_breakpoint [gdb_get_line_number $modify_src2_bp]
> +gdb_continue_to_breakpoint $modify_src2_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> +        pass "FPMR SRC2 matches E4M3"
> +    }
> +}
> +
> +set modify_dst_bp "MODIFY DST"
> +gdb_breakpoint [gdb_get_line_number $modify_dst_bp]
> +gdb_continue_to_breakpoint $modify_dst_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> +        pass "FPMR DST matches E4M3"
> +    }
> +}
> +
> +set modify_osm_bp "MODIFY OSM"
> +gdb_breakpoint [gdb_get_line_number $modify_osm_bp]
> +gdb_continue_to_breakpoint $modify_osm_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> +        pass "FPMR OSM matches MaxNormal"
> +    }
> +}
> +
> +set modify_osc_bp "MODIFY OSC"
> +gdb_breakpoint [gdb_get_line_number $modify_osc_bp]
> +gdb_continue_to_breakpoint $modify_osc_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=0 NSCALE=0 LSCALE2=0 \]" {
> +        pass "FPMR OSC matches MaxNormal"
> +    }
> +}
> +
> +set modify_lscale_bp "MODIFY LSCALE"
> +gdb_breakpoint [gdb_get_line_number $modify_lscale_bp]
> +gdb_continue_to_breakpoint $modify_lscale_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=0 LSCALE2=0 \]" {
> +        pass "FPMR LSCALE matches"
> +    }
> +}
> +
> +set modify_nscale_bp "MODIFY NSCALE"
> +gdb_breakpoint [gdb_get_line_number $modify_nscale_bp]
> +gdb_continue_to_breakpoint $modify_nscale_bp
> +
> +# GDB does not present bitfields as signed value.
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=0 \]" {
> +        pass "FPMR NSCALE matches"
> +    }
> +}
> +
> +set modify_lscale2_bp "MODIFY LSCALE2"
> +gdb_breakpoint [gdb_get_line_number $modify_lscale2_bp]
> +gdb_continue_to_breakpoint $modify_lscale2_bp
> +
> +gdb_test_multiple "info register \$fpmr" "" {
> +    -re ".*\r\n.*\[ F8S1=E4M3 F8S2=E4M3 F8D=E4M3 OSM=MaxNormal OSC=MaxNormal LSCALE=127 NSCALE=255 LSCALE2=63 \]" {
> +        pass "FPMR LSCALE2 matches"
> +    }
> +}

I think there is a better way to write these checks. Instead of 
duplicating most of the checks, we can build a list of breakpoints and a 
list of expected output values for each breakpoint.

And you also have control over the breakpoint names, so you could index 
them with a counter.

Then you can refactor these checks into a loop (using foreach) that goes 
through the breakpoints and checks the values.

> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index ab4506a4455..a6961fb8719 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -5266,6 +5266,55 @@ proc aarch64_supports_sme_svl { length } {
>       return 1
>   }
>   
> +# Run a test on the target to see if it supports AArch64 FPMR hardware.

s/AArch64 FPMR hardware/AArch64's FPMR

> +# 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}"

See allow_aarch64_sme_tests for how we try to compile an instruction 
related to the feature and only when we fail we switch to raw hex 
instruction.

> +
> +    # Compile a test program that writes to FPMR.
> +    set src {
> +	int main() {
> +	    asm volatile (".inst	0xd51b4440");
> +	    return 0;> +	}
> +    }
> +    if {![gdb_simple_compile $me $src executable $compile_flags]} {
> +        return 0
> +    }
> +
> +    # Compilation succeeded so now run it via gdb.
> +    clean_restart $obj
> +    gdb_run_cmd
> +    gdb_expect {
> +        -re ".*Illegal instruction.*${gdb_prompt} $" {
> +            verbose -log "\n$me fpmr not detected"

s/fpmr/fpmr support

> +            set allow_fpmr_tests 0
> +        }
> +        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
> +            verbose -log "\n$me: fpmr hardware detected"

s/fpmr hardware/fpmr support

> +            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.

A more general comment on the test source files. They appear to be 
mostly duplicated. For instance, does the core file test need to have 
all of the functions that modify fpmr, or is it enough if you modify it 
once and then check the core file contents?

The same goes for the signal handler test

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 0/5] gdb/aarch64: Support for FPMR
  2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
                   ` (4 preceding siblings ...)
  2025-09-05 13:17 ` [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
@ 2025-09-10 23:39 ` Thiago Jung Bauermann
  2025-09-11 15:52   ` Ezra Sitorus
  5 siblings, 1 reply; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:39 UTC (permalink / raw)
  To: Ezra.Sitorus; +Cc: gdb-patches, luis.machado.foss

Hello Ezra,

Thank you for these patches.

<Ezra.Sitorus@arm.com> writes:

> 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.
>
> This has been tested 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].

Is there something specific one has to do to enable FPMR on
Shrinkwrap/FVP?

I tried building an Armv9.5 configuration:

$ shrinkwrap build --overlay=arch/v9.5.yaml ns-edk2.yaml

and then running it with upstream kernel v6.16-rc7 which I think should
support FPMR, but AT_HWCAP doesn't have the FPMR bit set, and the test
program from the allow_aarch64_fpmr_tests procedure gets a SIGILL so the
testcases in this series report unsupported.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
  2025-09-05 13:17 ` [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
  2025-09-07 22:55   ` Luis
@ 2025-09-10 23:45   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:45 UTC (permalink / raw)
  To: Ezra.Sitorus; +Cc: gdb-patches, luis.machado.foss

<Ezra.Sitorus@arm.com> writes:

> 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.
>
> Manually validated with Shrinkwrap (Arm FVP).
>
> For this patch:
> * Are the FPMR fields useful? What to do if the format is not valid
>   (0x2)? What about the OSC/OSM fields with Inf/Nan, are these helpful
>   too?

I think they are useful. It's always good to get a "decoded" value from
this kind of register.

For invalid values, I think (though not sure) that GDB will just display
the "raw" value of the field since no enum value will match...

> ---
>  gdb/aarch64-linux-nat.c       | 58 ++++++++++++++++++++++++++++++++++-
>  gdb/aarch64-linux-tdep.c      |  2 +-
>  gdb/aarch64-tdep.c            | 18 +++++++++--
>  gdb/aarch64-tdep.h            |  7 +++++
>  gdb/arch/aarch64.c            |  4 +++
>  gdb/arch/aarch64.h            |  4 ++-
>  gdb/features/Makefile         |  1 +
>  gdb/features/aarch64-fpmr.c   | 44 ++++++++++++++++++++++++++
>  gdb/features/aarch64-fpmr.xml | 55 +++++++++++++++++++++++++++++++++
>  9 files changed, 188 insertions(+), 5 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..b524aa352be 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 content from the
> +   thread associated with REGCACHE.  If there is no active FPMR register state,
> +   make the FPMR register contents zero.  */
> +
> +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);

Missing space between function name and parenthesis.

> +
> +    if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_FPMR, &iov) < 0)
> +      perror_with_name (_("Unable to fetch FPMR"));
> +    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);

Missing space between function name and parenthesis.

> +
> +  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"));
> +}
> +
>  /* 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);
> +  /* FP8/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,7 +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 +1022,9 @@ aarch64_linux_nat_target::read_description ()
>    if ((hwcap2 & HWCAP2_SME2) || (hwcap2 & HWCAP2_SME2P1))
>      features.sme2 = supports_zt_registers (tid);
>  
> +  /* Check for FP8/FPMR. */

Two spaces after the period.

> +  features.fpmr = hwcap2 & (1UL << 48);
> +

Both Linux and glibc define HWCAP2_FPMR so it's better to use it here
and in the two other places were you use this value (one of them is in
another patch).

You can provide a definition in a header file for the case where the
system headers aren't new enough to have it, as is done for HWCAP_GCS
and HWCAP_MTE. With the difference that in both of those cases there's a
separate header specific for that hardware feature. For FPMR, I'd put
the definition in gdb/arch/aarch64.h.

>    return aarch64_read_description (features);
>  }
>  
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index 76bde85188b..acb650db514 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1713,7 +1713,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;
> -

It's subjective, but I think the code looks better with this blank line
separating this setup of the features struct and the "Handle the TLS
section" part below.

> +  features.fpmr = hwcap2 & (1UL << 48);

Here too, you can use HWCAP2_FPMR.

>    /* Handle the TLS section.  */
>    asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
>    if (tls != nullptr)
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index 500ac77d75a..33bef91c44e 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -4141,6 +4141,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>  			!= nullptr);
>  
>    return features;
> +
> +  /* Check for FPMR feature.  */
> +  features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
> +		   != nullptr);

This needs to be above the return.

>  }
>  
>  /* Implement the "cannot_store_register" gdbarch method.  */
> @@ -4448,11 +4452,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 +4555,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");
> +  }
> +

The curly braces need to be indented 2 spaces forward.

>    int first_sme_regnum = -1;
>    int first_sme2_regnum = -1;
>    int first_sme_pseudo_regnum = -1;
> @@ -4760,7 +4773,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..403743516df 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -207,6 +207,13 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>    {
>      return gcs_linux_reg_base != -1;
>    }

Missing blank line here.

> +  /* Index of FPMR. This is -1 if FPMR/FP8 is not supported. */

Missing two spaces after the two periods.

> +  int fpmr_regnum = -1;
> +
> +  bool has_fpmr () const

bool needs to be on its own line.

> +  {
> +    return fpmr_regnum != -1;
> +  }
>  };

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver on Linux
  2025-09-05 13:17 ` [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
  2025-09-07 22:55   ` Luis
@ 2025-09-10 23:46   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:46 UTC (permalink / raw)
  To: Ezra.Sitorus; +Cc: gdb-patches, luis.machado.foss

<Ezra.Sitorus@arm.com> writes:

> @@ -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) & (1UL << 48);

Here's the other spot to use HWCAP2_FPMR.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr
  2025-09-05 13:17 ` [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
  2025-09-07 22:56   ` Luis
@ 2025-09-10 23:47   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:47 UTC (permalink / raw)
  To: Ezra.Sitorus; +Cc: gdb-patches, luis.machado.foss

<Ezra.Sitorus@arm.com> writes:

> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Add support for FPMR in signal frames and restore contents of FPMR.
>
> Manually validated with Shrinkwrap (Arm FVP).
> ---
>  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 acb650db514..b4911d36410 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -168,6 +168,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
> @@ -214,6 +215,9 @@
>  /* features_enabled value offset in the GCS signal frame context.  */
>  #define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET	16
>  
> +/* FPMR constants. */

Missing double space after period.

> +#define AARCH64_FPMR_OFFSET			8
> +
>  /* Holds information about the signal frame.  */
>  struct aarch64_linux_sigframe
>  {
> @@ -261,6 +265,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
> @@ -577,6 +587,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)

This fits into one line.

> +	      {
> +		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
> @@ -740,6 +766,13 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
>  	}
>      }
>  
> +      /* Handle FPMR.  */

The indentation of this comment is off.

> +  if (tdep->has_fpmr () && signal_frame.fpmr_available != 0)
> +  {
> +    trad_frame_set_reg_value (this_cache, tdep->fpmr_regnum,
> +			      signal_frame.fpmr);
> +  }
> +

The curly braces need to be indented two spaces forward.

>    /* 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 ()
> @@ -792,6 +825,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);

I'll comment on this part in my answer to Luis.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR
  2025-09-05 13:17 ` [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
  2025-09-07 22:56   ` Luis
@ 2025-09-10 23:48   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:48 UTC (permalink / raw)
  To: Ezra.Sitorus; +Cc: gdb-patches, luis.machado.foss

<Ezra.Sitorus@arm.com> writes:

> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> Add support for FPMR dumps/reads for core files.
>
> Manually validated with Shrinkwrap (Arm FVP).
> ---
>  gdb/aarch64-linux-tdep.c | 67 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 67 insertions(+)
>
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index b4911d36410..731f05bae5a 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -1519,6 +1519,56 @@ 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)

The indentation of the arguments is missing 2 spaces.

> +{
> +  /* 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 ZT0 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)

The indentation of the arguments is missing 2 spaces.

> +{
> +  /* 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));

This fits in one line, no need to break it.

> +}
> +
>  /* Implement the "iterate_over_regset_sections" gdbarch method.  */
>  
>  static void
> @@ -1636,6 +1686,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.  */

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr
  2025-09-05 13:17 ` [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
  2025-09-07 22:56   ` Luis
@ 2025-09-10 23:53   ` Thiago Jung Bauermann
  1 sibling, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:53 UTC (permalink / raw)
  To: Ezra.Sitorus; +Cc: gdb-patches, luis.machado.foss

<Ezra.Sitorus@arm.com> writes:

> 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 and core file generation.
>
> For these tests, I have used shrinkwrap for FPMR emulation. I am not
> sure on how to do these tests properly as there are some things I'm not
> sure about:
>
> * Which board file do I use to test this? I've resorted to adapting
>   remote-stdio-gdbserver.exp to use tcp when starting gdbserver
>   remotely.
> * Do I need to run the whole regression test? This is quite slow, and
>   comes up with a lot of failures.
> * Since gdbserver doesn't support core files, I've had to adapt
>   core_find so that the core file is generated on target (where
>   gdbserver runs), but then it's copied over to host (where gdb runs) to
>   do the actual test. You can find this on aarch64-fpmr-core.exp
>   (remote_core_find). Please let me know if there's a better way of
>   doing this, or how I can improve the way I've done it.
> * Another issue with the core file test is that sometimes it says all
>   the tests pass, but there's 1 unexpected core file or that core files
>   can't be generated and I need to do ulimit -c unlimited, despite
>   having done that already.

If there's an unexpected core file, then either GDB or gdbserver
crashed.

Apart from the things Luis mentioned, another one that interferes with
core file tests is a system service that collects core files. On Ubuntu,
I disable the Apport systemd service.

> ---
>  gdb/testsuite/gdb.arch/aarch64-fpmr-core.c    | 109 +++++++++++++
>  gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp  | 143 ++++++++++++++++++
>  .../gdb.arch/aarch64-fpmr-sighandler.c        | 134 ++++++++++++++++
>  .../gdb.arch/aarch64-fpmr-sighandler.exp      |  75 +++++++++
>  gdb/testsuite/gdb.arch/aarch64-fpmr.c         | 117 ++++++++++++++
>  gdb/testsuite/gdb.arch/aarch64-fpmr.exp       | 116 ++++++++++++++
>  gdb/testsuite/lib/gdb.exp                     |  49 ++++++
>  7 files changed, 743 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..95c6f302ad7
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.c
> @@ -0,0 +1,109 @@
> +/* 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;
> +
> +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" : : );

It would be good to have a comment here mentioning to which instruction
the value above decodes to.

> 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..52acfd7291b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-fpmr-core.exp
> @@ -0,0 +1,143 @@
> +# 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 } {

Ideally, procedures should have documentation comments.

> +    # 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"
> +}
> +
> +proc remote_core_find {binfile {deletefiles {}} {arg ""}} {
> +    global objdir subdir REMOTE_TMPDIR
> +
> +    set target_binfile [gdbserver_download_current_prog]
> +
> +    set destcore "$target_binfile.core"
> +    remote_exec target delete $destcore
> +
> +    set found 0
> +    set coredir "${REMOTE_TMPDIR}/coredir.[getpid]"
> +    remote_exec target "mkdir $coredir"
> +    remote_exec target "(cd ${coredir}; ulimit -c unlimited; ${target_binfile} ${arg}; true) >/dev/null 2>&1"
> +    set binfile_basename [file tail $target_binfile]
> +    foreach i [list \
> +		   ${coredir}/core \
> +		   ${coredir}/core.coremaker.c \
> +		   ${coredir}/${binfile_basename}.core \
> +		   ${coredir}/${binfile_basename}.exe.core] {
> +	if [remote_file target exists $i] {
> +	    remote_exec target "mv $i $destcore"
> +	    set found 1
> +	}
> +    }
> +
> +    if { $found == 0 } {
> +	set names [glob -nocomplain -directory $coredir core.*]
> +	if {[llength $names] == 1} {
> +	    set corefile [file join $coredir [lindex $names 0]]
> +	    remote_exec target "mv $corefile $destcore"
> +	    set found 1
> +	}
> +    }
> +
> +    foreach deletefile $deletefiles {
> +	remote_file target delete [file join $coredir $deletefile]
> +    }
> +    remote_exec target "rmdir $coredir"
> +
> +    if { $found == 0  } {
> +	warning "can't generate a core file - core tests suppressed - check ulimit -c"
> +	return ""
> +    }
> +    set native_corefile "${binfile}.core"
> +    remote_download host [remote_upload target $destcore] $native_corefile
> +
> +    return $native_corefile
> +}
> +
> +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
> +}

Nowadays we don't return a value from the top level of the test, so just
"return" is enough.

> +
> +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 [remote_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 ${binfile}

I think that as of a few days ago this doesn't work anymore.
Now we use:

  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 ${binfile}
> +	with_test_prefix "native corefile" {
> +		check_fpmr_core_file $core_filename
> +	}
> +} else {
> +	untested "native corefile not generated"
> +}

<snip>

> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index ab4506a4455..a6961fb8719 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -5266,6 +5266,55 @@ 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 (".inst	0xd51b4440");

It would be good to have a comment mentioning which instruction the
value above decodes to.

Another option is to make the test program check AT_HWCAP instead of
trying to run an instruction. This is what proc allow_aarch64_gcs_tests
does. The advantage is consistency, since if the target machine is
running a kernel that doesn't report FPMR in AT_HWCAP, the test will
report that it is supported, but GDB will not recognize the feature.

Or would this program cause SIGILL if it's running on a processor
supporting this feature but with a kernel that doesn't? I don't know
actually.

> +	    return 0;
> +	}
> +    }
> +    if {![gdb_simple_compile $me $src executable $compile_flags]} {
> +        return 0
> +    }
> +
> +    # Compilation succeeded so now run it via gdb.
> +    clean_restart $obj
> +    gdb_run_cmd

There was a recent patch series standardising this sequence to:

  clean_restart
  gdb_load $obj
  gdb_run_cmd

to avoid passing absolute filenames to clean_restart.

> +    gdb_expect {
> +        -re ".*Illegal instruction.*${gdb_prompt} $" {
> +            verbose -log "\n$me fpmr not detected"
> +            set allow_fpmr_tests 0
> +        }
> +        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
> +            verbose -log "\n$me: fpmr hardware 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.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux
  2025-09-07 22:55   ` Luis
@ 2025-09-10 23:56     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-10 23:56 UTC (permalink / raw)
  To: Luis; +Cc: Ezra.Sitorus, gdb-patches

Luis <luis.machado.foss@gmail.com> writes:

> On 05/09/2025 14:17, Ezra.Sitorus@arm.com wrote:
>> index 679d845df74..731d4680248 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;
>>   }
>
> Do you also need to update the operator() to account for fpmr? It computes the hash of the
> feature based on what features are present.
>
> Unrelated, but looking at the code, it may be the case we missed adding gcs and gcs_linux
> to this operator.

You're right, I missed that one. I'll submit a patch fixing this.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr
  2025-09-07 22:56   ` Luis
@ 2025-09-11  0:03     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-11  0:03 UTC (permalink / raw)
  To: Luis; +Cc: Ezra.Sitorus, gdb-patches

Luis <luis.machado.foss@gmail.com> writes:

> On 05/09/2025 14:17, Ezra.Sitorus@arm.com wrote:
>> From: Ezra Sitorus <ezra.sitorus@arm.com>
>> Add support for FPMR in signal frames and restore contents of FPMR.
>> Manually validated with Shrinkwrap (Arm FVP).
>> ---
>>   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 acb650db514..b4911d36410 100644
>> --- a/gdb/aarch64-linux-tdep.c
>> +++ b/gdb/aarch64-linux-tdep.c
>> @@ -168,6 +168,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
>> @@ -214,6 +215,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
>>   {
>> @@ -261,6 +265,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
>> @@ -577,6 +587,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
>> @@ -740,6 +766,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 ()
>> @@ -792,6 +825,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;
>
> Unrelated, but looks like we're not handling gcs in aarch64_linux_sigframe_prev_arch. Is
> that something we need to do Thiago?

It isn't. This method is needed when gdbarch can change from one frame
to the next (or previous, rather). In the case of GCS, its state can be
enabled or disabled between consecutive frames, but in any case the GCS
feature will still be there because its presence only depends on whether
AT_HWCAP has the GCS bit set, which doesn't change at runtime.

From what I understood of this patch series, it looks like FPMR works
the same way so I think it also doesn't need this change in
aarch64_linux_sigframe_prev_arch either.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 0/5] gdb/aarch64: Support for FPMR
  2025-09-10 23:39 ` [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Thiago Jung Bauermann
@ 2025-09-11 15:52   ` Ezra Sitorus
  2025-09-12  3:17     ` Thiago Jung Bauermann
  0 siblings, 1 reply; 23+ messages in thread
From: Ezra Sitorus @ 2025-09-11 15:52 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches, luis.machado.foss

> Hello Ezra,

Hi!

> Thank you for these patches.
> 
> <Ezra.Sitorus@arm.com> writes:
> 
> > 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.
> >
> > This has been tested 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].
> 
> Is there something specific one has to do to enable FPMR on
> Shrinkwrap/FVP?
> 
> I tried building an Armv9.5 configuration:
> 
> $ shrinkwrap build --overlay=arch/v9.5.yaml ns-edk2.yaml
> 
> and then running it with upstream kernel v6.16-rc7 which I think should
> support FPMR, but AT_HWCAP doesn't have the FPMR bit set, and the test
> program from the allow_aarch64_fpmr_tests procedure gets a SIGILL so the
> testcases in this series report unsupported.
> 
> -- 
> Thiago

I think that kernel version is fine. To get FPMR to work, I created an overlay.yaml
file which contains this:

run:
  params:
    -C cluster0.has_fpmr: 1

Then I run with this:

shrinkwrap run ns-edk2.yaml --overlay overlay.yaml

FYI, if you want to enable other features, you can see the options by doing:

docker exec <docker container name> FVP_Base_RevC-2xAEMvA --list-params

Ezra

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 0/5] gdb/aarch64: Support for FPMR
  2025-09-11 15:52   ` Ezra Sitorus
@ 2025-09-12  3:17     ` Thiago Jung Bauermann
  0 siblings, 0 replies; 23+ messages in thread
From: Thiago Jung Bauermann @ 2025-09-12  3:17 UTC (permalink / raw)
  To: Ezra Sitorus; +Cc: gdb-patches, luis.machado.foss

Ezra Sitorus <ezra.sitorus@arm.com> writes:

>> Hello Ezra,
>
> Hi!
>
>> Thank you for these patches.
>> 
>> <Ezra.Sitorus@arm.com> writes:
>> 
>> > 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.
>> >
>> > This has been tested 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].
>> 
>> Is there something specific one has to do to enable FPMR on
>> Shrinkwrap/FVP?
>> 
>> I tried building an Armv9.5 configuration:
>> 
>> $ shrinkwrap build --overlay=arch/v9.5.yaml ns-edk2.yaml
>> 
>> and then running it with upstream kernel v6.16-rc7 which I think should
>> support FPMR, but AT_HWCAP doesn't have the FPMR bit set, and the test
>> program from the allow_aarch64_fpmr_tests procedure gets a SIGILL so the
>> testcases in this series report unsupported.
>> 
>> -- 
>> Thiago
>
> I think that kernel version is fine. To get FPMR to work, I created an overlay.yaml
> file which contains this:
>
> run:
>   params:
>     -C cluster0.has_fpmr: 1
>
> Then I run with this:
>
> shrinkwrap run ns-edk2.yaml --overlay overlay.yaml

Thanks! This worked.

> FYI, if you want to enable other features, you can see the options by doing:
>
> docker exec <docker container name> FVP_Base_RevC-2xAEMvA --list-params

This is very useful. Thanks for the tip.

-- 
Thiago

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr
  2025-09-07 22:56   ` Luis
@ 2025-09-16 11:09     ` Ezra Sitorus
  2025-09-16 23:50       ` Luis
  0 siblings, 1 reply; 23+ messages in thread
From: Ezra Sitorus @ 2025-09-16 11:09 UTC (permalink / raw)
  To: Luis; +Cc: gdb-patches, thiago.bauermann

Thanks for this - it's very helpful.

> Thanks for the patch.
> 
> On 05/09/2025 14:17, 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 and core file generation.
> > 
> > For these tests, I have used shrinkwrap for FPMR emulation. I am not
> > sure on how to do these tests properly as there are some things I'm not
> > sure about:
> > 
> > * Which board file do I use to test this? I've resorted to adapting
> >    remote-stdio-gdbserver.exp to use tcp when starting gdbserver
> >    remotely.
> 
> If you have Linux running on the FVP, you need to build gdb/gdbserver
> natively in there or cross-build aarch64-linux versions of gdb/gdbserver ,
> copy the binaries over and then invoke the testsuite like so:
> 
> make check-gdb RUNTESTFLAGS="--target_board=native-gdbserver"
> 
> You'll run gdb's testsuite against gdbserver inside the FVP. It will be
> fairly slow for sure, but that's unfortunately how it goes.

Why is it the case that we run gdb + gdbserver? I assume this is less demanding
than running gdb on its own?

> 
> If you want to exercise gdbserver in extended-remote mode, replace
> native-gdbserver with native-extended-gdbserver.
> 
> > * Do I need to run the whole regression test? This is quite slow, and
> >    comes up with a lot of failures.
> 
> It is a good idea to run the entire testsuite at least once to make sure
> things didn't break somewhere. If your change is aarch64-specific, it still
> makes sense to run the entire testsuite (maybe run it on a big server to see
> if things are still sane), but once you know the code is OK, you can then
> focus on the gdb.arch/*aarch64*.exp tests.
> 

Do you know roughly how long this takes? In my case, I've been running for 24
hours and it's still got a long way to go. Does changing to native-extended-gdbserver
speed things up?

On another note, I looked at the 'Testing gdbserver in a remote cross-target
configuration' section in the TestingGDB page in GDB Wiki. Would this be a
viable option? Unlike last time where I rewrote core_find for example, would
this help out as it delegates compiling to the build system (if I've understood
correctly)? Or should I just keep it simple with native-gdbserver/native-extended-gdbserver?

Ezra

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr
  2025-09-16 11:09     ` Ezra Sitorus
@ 2025-09-16 23:50       ` Luis
  0 siblings, 0 replies; 23+ messages in thread
From: Luis @ 2025-09-16 23:50 UTC (permalink / raw)
  To: Ezra Sitorus; +Cc: gdb-patches, thiago.bauermann

Hi,

On 16/09/2025 12:09, Ezra Sitorus wrote:
> Thanks for this - it's very helpful.
> 
>> Thanks for the patch.
>>
>> On 05/09/2025 14:17, 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 and core file generation.
>>>
>>> For these tests, I have used shrinkwrap for FPMR emulation. I am not
>>> sure on how to do these tests properly as there are some things I'm not
>>> sure about:
>>>
>>> * Which board file do I use to test this? I've resorted to adapting
>>>     remote-stdio-gdbserver.exp to use tcp when starting gdbserver
>>>     remotely.
>>
>> If you have Linux running on the FVP, you need to build gdb/gdbserver
>> natively in there or cross-build aarch64-linux versions of gdb/gdbserver ,
>> copy the binaries over and then invoke the testsuite like so:
>>
>> make check-gdb RUNTESTFLAGS="--target_board=native-gdbserver"
>>
>> You'll run gdb's testsuite against gdbserver inside the FVP. It will be
>> fairly slow for sure, but that's unfortunately how it goes.
> 
> Why is it the case that we run gdb + gdbserver? I assume this is less demanding
> than running gdb on its own?

I´d say testing native gdb is a bit lighter. Testing with gdbserver (or 
any remote target really) has a lot more overhead due to the serial 
protocol communication. Also potentially more file transfers between 
gdbserver and gdb.

> 
>>
>> If you want to exercise gdbserver in extended-remote mode, replace
>> native-gdbserver with native-extended-gdbserver.
>>
>>> * Do I need to run the whole regression test? This is quite slow, and
>>>     comes up with a lot of failures.
>>
>> It is a good idea to run the entire testsuite at least once to make sure
>> things didn't break somewhere. If your change is aarch64-specific, it still
>> makes sense to run the entire testsuite (maybe run it on a big server to see
>> if things are still sane), but once you know the code is OK, you can then
>> focus on the gdb.arch/*aarch64*.exp tests.
>>
> 
> Do you know roughly how long this takes? In my case, I've been running for 24
> hours and it's still got a long way to go. Does changing to native-extended-gdbserver
> speed things up?

My experience with QEMU is that it takes less than 24h to run the entire 
thing. But the FVP is slower than that, so I think a couple days or more 
sound reasonable.

Switching to native-extended-gdbserver won´t help unfortunately, as that 
is mostly a different remote target mode.

To speed things up, you could test gdb/gdbserver on a regular AArch64 
machine and then go do the gdb.arch/aarch64*.exp tests on the FVP. Given 
the FPMR changes are fairly localized, the risk of breaking things is low.

> 
> On another note, I looked at the 'Testing gdbserver in a remote cross-target
> configuration' section in the TestingGDB page in GDB Wiki. Would this be a
> viable option? Unlike last time where I rewrote core_find for example, would
> this help out as it delegates compiling to the build system (if I've understood
> correctly)? Or should I just keep it simple with native-gdbserver/native-extended-gdbserver?

Running gdb on the host and connecting to gdbserver on the target is 
definitely faster, but you need the board files to handle all the logic 
to spawn the emulator for each test (if in user mode) or spawn the 
emulator and connect to it and then spawn gdbserver for every test.

I don´t think we have such a board file. That's usually a custom 
implementation.

> 
> Ezra


^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2025-09-16 23:51 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-05 13:17 [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Ezra.Sitorus
2025-09-05 13:17 ` [RFC PATCH 1/5] gdb/aarch64: Enable FPMR for AArch64 in gdb on Linux Ezra.Sitorus
2025-09-07 22:55   ` Luis
2025-09-10 23:56     ` Thiago Jung Bauermann
2025-09-10 23:45   ` Thiago Jung Bauermann
2025-09-05 13:17 ` [RFC PATCH 2/5] gdbserver/aarch64: Enable FPMR for AArch64 in gdbserver " Ezra.Sitorus
2025-09-07 22:55   ` Luis
2025-09-10 23:46   ` Thiago Jung Bauermann
2025-09-05 13:17 ` [RFC PATCH 3/5] gdb/aarch64: signal frame support for fpmr Ezra.Sitorus
2025-09-07 22:56   ` Luis
2025-09-11  0:03     ` Thiago Jung Bauermann
2025-09-10 23:47   ` Thiago Jung Bauermann
2025-09-05 13:17 ` [RFC PATCH 4/5] gdb/aarch64: core file support for FPMR Ezra.Sitorus
2025-09-07 22:56   ` Luis
2025-09-10 23:48   ` Thiago Jung Bauermann
2025-09-05 13:17 ` [RFC PATCH 5/5] gdb/aarch64: Tests for fpmr Ezra.Sitorus
2025-09-07 22:56   ` Luis
2025-09-16 11:09     ` Ezra Sitorus
2025-09-16 23:50       ` Luis
2025-09-10 23:53   ` Thiago Jung Bauermann
2025-09-10 23:39 ` [RFC PATCH 0/5] gdb/aarch64: Support for FPMR Thiago Jung Bauermann
2025-09-11 15:52   ` Ezra Sitorus
2025-09-12  3:17     ` Thiago Jung Bauermann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox