Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register
@ 2026-06-17 17:00 srinath.parvathaneni
  2026-06-17 23:38 ` Ezra Sitorus
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: srinath.parvathaneni @ 2026-06-17 17:00 UTC (permalink / raw)
  To: gdb-patches
  Cc: guinevere, thiago.bauermann, luis.machado.foss, Srinath Parvathaneni

From: Srinath Parvathaneni <srinath.parvathaneni@arm.com>

Hi,

FEAT_S1POE introduces the POR_EL0 register. This patch adds
support for POR_EL0 in both native GDB and gdbserver using
NT_ARM_POE and HWCAP2_POE detection.

With this change, POR_EL0 is available through:
* info registers
* info registers por_el0
* p $por_el0
* p/x $por_el0

This patch also extends AArch64 SIGSEGV reporting for POE permission
faults. When a fault is reported with SEGV_PKUERR, GDB displays the
fault address together with the decoded POR_EL0 permissions associated
with the protection key that generated the fault and the current thread
ID.

Example:
Program received signal SIGSEGV, Segmentation fault
Protection overlay violation while accessing address 0x0000fffff7ff3000
POR_EL0[Protection-Key=1] = r-x (3) Thread Id = 1.
0x0000aaaaaaaa0990 in main () at aarch64-poe-sigsegv.c:49

The gdb.arch/aarch64-poe.exp testcase verifies POR_EL0 register
visibility and access. The gdb.arch/aarch64-poe-sigsegv.exp testcase
verifies POE-specific SIGSEGV reporting and is marked unsupported when
the required userspace or kernel support is not available.

The tests were run on Arm FVP with FEAT_S1POE support and a Linux
kernel built with CONFIG_ARM64_POE enabled.

Please note:
1. Support for "set $por_el0" is not included in this patch.
2. POR_EL0 write support will be addressed separately.

Regression tested on aarch64-none-linux-gnu target and found
no regressions.

Regards,
Srinath
---
 gdb/Makefile.in                               |  2 +
 gdb/aarch64-linux-nat.c                       | 35 ++++++++++
 gdb/aarch64-linux-tdep.c                      | 68 ++++++++++++++++++-
 gdb/aarch64-tdep.c                            | 15 ++++
 gdb/aarch64-tdep.h                            | 10 +++
 gdb/arch/aarch64-poe.h                        | 35 ++++++++++
 gdb/arch/aarch64.c                            |  4 ++
 gdb/arch/aarch64.h                            |  7 +-
 gdb/features/Makefile                         |  1 +
 gdb/features/aarch64-poe.c                    | 68 +++++++++++++++++++
 gdb/features/aarch64-poe.xml                  | 50 ++++++++++++++
 gdb/linux-tdep.c                              |  9 ++-
 gdb/nat/aarch64-poe.h                         | 49 +++++++++++++
 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c  | 52 ++++++++++++++
 .../gdb.arch/aarch64-poe-sigsegv.exp          | 51 ++++++++++++++
 gdb/testsuite/gdb.arch/aarch64-poe.c          | 29 ++++++++
 gdb/testsuite/gdb.arch/aarch64-poe.exp        | 44 ++++++++++++
 gdb/testsuite/lib/gdb.exp                     | 55 +++++++++++++++
 gdbserver/linux-aarch64-low.cc                | 20 ++++++
 19 files changed, 598 insertions(+), 6 deletions(-)
 create mode 100644 gdb/arch/aarch64-poe.h
 create mode 100644 gdb/features/aarch64-poe.c
 create mode 100644 gdb/features/aarch64-poe.xml
 create mode 100644 gdb/nat/aarch64-poe.h
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe.exp

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 57f384170ab..6cdc896d342 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1292,6 +1292,7 @@ HFILES_NO_SRCDIR = \
 	arch/aarch32.h \
 	arch/aarch64-fpmr-linux.h \
 	arch/aarch64-gcs-linux.h \
+	arch/aarch64-poe.h \
 	arch/aarch64.h \
 	arch/aarch64-insn.h \
 	arch/aarch64-mte.h \
@@ -1540,6 +1541,7 @@ HFILES_NO_SRCDIR = \
 	namespace.h \
 	nat/aarch64-fpmr-linux.h \
 	nat/aarch64-gcs-linux.h \
+	nat/aarch64-poe.h \
 	nat/aarch64-hw-point.h \
 	nat/aarch64-linux.h \
 	nat/aarch64-linux-hw-point.h \
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 52ace4aab41..181f3596481 100644
--- a/gdb/aarch64-linux-nat.c
+++ b/gdb/aarch64-linux-nat.c
@@ -34,6 +34,7 @@
 #include "arch/arm.h"
 #include "nat/aarch64-fpmr-linux.h"
 #include "nat/aarch64-gcs-linux.h"
+#include "nat/aarch64-poe.h"
 #include "nat/aarch64-linux.h"
 #include "nat/aarch64-linux-hw-point.h"
 #include "nat/aarch64-mte-linux-ptrace.h"
@@ -569,6 +570,30 @@ fetch_gcsregs_from_thread (regcache *regcache)
 			&user_gcs.features_locked);
 }
 
+/* Fill GDB's register array with the POE register value from the current
+   thread.  */
+
+static void
+fetch_por_el0_from_thread (regcache *regcache)
+{
+  aarch64_gdbarch_tdep *tdep
+    = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+  gdb_assert (tdep->poe_regnum != -1);
+
+  user_poe user_poe;
+  iovec iovec;
+
+  iovec.iov_base = &user_poe;
+  iovec.iov_len = sizeof (user_poe);
+
+  int tid = get_ptrace_pid (regcache->ptid ());
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_POE, &iovec) != 0)
+    perror_with_name (_("Unable to fetch POE register"));
+
+  regcache->raw_supply (tdep->poe_regnum, &user_poe.por_el0);
+}
+
 /* Store to the current thread the valid GCS register set in the GDB's
    register array.  */
 
@@ -683,6 +708,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
       if (tdep->has_gcs_linux ())
 	fetch_gcsregs_from_thread (regcache);
 
+      if (tdep->has_poe ())
+	fetch_por_el0_from_thread (regcache);
+
       if (tdep->has_fpmr ())
 	fetch_fpmr_from_thread (regcache);
     }
@@ -722,6 +750,10 @@ 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);
+  /* POE register?  */
+  else if (tdep->has_poe () && (regno == tdep->poe_regnum))
+    fetch_por_el0_from_thread (regcache);
+
   /* FPMR?  */
   else if (tdep->has_fpmr () && (regno == tdep->fpmr_regnum))
     fetch_fpmr_from_thread (regcache);
@@ -1024,6 +1056,9 @@ aarch64_linux_nat_target::read_description ()
   /* Check for FPMR.  */
   features.fpmr = hwcap2 & HWCAP2_FPMR;
 
+  /* Check for POE support.  */
+  features.poe = hwcap2 & HWCAP2_POE;
+
   return aarch64_read_description (features);
 }
 
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index f11eccc1bc1..be6ef8db526 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -53,6 +53,7 @@
 
 #include "arch/aarch64-fpmr-linux.h"
 #include "arch/aarch64-gcs-linux.h"
+#include "arch/aarch64-poe.h"
 #include "arch/aarch64-mte.h"
 #include "arch/aarch64-mte-linux.h"
 #include "arch/aarch64-pauth-linux.h"
@@ -66,6 +67,7 @@
 #include "elf/common.h"
 #include "elf/aarch64.h"
 #include "arch/aarch64-insn.h"
+#include "gdbthread.h"
 
 /* For std::pow */
 #include <cmath>
@@ -274,6 +276,31 @@ struct aarch64_linux_sigframe
 
 };
 
+/* Convert a POR_EL0 Perm<m> overlay permission encoding into rwx-style string.
+   For example:
+     0b0011 -> "r-x" (3)
+     0b0101 -> "rw-" (5)
+     0b0111 -> "rwx" (7)
+     0b0000 -> "---" (0)
+   Reserved encodings (0b1xxx) are returned as "???".  */
+
+static const char*
+aarch64_perm_overlay_decode (unsigned int perm)
+{
+  switch (perm)
+   {
+     case 0: return "---";
+     case 1: return "r--";
+     case 2: return "--x";
+     case 3: return "r-x";
+     case 4: return "-w-";
+     case 5: return "rw-";
+     case 6: return "-wx";
+     case 7: return "rwx";
+     default: return "???";
+   }
+}
+
 /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
    size, or return 0 on error.  */
 
@@ -2675,11 +2702,12 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
 {
   aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
 
-  if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != GDB_SIGNAL_SEGV)
+  if (!(tdep->has_mte () || tdep->has_gcs () || tdep->has_poe ())
+      || siggnal != GDB_SIGNAL_SEGV)
     return;
 
   CORE_ADDR fault_addr = 0;
-  long si_code = 0, si_errno = 0;
+  long si_code = 0, si_errno = 0, si_pkey = -1;
 
   try
     {
@@ -2687,6 +2715,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
 	 violation.  */
       si_code = parse_and_eval_long ("$_siginfo.si_code");
       si_errno = parse_and_eval_long ("$_siginfo.si_errno");
+      if (tdep->has_poe ())
+	si_pkey = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_pkey");
 
       fault_addr
 	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
@@ -2703,6 +2733,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
     meaning = _("Memory tag violation");
   else if (si_code == AARCH64_SEGV_CPERR && si_errno == 0)
     meaning = _("Guarded Control Stack error");
+  else if (si_code == AARCH64_SEGV_PKUERR && si_errno == 0)
+    meaning = _("Protection overlay violation");
   else
     return;
 
@@ -2734,6 +2766,36 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
 	  uiout->field_string ("logical-tag", hex_string (ltag));
 	}
     }
+  /* For POE SEGSEGV, show additional information.  */
+  else if (si_code == AARCH64_SEGV_PKUERR)
+    {
+      frame_info_ptr frame = get_selected_frame (nullptr);
+      value *v = value_of_register (tdep->poe_regnum, frame);
+      ULONGEST por_el0 = (ULONGEST) value_as_long (v);
+      unsigned int perm = (por_el0 >> (si_pkey * 4)) & 0xf;
+
+      uiout->text (_(" while accessing address "));
+      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
+      uiout->text ("\n");
+
+      /* In the case of a SIGSEGV, print the POR_EL0[si_pkey] permission
+	 associated with the faulting address as an rwx-style permission
+	string, followed by its decimal value in parentheses and the
+	current thread ID.
+
+	e.g. POR_EL0[Protection-Key=1] = r-x (3) Thread Id = 1.  */
+
+      uiout->text (_("POR_EL0[Protection-Key="));
+      uiout->field_signed ("protection-key", si_pkey);
+      uiout->text (_("] = "));
+      uiout->text (aarch64_perm_overlay_decode (perm));
+      uiout->text (" (");
+      uiout->field_unsigned ("por-el0-permission", perm);
+      uiout->text (")");
+      thread_info *thr = inferior_thread ();
+      uiout->text (" Thread Id = ");
+      uiout->field_signed ("thread-id", thr->global_num);
+    }
   else if (si_code != AARCH64_SEGV_CPERR)
     {
       uiout->text ("\n");
@@ -3054,7 +3116,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 					 aarch64_linux_decode_memtag_section);
     }
 
-  if (tdep->has_mte () || tdep->has_gcs ())
+  if (tdep->has_mte () || tdep->has_gcs () || tdep->has_poe ())
     set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info);
 
   /* Initialize the aarch64_linux_record_tdep.  */
diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 886e7ce1e7b..23bca26ce43 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -4136,6 +4136,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
   features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
 		   != nullptr);
 
+  /* Check for POE feature.  */
+  features.poe = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe")
+		   != nullptr);
+
   return features;
 }
 
@@ -4556,6 +4560,16 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 					  fpmr_regnum, "fpmr");
     }
 
+  int poe_regnum = -1;
+  const struct tdesc_feature *feature_poe
+      = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe");
+  if (feature_poe != nullptr)
+    {
+      poe_regnum = num_regs++;
+      valid_p &= tdesc_numbered_register (feature_poe, tdesc_data.get (),
+					  poe_regnum, "por_el0");
+    }
+
   int first_sme_regnum = -1;
   int first_sme2_regnum = -1;
   int first_sme_pseudo_regnum = -1;
@@ -4755,6 +4769,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->tls_register_count = tls_register_count;
   tdep->gcs_reg_base = first_gcs_regnum;
   tdep->gcs_linux_reg_base = first_gcs_linux_regnum;
+  tdep->poe_regnum = poe_regnum;
   tdep->fpmr_regnum = fpmr_regnum;
 
   /* Set the SME register set details.  The pseudo-registers will be adjusted
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index dff05a08f84..3b959132ca6 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -208,6 +208,16 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
     return gcs_linux_reg_base != -1;
   }
 
+  /* First POE register.  This is -1 if no POE feature is available.  */
+  int poe_regnum = -1;
+
+  /* Returns true if the target supports the Linux POE feature.  */
+  bool
+  has_poe () const
+  {
+    return poe_regnum != -1;
+  }
+
   /* First FPMR register.  This is -1 if FPMR is not supported.  */
   int fpmr_regnum = -1;
 
diff --git a/gdb/arch/aarch64-poe.h b/gdb/arch/aarch64-poe.h
new file mode 100644
index 00000000000..1f2ac5c0cd2
--- /dev/null
+++ b/gdb/arch/aarch64-poe.h
@@ -0,0 +1,35 @@
+/* Common Linux target-dependent definitions for AArch64 POE
+
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_ARCH_AARCH64_POE_H
+#define GDB_ARCH_AARCH64_POE_H
+
+/* Feature check for Permission Overlay Extension.  */
+#ifndef HWCAP2_POE
+#define AARCH64_HWCAP2_POE (1ULL << 63)
+#endif
+
+#ifndef AARCH64_SEGV_PKUERR
+#define AARCH64_SEGV_PKUERR 4  /* Protection overlay violation.  */
+#endif
+
+/* The POE regset consists of 1 64-bit register.  */
+#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)
+
+#endif /* GDB_ARCH_AARCH64_POE_H */
diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
index 2401a325b7b..a567938d06d 100644
--- a/gdb/arch/aarch64.c
+++ b/gdb/arch/aarch64.c
@@ -28,6 +28,7 @@
 #include "../features/aarch64-sme2.c"
 #include "../features/aarch64-tls.c"
 #include "../features/aarch64-gcs.c"
+#include "../features/aarch64-poe.c"
 #include "../features/aarch64-gcs-linux.c"
 
 /* See arch/aarch64.h.  */
@@ -77,6 +78,9 @@ aarch64_create_target_description (const aarch64_features &features)
   if (features.fpmr)
     regnum = create_feature_aarch64_fpmr (tdesc.get (), regnum);
 
+  if (features.poe)
+    regnum = create_feature_aarch64_poe (tdesc.get (), regnum);
+
   return tdesc;
 }
 
diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
index cf7318cbe74..4e4b50f729e 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -35,6 +35,7 @@ struct aarch64_features
   bool pauth = false;
   bool mte = false;
   bool fpmr = false;
+  bool poe = false;
 
   /* A positive TLS value indicates the number of TLS registers available.  */
   uint8_t tls = 0;
@@ -70,7 +71,8 @@ inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
     && lhs.sme2 == rhs.sme2
     && lhs.gcs == rhs.gcs
     && lhs.gcs_linux == rhs.gcs_linux
-    && lhs.fpmr == rhs.fpmr;
+    && lhs.fpmr == rhs.fpmr
+    && lhs.poe == rhs.poe;
 }
 
 namespace std
@@ -103,6 +105,9 @@ namespace std
 
       /* FPMR feature.  */
       h = h << 1 | features.fpmr;
+
+      /* POE feature.  */
+      h = h << 1 | features.poe;
       return h;
     }
   };
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 161a7453d66..cc77e5bb652 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -207,6 +207,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
 	aarch64-pauth.xml \
 	aarch64-mte.xml \
 	aarch64-gcs.xml \
+	aarch64-poe.xml \
 	aarch64-gcs-linux.xml \
 	arc/v1-core.xml \
 	arc/v1-aux.xml \
diff --git a/gdb/features/aarch64-poe.c b/gdb/features/aarch64-poe.c
new file mode 100644
index 00000000000..6892b52c1cf
--- /dev/null
+++ b/gdb/features/aarch64-poe.c
@@ -0,0 +1,68 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: aarch64-poe.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_aarch64_poe (struct target_desc *result, long regnum)
+{
+  struct tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.poe");
+  tdesc_type_with_fields *type_with_fields;
+  type_with_fields = tdesc_create_enum (feature, "por_el0_fmt", 4);
+  tdesc_add_enum_value (type_with_fields, 0, "---");
+  tdesc_add_enum_value (type_with_fields, 1, "r--");
+  tdesc_add_enum_value (type_with_fields, 2, "--x");
+  tdesc_add_enum_value (type_with_fields, 3, "r-x");
+  tdesc_add_enum_value (type_with_fields, 4, "-w-");
+  tdesc_add_enum_value (type_with_fields, 5, "rw-");
+  tdesc_add_enum_value (type_with_fields, 6, "-wx");
+  tdesc_add_enum_value (type_with_fields, 7, "rwx");
+  tdesc_add_enum_value (type_with_fields, 8, "???");
+  tdesc_add_enum_value (type_with_fields, 9, "???");
+  tdesc_add_enum_value (type_with_fields, 10, "???");
+  tdesc_add_enum_value (type_with_fields, 11, "???");
+  tdesc_add_enum_value (type_with_fields, 12, "???");
+  tdesc_add_enum_value (type_with_fields, 13, "???");
+  tdesc_add_enum_value (type_with_fields, 14, "???");
+  tdesc_add_enum_value (type_with_fields, 15, "???");
+
+  type_with_fields = tdesc_create_flags (feature, "por_el0_flags", 8);
+  tdesc_type *field_type;
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "Pf", 60, 63, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "Pe", 56, 59, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "Pd", 52, 55, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "Pc", 48, 51, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "Pb", 44, 47, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "Pa", 40, 43, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P9", 36, 39, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P8", 32, 35, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P7", 28, 31, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P6", 24, 27, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P5", 20, 23, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P4", 16, 19, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P3", 12, 15, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P2", 8, 11, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P1", 4, 7, field_type);
+  field_type = tdesc_named_type (feature, "por_el0_fmt");
+  tdesc_add_typed_bitfield (type_with_fields, "P0", 0, 3, field_type);
+
+  tdesc_create_reg (feature, "por_el0", regnum++, 1, "system", 64, "por_el0_flags");
+  return regnum;
+}
diff --git a/gdb/features/aarch64-poe.xml b/gdb/features/aarch64-poe.xml
new file mode 100644
index 00000000000..e415a0f6bb6
--- /dev/null
+++ b/gdb/features/aarch64-poe.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2026 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.aarch64.poe">
+
+  <enum id="por_el0_fmt" size="4">
+    <evalue name="---" value="0"/>
+    <evalue name="r--" value="1"/>
+    <evalue name="--x" value="2"/>
+    <evalue name="r-x" value="3"/>
+    <evalue name="-w-" value="4"/>
+    <evalue name="rw-" value="5"/>
+    <evalue name="-wx" value="6"/>
+    <evalue name="rwx" value="7"/>
+    <evalue name="???" value="8"/>
+    <evalue name="???" value="9"/>
+    <evalue name="???" value="10"/>
+    <evalue name="???" value="11"/>
+    <evalue name="???" value="12"/>
+    <evalue name="???" value="13"/>
+    <evalue name="???" value="14"/>
+    <evalue name="???" value="15"/>
+  </enum>
+
+  <flags id="por_el0_flags" size="8">
+    <field name="Pf" start="60" end="63" type="por_el0_fmt"/>
+    <field name="Pe" start="56" end="59" type="por_el0_fmt"/>
+    <field name="Pd" start="52" end="55" type="por_el0_fmt"/>
+    <field name="Pc" start="48" end="51" type="por_el0_fmt"/>
+    <field name="Pb" start="44" end="47" type="por_el0_fmt"/>
+    <field name="Pa" start="40" end="43" type="por_el0_fmt"/>
+    <field name="P9" start="36" end="39" type="por_el0_fmt"/>
+    <field name="P8" start="32" end="35" type="por_el0_fmt"/>
+    <field name="P7" start="28" end="31" type="por_el0_fmt"/>
+    <field name="P6" start="24" end="27" type="por_el0_fmt"/>
+    <field name="P5" start="20" end="23" type="por_el0_fmt"/>
+    <field name="P4" start="16" end="19" type="por_el0_fmt"/>
+    <field name="P3" start="12" end="15" type="por_el0_fmt"/>
+    <field name="P2" start="8" end="11" type="por_el0_fmt"/>
+    <field name="P1" start="4" end="7" type="por_el0_fmt"/>
+    <field name="P0" start="0" end="3" type="por_el0_fmt"/>
+  </flags>
+
+  <reg name="por_el0" bitsize="64" type="por_el0_flags" group="system"/>
+</feature>
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index a7381677498..44236ebe86e 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -366,8 +366,13 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
 
   /* _sigfault */
   type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
-  append_composite_type_field (type, "si_addr", void_ptr_type);
-  append_composite_type_field (sifields_type, "_sigfault", type);
+   {
+     int size_of_ptr = gdbarch_ptr_bit (gdbarch) / HOST_CHAR_BIT;
+     append_composite_type_field (type, "si_addr", void_ptr_type);
+     append_composite_type_field (type, "_pad", init_vector_type (builtin_type (gdbarch)->builtin_char, size_of_ptr));
+     append_composite_type_field (type, "si_pkey", builtin_type (gdbarch)->builtin_uint32);
+     append_composite_type_field (sifields_type, "_sigfault", type);
+   }
 
   /* _sigpoll */
   type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
diff --git a/gdb/nat/aarch64-poe.h b/gdb/nat/aarch64-poe.h
new file mode 100644
index 00000000000..3221634fd25
--- /dev/null
+++ b/gdb/nat/aarch64-poe.h
@@ -0,0 +1,49 @@
+/* Common native Linux definitions for AArch64 Permission Overlay Extension.
+
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_NAT_AARCH64_POE_H
+#define GDB_NAT_AARCH64_POE_H
+
+#include <stdint.h>
+#include <asm/hwcap.h>
+#include <asm/ptrace.h>
+
+/* Feature check for Permission Overlay Extension.  */
+#ifndef HWCAP2_POE
+#define HWCAP2_POE (1ULL << 63)
+#endif
+
+#ifndef HAVE_STRUCT_USER_POE
+
+/* POE state (NT_ARM_POE).  */
+#ifndef NT_ARM_POE
+#define NT_ARM_POE 0x40f
+#endif
+
+struct user_poe
+{
+  uint64_t por_el0;
+};
+
+#endif /* HAVE_STRUCT_USER_POE */
+
+/* The POE regset consists of 1 64-bit register.  */
+#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)
+
+#endif /* GDB_NAT_AARCH64_POE_H */
diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
new file mode 100644
index 00000000000..6b0c07e782f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
@@ -0,0 +1,52 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2026 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 AArch64's POE Extension.  */
+
+/* This test is based on the Linux kernel documentation for Memory
+   Protection Keys, including the arm64 Permission Overlay Extension
+   (FEAT_S1POE) support described in
+   Documentation/core-api/protection-keys.rst.  */
+
+#define _GNU_SOURCE
+#include <sys/mman.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+  long pagesize = sysconf (_SC_PAGESIZE);
+
+  int *buf = mmap (NULL, pagesize, PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (buf == MAP_FAILED)
+    return 1;
+
+  int pkey = pkey_alloc (0, 0);
+  if (pkey == -1)
+    return 1;
+
+  if (pkey_mprotect (buf, pagesize, PROT_READ | PROT_WRITE, pkey) == -1)
+    return 1;
+
+  if (pkey_set (pkey, PKEY_DISABLE_WRITE) == -1)
+    return 1;
+
+  buf[0] = 42;  /* Expect SIGSEGV POE violation.  */
+
+  return 1;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
new file mode 100644
index 00000000000..dfd91f652f0
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
@@ -0,0 +1,51 @@
+# Copyright (C) 2026 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/>.
+
+# Test a binary that uses POE and exposed POR_EL0 register.
+
+global hex
+global decimal
+
+require is_aarch64_target
+
+if {![allow_aarch64_poe_tests]} {
+    unsupported "AArch64 POE not supported"
+    return
+}
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+    return
+}
+
+if {![runto_main]} {
+    return
+}
+
+# Display POE violation SIGSEGV error message.
+set poe_sigsegv_re [multi_line \
+    "Program received signal SIGSEGV, Segmentation fault" \
+    "Protection overlay violation while accessing address ${hex}" \
+    "POR_EL0\\\[Protection-Key=${decimal}\\\] = \[-rwx\]+ \\(${decimal}\\) Thread Id = ${decimal}"]
+
+gdb_test_multiple "continue" "display POE violation information" {
+    -re "$poe_sigsegv_re.*$gdb_prompt $" {
+	pass $gdb_test_name
+    }
+
+    -re ".*exited with code 01.*$gdb_prompt $" {
+	unsupported "POE userspace support unavailable"
+    }
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-poe.c b/gdb/testsuite/gdb.arch/aarch64-poe.c
new file mode 100644
index 00000000000..2c95dc2a99b
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe.c
@@ -0,0 +1,29 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2026 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 AArch64's POE Extension.  */
+
+/* This test is based on the Linux kernel documentation for Memory
+   Protection Keys, including the arm64 Permission Overlay Extension
+   (FEAT_S1POE) support described in
+   Documentation/core-api/protection-keys.rst.  */
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-poe.exp b/gdb/testsuite/gdb.arch/aarch64-poe.exp
new file mode 100644
index 00000000000..ae2663a7dbc
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe.exp
@@ -0,0 +1,44 @@
+# Copyright (C) 2026 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/>.
+
+# Test a binary that uses POE and exposed POR_EL0 register.
+
+global hex
+global decimal
+
+require is_aarch64_target
+
+if {![allow_aarch64_poe_tests]} {
+    unsupported "AArch64 POE not supported"
+    return
+}
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+    return
+}
+
+if {![runto_main]} {
+    return
+}
+
+# Validate the presence of the POE register.
+    gdb_test "info registers por_el0" \
+	     "por_el0\[ \t\]+$hex.*" \
+	     "register por_el0 available"
+
+    gdb_test "p/x \$por_el0" \
+	     "\\$\[0-9\]+ = ${hex}" \
+	     "print por_el0"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 7b1feeaac84..fe2c533791c 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5616,6 +5616,61 @@ gdb_caching_proc allow_aarch64_gcs_tests {} {
     return $allow_gcs_tests
 }
 
+# Run a test on the target to see if it supports AArch64 POE extensions.
+# Return 1 if so, 0 if it does not.  Note this causes a restart of GDB.
+
+gdb_caching_proc allow_aarch64_poe_tests {} {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "allow_aarch64_poe_tests"
+
+    if { ![is_aarch64_target]} {
+	return 0
+    }
+
+    # Compile a program that tests the POE feature.
+    set src {
+	#include <stdbool.h>
+	#include <sys/auxv.h>
+
+	/* Feature check for POE feature.  */
+	#ifndef HWCAP2_POE
+	#define HWCAP2_POE (1ULL << 63)
+	#endif
+
+	int main (void) {
+	    bool poe_supported = getauxval (AT_HWCAP2) & HWCAP2_POE;
+
+	    /* Return success if POE is supported.  */
+	    return !poe_supported;
+	}
+    }
+
+    if {![gdb_simple_compile $me $src executable]} {
+	return 0
+    }
+
+    # Compilation succeeded so now run it via gdb.
+    set allow_poe_tests 0
+    clean_restart
+    gdb_load $obj
+    gdb_run_cmd
+    gdb_expect {
+	-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+	    verbose -log "\n$me: poe support detected"
+	    set allow_poe_tests 1
+	}
+	-re ".*$inferior_exited_re with code 01.*${gdb_prompt} $" {
+	    verbose -log "\n$me: poe support not detected"
+	}
+    }
+    gdb_exit
+    remote_file build delete $obj
+
+    verbose "$me:  returning $allow_poe_tests" 2
+    return $allow_poe_tests
+}
+
 # A helper that compiles a test case to see if __int128 is supported.
 proc gdb_int128_helper {lang} {
     return [gdb_can_simple_compile "i128-for-$lang" {
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index a2588a6e2a9..c27525be1ac 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -45,6 +45,7 @@
 #include "linux-aarch32-tdesc.h"
 #include "linux-aarch64-tdesc.h"
 #include "nat/aarch64-fpmr-linux.h"
+#include "nat/aarch64-poe.h"
 #include "nat/aarch64-gcs-linux.h"
 #include "nat/aarch64-mte-linux-ptrace.h"
 #include "nat/aarch64-scalable-linux-ptrace.h"
@@ -250,6 +251,16 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
   supply_register (regcache, AARCH64_FPCR_REGNUM, &regset->fpcr);
 }
 
+/* Store the POE (POR_EL0) register set to regcache.  */
+
+static void
+aarch64_store_por_el0_regset (struct regcache *regcache, const void *buf)
+{
+  const user_poe *regset = (const user_poe *) buf;
+  int poe_regnum  = find_regno (regcache->tdesc, "por_el0");
+  supply_register (regcache, poe_regnum, &regset->por_el0);
+}
+
 /* Fill BUF with the FPMR register set from the regcache.  */
 
 static void
@@ -901,6 +912,10 @@ static struct regset_info aarch64_regsets[] =
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_FPMR,
     0, OPTIONAL_REGS,
     aarch64_fill_fpmr_regset, aarch64_store_fpmr_regset },
+  /* POE register (POR_EL0).  */
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_POE,
+    0, OPTIONAL_REGS,
+    nullptr, aarch64_store_por_el0_regset },
   /* TLS register.  */
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
     0, OPTIONAL_REGS,
@@ -980,6 +995,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
 	  if (features.fpmr)
 	    regset->size = sizeof (uint64_t);
 	  break;
+	case NT_ARM_POE:
+	  if (features.poe)
+	    regset->size = sizeof (user_poe);
+	  break;
 	default:
 	  gdb_assert_not_reached ("Unknown register set found.");
 	}
@@ -1010,6 +1029,7 @@ aarch64_target::low_arch_setup ()
       features.tls = aarch64_tls_register_count (tid);
       features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) & HWCAP_GCS;
       features.fpmr = linux_get_hwcap2 (pid, 8) & HWCAP2_FPMR;
+      features.poe = linux_get_hwcap2 (pid, 8) & HWCAP2_POE;
 
       /* Scalable Matrix Extension feature and size check.  */
       if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
-- 
2.43.0


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

* Re: [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register
  2026-06-17 17:00 [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register srinath.parvathaneni
@ 2026-06-17 23:38 ` Ezra Sitorus
  2026-06-18 17:04 ` Matthieu Longo
  2026-06-21 11:50 ` Luis
  2 siblings, 0 replies; 5+ messages in thread
From: Ezra Sitorus @ 2026-06-17 23:38 UTC (permalink / raw)
  To: srinath.parvathaneni
  Cc: gdb-patches, guinevere, thiago.bauermann, luis.machado.foss

On the whole it looks OK, these are just some observations from me.  I haven't
tested it yet, I can do so later.  Also, I can't give the final approval.

On Wed, Jun 17, 2026 at 05:00:03PM +0000, srinath.parvathaneni@arm.com wrote:
> From: Srinath Parvathaneni <srinath.parvathaneni@arm.com>
> 
> Hi,
> 
> FEAT_S1POE introduces the POR_EL0 register. This patch adds
> support for POR_EL0 in both native GDB and gdbserver using
> NT_ARM_POE and HWCAP2_POE detection.
> 
> With this change, POR_EL0 is available through:
> * info registers
> * info registers por_el0
> * p $por_el0
> * p/x $por_el0
> 
> This patch also extends AArch64 SIGSEGV reporting for POE permission
> faults. When a fault is reported with SEGV_PKUERR, GDB displays the
> fault address together with the decoded POR_EL0 permissions associated
> with the protection key that generated the fault and the current thread
> ID.
> 
> Example:
> Program received signal SIGSEGV, Segmentation fault
> Protection overlay violation while accessing address 0x0000fffff7ff3000
> POR_EL0[Protection-Key=1] = r-x (3) Thread Id = 1.
> 0x0000aaaaaaaa0990 in main () at aarch64-poe-sigsegv.c:49
> 
> The gdb.arch/aarch64-poe.exp testcase verifies POR_EL0 register
> visibility and access. The gdb.arch/aarch64-poe-sigsegv.exp testcase
> verifies POE-specific SIGSEGV reporting and is marked unsupported when
> the required userspace or kernel support is not available.
> 
> The tests were run on Arm FVP with FEAT_S1POE support and a Linux
> kernel built with CONFIG_ARM64_POE enabled.
> 
> Please note:
> 1. Support for "set $por_el0" is not included in this patch.
> 2. POR_EL0 write support will be addressed separately.
> 
> Regression tested on aarch64-none-linux-gnu target and found
> no regressions.
> 
> Regards,
> Srinath
> ---
>  gdb/Makefile.in                               |  2 +
>  gdb/aarch64-linux-nat.c                       | 35 ++++++++++
>  gdb/aarch64-linux-tdep.c                      | 68 ++++++++++++++++++-
>  gdb/aarch64-tdep.c                            | 15 ++++
>  gdb/aarch64-tdep.h                            | 10 +++
>  gdb/arch/aarch64-poe.h                        | 35 ++++++++++
>  gdb/arch/aarch64.c                            |  4 ++
>  gdb/arch/aarch64.h                            |  7 +-
>  gdb/features/Makefile                         |  1 +
>  gdb/features/aarch64-poe.c                    | 68 +++++++++++++++++++
>  gdb/features/aarch64-poe.xml                  | 50 ++++++++++++++
>  gdb/linux-tdep.c                              |  9 ++-
>  gdb/nat/aarch64-poe.h                         | 49 +++++++++++++
>  gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c  | 52 ++++++++++++++
>  .../gdb.arch/aarch64-poe-sigsegv.exp          | 51 ++++++++++++++
>  gdb/testsuite/gdb.arch/aarch64-poe.c          | 29 ++++++++
>  gdb/testsuite/gdb.arch/aarch64-poe.exp        | 44 ++++++++++++
>  gdb/testsuite/lib/gdb.exp                     | 55 +++++++++++++++
>  gdbserver/linux-aarch64-low.cc                | 20 ++++++
>  19 files changed, 598 insertions(+), 6 deletions(-)
>  create mode 100644 gdb/arch/aarch64-poe.h
>  create mode 100644 gdb/features/aarch64-poe.c
>  create mode 100644 gdb/features/aarch64-poe.xml
>  create mode 100644 gdb/nat/aarch64-poe.h
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe.c
>  create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe.exp
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 57f384170ab..6cdc896d342 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1292,6 +1292,7 @@ HFILES_NO_SRCDIR = \
>  	arch/aarch32.h \
>  	arch/aarch64-fpmr-linux.h \
>  	arch/aarch64-gcs-linux.h \
> +	arch/aarch64-poe.h \
>  	arch/aarch64.h \
>  	arch/aarch64-insn.h \
>  	arch/aarch64-mte.h \
> @@ -1540,6 +1541,7 @@ HFILES_NO_SRCDIR = \
>  	namespace.h \
>  	nat/aarch64-fpmr-linux.h \
>  	nat/aarch64-gcs-linux.h \
> +	nat/aarch64-poe.h \
>  	nat/aarch64-hw-point.h \
>  	nat/aarch64-linux.h \
>  	nat/aarch64-linux-hw-point.h \
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index 52ace4aab41..181f3596481 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -34,6 +34,7 @@
>  #include "arch/arm.h"
>  #include "nat/aarch64-fpmr-linux.h"
>  #include "nat/aarch64-gcs-linux.h"
> +#include "nat/aarch64-poe.h"
>  #include "nat/aarch64-linux.h"
>  #include "nat/aarch64-linux-hw-point.h"
>  #include "nat/aarch64-mte-linux-ptrace.h"
> @@ -569,6 +570,30 @@ fetch_gcsregs_from_thread (regcache *regcache)
>  			&user_gcs.features_locked);
>  }
>  
> +/* Fill GDB's register array with the POE register value from the current
> +   thread.  */
> +
> +static void
> +fetch_por_el0_from_thread (regcache *regcache)
> +{
> +  aarch64_gdbarch_tdep *tdep
> +    = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> +
> +  gdb_assert (tdep->poe_regnum != -1);
> +
> +  user_poe user_poe;
> +  iovec iovec;
> +
> +  iovec.iov_base = &user_poe;
> +  iovec.iov_len = sizeof (user_poe);
> +
> +  int tid = get_ptrace_pid (regcache->ptid ());
> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_POE, &iovec) != 0)
> +    perror_with_name (_("Unable to fetch POE register"));
> +
> +  regcache->raw_supply (tdep->poe_regnum, &user_poe.por_el0);
> +}
> +
>  /* Store to the current thread the valid GCS register set in the GDB's
>     register array.  */
>  
> @@ -683,6 +708,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
>        if (tdep->has_gcs_linux ())
>  	fetch_gcsregs_from_thread (regcache);
>  
> +      if (tdep->has_poe ())
> +	fetch_por_el0_from_thread (regcache);
> +
>        if (tdep->has_fpmr ())
>  	fetch_fpmr_from_thread (regcache);
>      }
> @@ -722,6 +750,10 @@ 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);
> +  /* POE register?  */
> +  else if (tdep->has_poe () && (regno == tdep->poe_regnum))
> +    fetch_por_el0_from_thread (regcache);
> +
>    /* FPMR?  */
>    else if (tdep->has_fpmr () && (regno == tdep->fpmr_regnum))
>      fetch_fpmr_from_thread (regcache);
> @@ -1024,6 +1056,9 @@ aarch64_linux_nat_target::read_description ()
>    /* Check for FPMR.  */
>    features.fpmr = hwcap2 & HWCAP2_FPMR;
>  
> +  /* Check for POE support.  */
> +  features.poe = hwcap2 & HWCAP2_POE;
> +
>    return aarch64_read_description (features);
>  }
>  
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index f11eccc1bc1..be6ef8db526 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -53,6 +53,7 @@
>  
>  #include "arch/aarch64-fpmr-linux.h"
>  #include "arch/aarch64-gcs-linux.h"
> +#include "arch/aarch64-poe.h"
>  #include "arch/aarch64-mte.h"
>  #include "arch/aarch64-mte-linux.h"
>  #include "arch/aarch64-pauth-linux.h"
> @@ -66,6 +67,7 @@
>  #include "elf/common.h"
>  #include "elf/aarch64.h"
>  #include "arch/aarch64-insn.h"
> +#include "gdbthread.h"
>  
>  /* For std::pow */
>  #include <cmath>
> @@ -274,6 +276,31 @@ struct aarch64_linux_sigframe
>  
>  };
>  
> +/* Convert a POR_EL0 Perm<m> overlay permission encoding into rwx-style string.
> +   For example:
> +     0b0011 -> "r-x" (3)
> +     0b0101 -> "rw-" (5)
> +     0b0111 -> "rwx" (7)
> +     0b0000 -> "---" (0)
> +   Reserved encodings (0b1xxx) are returned as "???".  */
> +
> +static const char*
> +aarch64_perm_overlay_decode (unsigned int perm)
> +{
> +  switch (perm)
> +   {
> +     case 0: return "---";
> +     case 1: return "r--";
> +     case 2: return "--x";
> +     case 3: return "r-x";
> +     case 4: return "-w-";
> +     case 5: return "rw-";
> +     case 6: return "-wx";
> +     case 7: return "rwx";
> +     default: return "???";
> +   }
> +}
> +
>  /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
>     size, or return 0 on error.  */
>  
> @@ -2675,11 +2702,12 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>  {
>    aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>  
> -  if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != GDB_SIGNAL_SEGV)
> +  if (!(tdep->has_mte () || tdep->has_gcs () || tdep->has_poe ())
> +      || siggnal != GDB_SIGNAL_SEGV)
>      return;
>  
>    CORE_ADDR fault_addr = 0;
> -  long si_code = 0, si_errno = 0;
> +  long si_code = 0, si_errno = 0, si_pkey = -1;
>  
>    try
>      {
> @@ -2687,6 +2715,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>  	 violation.  */
>        si_code = parse_and_eval_long ("$_siginfo.si_code");
>        si_errno = parse_and_eval_long ("$_siginfo.si_errno");
> +      if (tdep->has_poe ())
> +	si_pkey = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_pkey");
>  
>        fault_addr
>  	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> @@ -2703,6 +2733,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>      meaning = _("Memory tag violation");
>    else if (si_code == AARCH64_SEGV_CPERR && si_errno == 0)
>      meaning = _("Guarded Control Stack error");
> +  else if (si_code == AARCH64_SEGV_PKUERR && si_errno == 0)
> +    meaning = _("Protection overlay violation");
>    else
>      return;
>  
> @@ -2734,6 +2766,36 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>  	  uiout->field_string ("logical-tag", hex_string (ltag));
>  	}
>      }
> +  /* For POE SEGSEGV, show additional information.  */
> +  else if (si_code == AARCH64_SEGV_PKUERR)
> +    {
> +      frame_info_ptr frame = get_selected_frame (nullptr);
> +      value *v = value_of_register (tdep->poe_regnum, frame);
> +      ULONGEST por_el0 = (ULONGEST) value_as_long (v);
> +      unsigned int perm = (por_el0 >> (si_pkey * 4)) & 0xf;
> +
> +      uiout->text (_(" while accessing address "));
> +      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
> +      uiout->text ("\n");
> +
> +      /* In the case of a SIGSEGV, print the POR_EL0[si_pkey] permission
> +	 associated with the faulting address as an rwx-style permission
> +	string, followed by its decimal value in parentheses and the
> +	current thread ID.
> +
> +	e.g. POR_EL0[Protection-Key=1] = r-x (3) Thread Id = 1.  */
> +

There's a minor issue with whitespacing here.

> +      uiout->text (_("POR_EL0[Protection-Key="));
> +      uiout->field_signed ("protection-key", si_pkey);
> +      uiout->text (_("] = "));
> +      uiout->text (aarch64_perm_overlay_decode (perm));
> +      uiout->text (" (");
> +      uiout->field_unsigned ("por-el0-permission", perm);
> +      uiout->text (")");
> +      thread_info *thr = inferior_thread ();
> +      uiout->text (" Thread Id = ");
> +      uiout->field_signed ("thread-id", thr->global_num);
> +    }
>    else if (si_code != AARCH64_SEGV_CPERR)
>      {
>        uiout->text ("\n");
> @@ -3054,7 +3116,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>  					 aarch64_linux_decode_memtag_section);
>      }
>  
> -  if (tdep->has_mte () || tdep->has_gcs ())
> +  if (tdep->has_mte () || tdep->has_gcs () || tdep->has_poe ())
>      set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info);
>  
>    /* Initialize the aarch64_linux_record_tdep.  */
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index 886e7ce1e7b..23bca26ce43 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -4136,6 +4136,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>    features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
>  		   != nullptr);
>  
> +  /* Check for POE feature.  */
> +  features.poe = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe")
> +		   != nullptr);
> +
>    return features;
>  }
>  
> @@ -4556,6 +4560,16 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>  					  fpmr_regnum, "fpmr");
>      }
>  
> +  int poe_regnum = -1;
> +  const struct tdesc_feature *feature_poe
> +      = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe");
> +  if (feature_poe != nullptr)
> +    {
> +      poe_regnum = num_regs++;
> +      valid_p &= tdesc_numbered_register (feature_poe, tdesc_data.get (),
> +					  poe_regnum, "por_el0");
> +    }
> +
>    int first_sme_regnum = -1;
>    int first_sme2_regnum = -1;
>    int first_sme_pseudo_regnum = -1;
> @@ -4755,6 +4769,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>    tdep->tls_register_count = tls_register_count;
>    tdep->gcs_reg_base = first_gcs_regnum;
>    tdep->gcs_linux_reg_base = first_gcs_linux_regnum;
> +  tdep->poe_regnum = poe_regnum;
>    tdep->fpmr_regnum = fpmr_regnum;
>  
>    /* Set the SME register set details.  The pseudo-registers will be adjusted
> diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
> index dff05a08f84..3b959132ca6 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -208,6 +208,16 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>      return gcs_linux_reg_base != -1;
>    }
>  
> +  /* First POE register.  This is -1 if no POE feature is available.  */
> +  int poe_regnum = -1;
> +
> +  /* Returns true if the target supports the Linux POE feature.  */
> +  bool
> +  has_poe () const
> +  {
> +    return poe_regnum != -1;
> +  }
> +
>    /* First FPMR register.  This is -1 if FPMR is not supported.  */
>    int fpmr_regnum = -1;
>  
> diff --git a/gdb/arch/aarch64-poe.h b/gdb/arch/aarch64-poe.h
> new file mode 100644
> index 00000000000..1f2ac5c0cd2
> --- /dev/null
> +++ b/gdb/arch/aarch64-poe.h
> @@ -0,0 +1,35 @@
> +/* Common Linux target-dependent definitions for AArch64 POE
> +
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GDB_ARCH_AARCH64_POE_H
> +#define GDB_ARCH_AARCH64_POE_H
> +
> +/* Feature check for Permission Overlay Extension.  */
> +#ifndef HWCAP2_POE
> +#define AARCH64_HWCAP2_POE (1ULL << 63)
> +#endif
> +
> +#ifndef AARCH64_SEGV_PKUERR
> +#define AARCH64_SEGV_PKUERR 4  /* Protection overlay violation.  */
> +#endif
> +
> +/* The POE regset consists of 1 64-bit register.  */
> +#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)
> +
> +#endif /* GDB_ARCH_AARCH64_POE_H */
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 2401a325b7b..a567938d06d 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -28,6 +28,7 @@
>  #include "../features/aarch64-sme2.c"
>  #include "../features/aarch64-tls.c"
>  #include "../features/aarch64-gcs.c"
> +#include "../features/aarch64-poe.c"
>  #include "../features/aarch64-gcs-linux.c"
>  
>  /* See arch/aarch64.h.  */
> @@ -77,6 +78,9 @@ aarch64_create_target_description (const aarch64_features &features)
>    if (features.fpmr)
>      regnum = create_feature_aarch64_fpmr (tdesc.get (), regnum);
>  
> +  if (features.poe)
> +    regnum = create_feature_aarch64_poe (tdesc.get (), regnum);
> +
>    return tdesc;
>  }
>  
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index cf7318cbe74..4e4b50f729e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -35,6 +35,7 @@ struct aarch64_features
>    bool pauth = false;
>    bool mte = false;
>    bool fpmr = false;
> +  bool poe = false;
>  
>    /* A positive TLS value indicates the number of TLS registers available.  */
>    uint8_t tls = 0;
> @@ -70,7 +71,8 @@ inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
>      && lhs.sme2 == rhs.sme2
>      && lhs.gcs == rhs.gcs
>      && lhs.gcs_linux == rhs.gcs_linux
> -    && lhs.fpmr == rhs.fpmr;
> +    && lhs.fpmr == rhs.fpmr
> +    && lhs.poe == rhs.poe;
>  }
>  
>  namespace std
> @@ -103,6 +105,9 @@ namespace std
>  
>        /* FPMR feature.  */
>        h = h << 1 | features.fpmr;
> +
> +      /* POE feature.  */
> +      h = h << 1 | features.poe;
>        return h;
>      }
>    };
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 161a7453d66..cc77e5bb652 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -207,6 +207,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
>  	aarch64-pauth.xml \
>  	aarch64-mte.xml \
>  	aarch64-gcs.xml \
> +	aarch64-poe.xml \
>  	aarch64-gcs-linux.xml \
>  	arc/v1-core.xml \
>  	arc/v1-aux.xml \
> diff --git a/gdb/features/aarch64-poe.c b/gdb/features/aarch64-poe.c
> new file mode 100644
> index 00000000000..6892b52c1cf
> --- /dev/null
> +++ b/gdb/features/aarch64-poe.c
> @@ -0,0 +1,68 @@
> +/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> +  Original: aarch64-poe.xml */
> +
> +#include "gdbsupport/tdesc.h"
> +
> +static int
> +create_feature_aarch64_poe (struct target_desc *result, long regnum)
> +{
> +  struct tdesc_feature *feature;
> +
> +  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.poe");
> +  tdesc_type_with_fields *type_with_fields;
> +  type_with_fields = tdesc_create_enum (feature, "por_el0_fmt", 4);
> +  tdesc_add_enum_value (type_with_fields, 0, "---");
> +  tdesc_add_enum_value (type_with_fields, 1, "r--");
> +  tdesc_add_enum_value (type_with_fields, 2, "--x");
> +  tdesc_add_enum_value (type_with_fields, 3, "r-x");
> +  tdesc_add_enum_value (type_with_fields, 4, "-w-");
> +  tdesc_add_enum_value (type_with_fields, 5, "rw-");
> +  tdesc_add_enum_value (type_with_fields, 6, "-wx");
> +  tdesc_add_enum_value (type_with_fields, 7, "rwx");
> +  tdesc_add_enum_value (type_with_fields, 8, "???");
> +  tdesc_add_enum_value (type_with_fields, 9, "???");
> +  tdesc_add_enum_value (type_with_fields, 10, "???");
> +  tdesc_add_enum_value (type_with_fields, 11, "???");
> +  tdesc_add_enum_value (type_with_fields, 12, "???");
> +  tdesc_add_enum_value (type_with_fields, 13, "???");
> +  tdesc_add_enum_value (type_with_fields, 14, "???");
> +  tdesc_add_enum_value (type_with_fields, 15, "???");
> +
> +  type_with_fields = tdesc_create_flags (feature, "por_el0_flags", 8);
> +  tdesc_type *field_type;
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pf", 60, 63, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pe", 56, 59, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pd", 52, 55, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pc", 48, 51, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pb", 44, 47, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pa", 40, 43, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P9", 36, 39, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P8", 32, 35, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P7", 28, 31, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P6", 24, 27, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P5", 20, 23, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P4", 16, 19, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P3", 12, 15, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P2", 8, 11, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P1", 4, 7, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P0", 0, 3, field_type);
> +
> +  tdesc_create_reg (feature, "por_el0", regnum++, 1, "system", 64, "por_el0_flags");
> +  return regnum;
> +}
> diff --git a/gdb/features/aarch64-poe.xml b/gdb/features/aarch64-poe.xml
> new file mode 100644
> index 00000000000..e415a0f6bb6
> --- /dev/null
> +++ b/gdb/features/aarch64-poe.xml
> @@ -0,0 +1,50 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
> +<feature name="org.gnu.gdb.aarch64.poe">
> +
> +  <enum id="por_el0_fmt" size="4">
> +    <evalue name="---" value="0"/>
> +    <evalue name="r--" value="1"/>
> +    <evalue name="--x" value="2"/>
> +    <evalue name="r-x" value="3"/>
> +    <evalue name="-w-" value="4"/>
> +    <evalue name="rw-" value="5"/>
> +    <evalue name="-wx" value="6"/>
> +    <evalue name="rwx" value="7"/>
> +    <evalue name="???" value="8"/>
> +    <evalue name="???" value="9"/>
> +    <evalue name="???" value="10"/>
> +    <evalue name="???" value="11"/>
> +    <evalue name="???" value="12"/>
> +    <evalue name="???" value="13"/>
> +    <evalue name="???" value="14"/>
> +    <evalue name="???" value="15"/>
> +  </enum>
> +
> +  <flags id="por_el0_flags" size="8">
> +    <field name="Pf" start="60" end="63" type="por_el0_fmt"/>
> +    <field name="Pe" start="56" end="59" type="por_el0_fmt"/>
> +    <field name="Pd" start="52" end="55" type="por_el0_fmt"/>
> +    <field name="Pc" start="48" end="51" type="por_el0_fmt"/>
> +    <field name="Pb" start="44" end="47" type="por_el0_fmt"/>
> +    <field name="Pa" start="40" end="43" type="por_el0_fmt"/>
> +    <field name="P9" start="36" end="39" type="por_el0_fmt"/>
> +    <field name="P8" start="32" end="35" type="por_el0_fmt"/>
> +    <field name="P7" start="28" end="31" type="por_el0_fmt"/>
> +    <field name="P6" start="24" end="27" type="por_el0_fmt"/>
> +    <field name="P5" start="20" end="23" type="por_el0_fmt"/>
> +    <field name="P4" start="16" end="19" type="por_el0_fmt"/>
> +    <field name="P3" start="12" end="15" type="por_el0_fmt"/>
> +    <field name="P2" start="8" end="11" type="por_el0_fmt"/>
> +    <field name="P1" start="4" end="7" type="por_el0_fmt"/>
> +    <field name="P0" start="0" end="3" type="por_el0_fmt"/>
> +  </flags>
> +
> +  <reg name="por_el0" bitsize="64" type="por_el0_flags" group="system"/>
> +</feature>
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index a7381677498..44236ebe86e 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -366,8 +366,13 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
>  
>    /* _sigfault */
>    type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
> -  append_composite_type_field (type, "si_addr", void_ptr_type);
> -  append_composite_type_field (sifields_type, "_sigfault", type);
> +   {
> +     int size_of_ptr = gdbarch_ptr_bit (gdbarch) / HOST_CHAR_BIT;
> +     append_composite_type_field (type, "si_addr", void_ptr_type);
> +     append_composite_type_field (type, "_pad", init_vector_type (builtin_type (gdbarch)->builtin_char, size_of_ptr));
> +     append_composite_type_field (type, "si_pkey", builtin_type (gdbarch)->builtin_uint32);
> +     append_composite_type_field (sifields_type, "_sigfault", type);
> +   }
>  
>    /* _sigpoll */
>    type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
> diff --git a/gdb/nat/aarch64-poe.h b/gdb/nat/aarch64-poe.h
> new file mode 100644
> index 00000000000..3221634fd25
> --- /dev/null
> +++ b/gdb/nat/aarch64-poe.h
> @@ -0,0 +1,49 @@
> +/* Common native Linux definitions for AArch64 Permission Overlay Extension.
> +
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GDB_NAT_AARCH64_POE_H
> +#define GDB_NAT_AARCH64_POE_H
> +
> +#include <stdint.h>
> +#include <asm/hwcap.h>
> +#include <asm/ptrace.h>
> +
> +/* Feature check for Permission Overlay Extension.  */
> +#ifndef HWCAP2_POE
> +#define HWCAP2_POE (1ULL << 63)
> +#endif
> +
> +#ifndef HAVE_STRUCT_USER_POE
> +
> +/* POE state (NT_ARM_POE).  */
> +#ifndef NT_ARM_POE
> +#define NT_ARM_POE 0x40f
> +#endif
> +
> +struct user_poe
> +{
> +  uint64_t por_el0;
> +};
> +

Any particular reason as to why a struct is used here?  From looking at kernel,
I don't think there's any more fields to be added.

> +#endif /* HAVE_STRUCT_USER_POE */
> +
> +/* The POE regset consists of 1 64-bit register.  */
> +#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)
> +
> +#endif /* GDB_NAT_AARCH64_POE_H */
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
> new file mode 100644
> index 00000000000..6b0c07e782f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
> @@ -0,0 +1,52 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2026 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 AArch64's POE Extension.  */
> +
> +/* This test is based on the Linux kernel documentation for Memory
> +   Protection Keys, including the arm64 Permission Overlay Extension
> +   (FEAT_S1POE) support described in
> +   Documentation/core-api/protection-keys.rst.  */
> +
> +#define _GNU_SOURCE
> +#include <sys/mman.h>
> +#include <unistd.h>
> +
> +int
> +main (void)
> +{
> +  long pagesize = sysconf (_SC_PAGESIZE);
> +
> +  int *buf = mmap (NULL, pagesize, PROT_READ | PROT_WRITE,
> +		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +  if (buf == MAP_FAILED)
> +    return 1;
> +
> +  int pkey = pkey_alloc (0, 0);
> +  if (pkey == -1)
> +    return 1;
> +
> +  if (pkey_mprotect (buf, pagesize, PROT_READ | PROT_WRITE, pkey) == -1)
> +    return 1;
> +
> +  if (pkey_set (pkey, PKEY_DISABLE_WRITE) == -1)
> +    return 1;
> +
> +  buf[0] = 42;  /* Expect SIGSEGV POE violation.  */
> +
> +  return 1;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
> new file mode 100644
> index 00000000000..dfd91f652f0
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
> @@ -0,0 +1,51 @@
> +# Copyright (C) 2026 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/>.
> +
> +# Test a binary that uses POE and exposed POR_EL0 register.
> +
> +global hex
> +global decimal
> +
> +require is_aarch64_target
> +
> +if {![allow_aarch64_poe_tests]} {
> +    unsupported "AArch64 POE not supported"
> +    return
> +}
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> +    return
> +}
> +
> +if {![runto_main]} {
> +    return
> +}
> +
> +# Display POE violation SIGSEGV error message.
> +set poe_sigsegv_re [multi_line \
> +    "Program received signal SIGSEGV, Segmentation fault" \
> +    "Protection overlay violation while accessing address ${hex}" \
> +    "POR_EL0\\\[Protection-Key=${decimal}\\\] = \[-rwx\]+ \\(${decimal}\\) Thread Id = ${decimal}"]
> +
> +gdb_test_multiple "continue" "display POE violation information" {
> +    -re "$poe_sigsegv_re.*$gdb_prompt $" {
> +	pass $gdb_test_name
> +    }
> +
> +    -re ".*exited with code 01.*$gdb_prompt $" {
> +	unsupported "POE userspace support unavailable"
> +    }
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe.c b/gdb/testsuite/gdb.arch/aarch64-poe.c
> new file mode 100644
> index 00000000000..2c95dc2a99b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe.c
> @@ -0,0 +1,29 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2026 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 AArch64's POE Extension.  */
> +
> +/* This test is based on the Linux kernel documentation for Memory
> +   Protection Keys, including the arm64 Permission Overlay Extension
> +   (FEAT_S1POE) support described in
> +   Documentation/core-api/protection-keys.rst.  */
> +
> +int
> +main (void)
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe.exp b/gdb/testsuite/gdb.arch/aarch64-poe.exp
> new file mode 100644
> index 00000000000..ae2663a7dbc
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe.exp
> @@ -0,0 +1,44 @@
> +# Copyright (C) 2026 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/>.
> +
> +# Test a binary that uses POE and exposed POR_EL0 register.
> +
> +global hex
> +global decimal
> +
> +require is_aarch64_target
> +
> +if {![allow_aarch64_poe_tests]} {
> +    unsupported "AArch64 POE not supported"
> +    return
> +}
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> +    return
> +}
> +
> +if {![runto_main]} {
> +    return
> +}
> +
> +# Validate the presence of the POE register.
> +    gdb_test "info registers por_el0" \
> +	     "por_el0\[ \t\]+$hex.*" \
> +	     "register por_el0 available"
> +
> +    gdb_test "p/x \$por_el0" \
> +	     "\\$\[0-9\]+ = ${hex}" \
> +	     "print por_el0"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 7b1feeaac84..fe2c533791c 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -5616,6 +5616,61 @@ gdb_caching_proc allow_aarch64_gcs_tests {} {
>      return $allow_gcs_tests
>  }
>  
> +# Run a test on the target to see if it supports AArch64 POE extensions.
> +# Return 1 if so, 0 if it does not.  Note this causes a restart of GDB.
> +
> +gdb_caching_proc allow_aarch64_poe_tests {} {
> +    global srcdir subdir gdb_prompt inferior_exited_re
> +
> +    set me "allow_aarch64_poe_tests"
> +
> +    if { ![is_aarch64_target]} {
> +	return 0
> +    }
> +
> +    # Compile a program that tests the POE feature.
> +    set src {
> +	#include <stdbool.h>
> +	#include <sys/auxv.h>
> +
> +	/* Feature check for POE feature.  */
> +	#ifndef HWCAP2_POE
> +	#define HWCAP2_POE (1ULL << 63)
> +	#endif
> +
> +	int main (void) {
> +	    bool poe_supported = getauxval (AT_HWCAP2) & HWCAP2_POE;
> +
> +	    /* Return success if POE is supported.  */
> +	    return !poe_supported;
> +	}
> +    }
> +
> +    if {![gdb_simple_compile $me $src executable]} {
> +	return 0
> +    }
> +
> +    # Compilation succeeded so now run it via gdb.
> +    set allow_poe_tests 0
> +    clean_restart
> +    gdb_load $obj
> +    gdb_run_cmd
> +    gdb_expect {
> +	-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
> +	    verbose -log "\n$me: poe support detected"
> +	    set allow_poe_tests 1
> +	}
> +	-re ".*$inferior_exited_re with code 01.*${gdb_prompt} $" {
> +	    verbose -log "\n$me: poe support not detected"
> +	}
> +    }
> +    gdb_exit
> +    remote_file build delete $obj
> +
> +    verbose "$me:  returning $allow_poe_tests" 2
> +    return $allow_poe_tests
> +}
> +
>  # A helper that compiles a test case to see if __int128 is supported.
>  proc gdb_int128_helper {lang} {
>      return [gdb_can_simple_compile "i128-for-$lang" {
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index a2588a6e2a9..c27525be1ac 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -45,6 +45,7 @@
>  #include "linux-aarch32-tdesc.h"
>  #include "linux-aarch64-tdesc.h"
>  #include "nat/aarch64-fpmr-linux.h"
> +#include "nat/aarch64-poe.h"
>  #include "nat/aarch64-gcs-linux.h"
>  #include "nat/aarch64-mte-linux-ptrace.h"
>  #include "nat/aarch64-scalable-linux-ptrace.h"
> @@ -250,6 +251,16 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
>    supply_register (regcache, AARCH64_FPCR_REGNUM, &regset->fpcr);
>  }
>  
> +/* Store the POE (POR_EL0) register set to regcache.  */
> +
> +static void
> +aarch64_store_por_el0_regset (struct regcache *regcache, const void *buf)
> +{
> +  const user_poe *regset = (const user_poe *) buf;
> +  int poe_regnum  = find_regno (regcache->tdesc, "por_el0");

I've noticed that a few of the regnum have 2 spaces before the '=' (gcspr,
features_enabled).  I'm not sure if this is intentional or not.

> +  supply_register (regcache, poe_regnum, &regset->por_el0);
> +}
> +
>  /* Fill BUF with the FPMR register set from the regcache.  */
>  
>  static void
> @@ -901,6 +912,10 @@ static struct regset_info aarch64_regsets[] =
>    { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_FPMR,
>      0, OPTIONAL_REGS,
>      aarch64_fill_fpmr_regset, aarch64_store_fpmr_regset },
> +  /* POE register (POR_EL0).  */
> +  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_POE,
> +    0, OPTIONAL_REGS,
> +    nullptr, aarch64_store_por_el0_regset },
>    /* TLS register.  */
>    { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
>      0, OPTIONAL_REGS,
> @@ -980,6 +995,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>  	  if (features.fpmr)
>  	    regset->size = sizeof (uint64_t);
>  	  break;
> +	case NT_ARM_POE:
> +	  if (features.poe)
> +	    regset->size = sizeof (user_poe);
> +	  break;
>  	default:
>  	  gdb_assert_not_reached ("Unknown register set found.");
>  	}
> @@ -1010,6 +1029,7 @@ aarch64_target::low_arch_setup ()
>        features.tls = aarch64_tls_register_count (tid);
>        features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) & HWCAP_GCS;
>        features.fpmr = linux_get_hwcap2 (pid, 8) & HWCAP2_FPMR;
> +      features.poe = linux_get_hwcap2 (pid, 8) & HWCAP2_POE;
>  
>        /* Scalable Matrix Extension feature and size check.  */
>        if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)
> -- 
> 2.43.0
> 

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

* Re: [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register
  2026-06-17 17:00 [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register srinath.parvathaneni
  2026-06-17 23:38 ` Ezra Sitorus
@ 2026-06-18 17:04 ` Matthieu Longo
  2026-06-21 11:32   ` Luis
  2026-06-21 11:50 ` Luis
  2 siblings, 1 reply; 5+ messages in thread
From: Matthieu Longo @ 2026-06-18 17:04 UTC (permalink / raw)
  To: srinath.parvathaneni, gdb-patches
  Cc: guinevere, thiago.bauermann, luis.machado.foss

On 17/06/2026 18:00, srinath.parvathaneni@arm.com wrote:
> From: Srinath Parvathaneni <srinath.parvathaneni@arm.com>
> 
> Hi,
> 
> FEAT_S1POE introduces the POR_EL0 register. This patch adds
> support for POR_EL0 in both native GDB and gdbserver using
> NT_ARM_POE and HWCAP2_POE detection.
> 
> With this change, POR_EL0 is available through:
> * info registers
> * info registers por_el0
> * p $por_el0
> * p/x $por_el0
> 
> This patch also extends AArch64 SIGSEGV reporting for POE permission
> faults. When a fault is reported with SEGV_PKUERR, GDB displays the
> fault address together with the decoded POR_EL0 permissions associated
> with the protection key that generated the fault and the current thread
> ID.
> 
> Example:
> Program received signal SIGSEGV, Segmentation fault
> Protection overlay violation while accessing address 0x0000fffff7ff3000
> POR_EL0[Protection-Key=1] = r-x (3) Thread Id = 1.
> 0x0000aaaaaaaa0990 in main () at aarch64-poe-sigsegv.c:49
> 
> The gdb.arch/aarch64-poe.exp testcase verifies POR_EL0 register
> visibility and access. The gdb.arch/aarch64-poe-sigsegv.exp testcase
> verifies POE-specific SIGSEGV reporting and is marked unsupported when
> the required userspace or kernel support is not available.
> 
> The tests were run on Arm FVP with FEAT_S1POE support and a Linux
> kernel built with CONFIG_ARM64_POE enabled.
> 

1. Did you do a native build of GDB on a x86_64 host or AArch64 one ?
2. Did you directly run gdb inside Arm FVP, or run gdb on a host, and gdbserver in Arm FVP ?

> Please note:
> 1. Support for "set $por_el0" is not included in this patch.
> 2. POR_EL0 write support will be addressed separately.

What about the support for coredumps ?

> 
> Regression tested on aarch64-none-linux-gnu target and found
> no regressions.
> 
> Regards,
> Srinath
> ---
>   gdb/Makefile.in                               |  2 +
>   gdb/aarch64-linux-nat.c                       | 35 ++++++++++
>   gdb/aarch64-linux-tdep.c                      | 68 ++++++++++++++++++-
>   gdb/aarch64-tdep.c                            | 15 ++++
>   gdb/aarch64-tdep.h                            | 10 +++
>   gdb/arch/aarch64-poe.h                        | 35 ++++++++++
>   gdb/arch/aarch64.c                            |  4 ++
>   gdb/arch/aarch64.h                            |  7 +-
>   gdb/features/Makefile                         |  1 +
>   gdb/features/aarch64-poe.c                    | 68 +++++++++++++++++++
>   gdb/features/aarch64-poe.xml                  | 50 ++++++++++++++
>   gdb/linux-tdep.c                              |  9 ++-
>   gdb/nat/aarch64-poe.h                         | 49 +++++++++++++
>   gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c  | 52 ++++++++++++++
>   .../gdb.arch/aarch64-poe-sigsegv.exp          | 51 ++++++++++++++
>   gdb/testsuite/gdb.arch/aarch64-poe.c          | 29 ++++++++
>   gdb/testsuite/gdb.arch/aarch64-poe.exp        | 44 ++++++++++++
>   gdb/testsuite/lib/gdb.exp                     | 55 +++++++++++++++
>   gdbserver/linux-aarch64-low.cc                | 20 ++++++
>   19 files changed, 598 insertions(+), 6 deletions(-)
>   create mode 100644 gdb/arch/aarch64-poe.h
>   create mode 100644 gdb/features/aarch64-poe.c
>   create mode 100644 gdb/features/aarch64-poe.xml
>   create mode 100644 gdb/nat/aarch64-poe.h
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe.c
>   create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe.exp
> 
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 57f384170ab..6cdc896d342 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -1292,6 +1292,7 @@ HFILES_NO_SRCDIR = \
>   	arch/aarch32.h \
>   	arch/aarch64-fpmr-linux.h \
>   	arch/aarch64-gcs-linux.h \
> +	arch/aarch64-poe.h \
>   	arch/aarch64.h \
>   	arch/aarch64-insn.h \
>   	arch/aarch64-mte.h \
> @@ -1540,6 +1541,7 @@ HFILES_NO_SRCDIR = \
>   	namespace.h \
>   	nat/aarch64-fpmr-linux.h \
>   	nat/aarch64-gcs-linux.h \
> +	nat/aarch64-poe.h \
>   	nat/aarch64-hw-point.h \
>   	nat/aarch64-linux.h \
>   	nat/aarch64-linux-hw-point.h \
> diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
> index 52ace4aab41..181f3596481 100644
> --- a/gdb/aarch64-linux-nat.c
> +++ b/gdb/aarch64-linux-nat.c
> @@ -34,6 +34,7 @@
>   #include "arch/arm.h"
>   #include "nat/aarch64-fpmr-linux.h"
>   #include "nat/aarch64-gcs-linux.h"
> +#include "nat/aarch64-poe.h"
>   #include "nat/aarch64-linux.h"
>   #include "nat/aarch64-linux-hw-point.h"
>   #include "nat/aarch64-mte-linux-ptrace.h"
> @@ -569,6 +570,30 @@ fetch_gcsregs_from_thread (regcache *regcache)
>   			&user_gcs.features_locked);
>   }
>   
> +/* Fill GDB's register array with the POE register value from the current
> +   thread.  */
> +
> +static void
> +fetch_por_el0_from_thread (regcache *regcache)

Maybe keep the name "generic" as in others fetch and store functions.
E.g. fetch_fpmr_from_thread, fetch_gcsregs_from_thread, fetch_tlsregs_from_thread, ...

For instance, fetch_poereg_from_thread ?

> +{
> +  aarch64_gdbarch_tdep *tdep
> +    = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
> +
> +  gdb_assert (tdep->poe_regnum != -1);
> +

Use tdep->has_poe() instead.

> +  user_poe user_poe;
> +  iovec iovec;
> +
> +  iovec.iov_base = &user_poe;
> +  iovec.iov_len = sizeof (user_poe);
> +
> +  int tid = get_ptrace_pid (regcache->ptid ());

* Question for maintainers: *

It seems that there are different methods to get the thread ID.
I observed in the same file 3 different ways:
- int tid = get_ptrace_pid (inferior_ptid);
- int tid = regcache->ptid ().lwp ();
- int tid = get_ptrace_pid (regcache->ptid ());

What is the "correct" method ?

> +  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_POE, &iovec) != 0)
> +    perror_with_name (_("Unable to fetch POE register"));
> +
> +  regcache->raw_supply (tdep->poe_regnum, &user_poe.por_el0);
> +}
> +
>   /* Store to the current thread the valid GCS register set in the GDB's
>      register array.  */
>   
> @@ -683,6 +708,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
>         if (tdep->has_gcs_linux ())
>   	fetch_gcsregs_from_thread (regcache);
>   
> +      if (tdep->has_poe ())
> +	fetch_por_el0_from_thread (regcache);
> +
>         if (tdep->has_fpmr ())
>   	fetch_fpmr_from_thread (regcache);
>       }
> @@ -722,6 +750,10 @@ 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);
> +  /* POE register?  */
> +  else if (tdep->has_poe () && (regno == tdep->poe_regnum))
> +    fetch_por_el0_from_thread (regcache);
> +
>     /* FPMR?  */
>     else if (tdep->has_fpmr () && (regno == tdep->fpmr_regnum))
>       fetch_fpmr_from_thread (regcache);
> @@ -1024,6 +1056,9 @@ aarch64_linux_nat_target::read_description ()
>     /* Check for FPMR.  */
>     features.fpmr = hwcap2 & HWCAP2_FPMR;
>   
> +  /* Check for POE support.  */
> +  features.poe = hwcap2 & HWCAP2_POE;
> +
>     return aarch64_read_description (features);
>   }
>   
> diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
> index f11eccc1bc1..be6ef8db526 100644
> --- a/gdb/aarch64-linux-tdep.c
> +++ b/gdb/aarch64-linux-tdep.c
> @@ -53,6 +53,7 @@
>   
>   #include "arch/aarch64-fpmr-linux.h"
>   #include "arch/aarch64-gcs-linux.h"
> +#include "arch/aarch64-poe.h"
>   #include "arch/aarch64-mte.h"
>   #include "arch/aarch64-mte-linux.h"
>   #include "arch/aarch64-pauth-linux.h"
> @@ -66,6 +67,7 @@
>   #include "elf/common.h"
>   #include "elf/aarch64.h"
>   #include "arch/aarch64-insn.h"
> +#include "gdbthread.h"
>   
>   /* For std::pow */
>   #include <cmath>
> @@ -274,6 +276,31 @@ struct aarch64_linux_sigframe
>   
>   };
>   
> +/* Convert a POR_EL0 Perm<m> overlay permission encoding into rwx-style string.
> +   For example:
> +     0b0011 -> "r-x" (3)
> +     0b0101 -> "rw-" (5)
> +     0b0111 -> "rwx" (7)
> +     0b0000 -> "---" (0)
> +   Reserved encodings (0b1xxx) are returned as "???".  */
> +
> +static const char*
> +aarch64_perm_overlay_decode (unsigned int perm)
> +{
> +  switch (perm)
> +   {
> +     case 0: return "---";
> +     case 1: return "r--";
> +     case 2: return "--x";
> +     case 3: return "r-x";
> +     case 4: return "-w-";
> +     case 5: return "rw-";
> +     case 6: return "-wx";
> +     case 7: return "rwx";
> +     default: return "???";
> +   }
> +}
> +

I don't think that this code is AArch64 and Linux specific.
It might make sense to move it to another file with generic utils.

>   /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
>      size, or return 0 on error.  */
>   
> @@ -2675,11 +2702,12 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>   {
>     aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
>   
> -  if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != GDB_SIGNAL_SEGV)
> +  if (!(tdep->has_mte () || tdep->has_gcs () || tdep->has_poe ())
> +      || siggnal != GDB_SIGNAL_SEGV)
>       return;
>   
>     CORE_ADDR fault_addr = 0;
> -  long si_code = 0, si_errno = 0;
> +  long si_code = 0, si_errno = 0, si_pkey = -1;
>   
>     try
>       {
> @@ -2687,6 +2715,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>   	 violation.  */
>         si_code = parse_and_eval_long ("$_siginfo.si_code");
>         si_errno = parse_and_eval_long ("$_siginfo.si_errno");
> +      if (tdep->has_poe ())
> +	si_pkey = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_pkey");
>   
>         fault_addr
>   	= parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> @@ -2703,6 +2733,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>       meaning = _("Memory tag violation");
>     else if (si_code == AARCH64_SEGV_CPERR && si_errno == 0)
>       meaning = _("Guarded Control Stack error");
> +  else if (si_code == AARCH64_SEGV_PKUERR && si_errno == 0)
> +    meaning = _("Protection overlay violation");

si_errno is not used for AARCH64_SEGV_PKUERR, so the check is not needed, isn't it ?

I would also strongly recommend to rename the message to something align with the Linux kernel 
documentation.
https://docs.kernel.org/core-api/protection-keys.html

They refer the feature as "Pkeys Userspace (PKU)".
In my opinion, "userspace" in the context of GDB seems redundant.
What about "Protection Key violation" ?

>     else
>       return;
>   
> @@ -2734,6 +2766,36 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
>   	  uiout->field_string ("logical-tag", hex_string (ltag));
>   	}
>       }
> +  /* For POE SEGSEGV, show additional information.  */
> +  else if (si_code == AARCH64_SEGV_PKUERR)
> +    {
> +      frame_info_ptr frame = get_selected_frame (nullptr);
> +      value *v = value_of_register (tdep->poe_regnum, frame);
> +      ULONGEST por_el0 = (ULONGEST) value_as_long (v);
> +      unsigned int perm = (por_el0 >> (si_pkey * 4)) & 0xf;
> +
> +      uiout->text (_(" while accessing address "));
> +      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
> +      uiout->text ("\n");
> +
> +      /* In the case of a SIGSEGV, print the POR_EL0[si_pkey] permission
> +	 associated with the faulting address as an rwx-style permission
> +	string, followed by its decimal value in parentheses and the
> +	current thread ID.
> +
> +	e.g. POR_EL0[Protection-Key=1] = r-x (3) Thread Id = 1.  */
> +

The indentation seems off here.

> +      uiout->text (_("POR_EL0[Protection-Key="));
> +      uiout->field_signed ("protection-key", si_pkey);
> +      uiout->text (_("] = "));
> +      uiout->text (aarch64_perm_overlay_decode (perm));
> +      uiout->text (" (");
> +      uiout->field_unsigned ("por-el0-permission", perm);
> +      uiout->text (")");
> +      thread_info *thr = inferior_thread ();
> +      uiout->text (" Thread Id = ");
> +      uiout->field_signed ("thread-id", thr->global_num);

By default, in the context of a multithreaded program, GDB always augments the usual message with 
the ID and name of the thread. It also automatically switch to the thread that received the signal.

For instance:
   [New Thread 318.321 (id 2)]
   [New Thread 318.322 (id 3)]
...
   Thread 2 "poe2-demo" received signal SIGSEGV, Segmentation fault
   Permission Overlay violation while accessing address 0x0000fffff7ff5000 with DPOIndex=0 and TIndex=2.
   [Switching to Thread 318.321]

Consequently, I would recommend to remove the thread ID from the explanation message as it is 
already provided by the previous line informing that a fault occurred.

Now there is only one information on this line, why not moving it to the previous sentence ?
Something like:

   Protection Key violation while accessing address <ADDRESS> with PKey=<PKEY>

Additionally, displaying the associated overlay value to the PKey is misleading for the user. It 
should be the effective permission instead.
For instance, if the base permission is r-x and the overlay value rw-, the user will be confused 
because if he looks at the instruction that failed (a store for instance) and see the permission 
rw-, he really does not understand what is going on.

> +    }
>     else if (si_code != AARCH64_SEGV_CPERR)
>       {
>         uiout->text ("\n");
> @@ -3054,7 +3116,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>   					 aarch64_linux_decode_memtag_section);
>       }
>   
> -  if (tdep->has_mte () || tdep->has_gcs ())
> +  if (tdep->has_mte () || tdep->has_gcs () || tdep->has_poe ())
>       set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info);
>   
>     /* Initialize the aarch64_linux_record_tdep.  */
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index 886e7ce1e7b..23bca26ce43 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -4136,6 +4136,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc)
>     features.fpmr = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpmr")
>   		   != nullptr);
>   
> +  /* Check for POE feature.  */
> +  features.poe = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe")
> +		   != nullptr);

Remove one space in the indentation.

> +
>     return features;
>   }
>   
> @@ -4556,6 +4560,16 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>   					  fpmr_regnum, "fpmr");
>       }
>   
> +  int poe_regnum = -1;
> +  const struct tdesc_feature *feature_poe
> +      = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe");
> +  if (feature_poe != nullptr)
> +    {
> +      poe_regnum = num_regs++;

I personally don't like this notation as it makes reading harder for me.
Even if there is only one register, it is more readable to follow the strategy as if there was 
several registers by splitting this statement in:

poe_regnum = num_regs;
valid_p &= tdesc_numbered_register (feature_poe, tdesc_data.get (),
				  poe_regnum, "por_el0");
num_regs++;

> +      valid_p &= tdesc_numbered_register (feature_poe, tdesc_data.get (),
> +					  poe_regnum, "por_el0");

If you look at GCS or MTE registers, an array of names has been created for each of them even if 
there is only one register.
I guess that having all of the names in one place is making reading easier.
It's probably better to follow the current way.

> +    }
> +
>     int first_sme_regnum = -1;
>     int first_sme2_regnum = -1;
>     int first_sme_pseudo_regnum = -1;
> @@ -4755,6 +4769,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>     tdep->tls_register_count = tls_register_count;
>     tdep->gcs_reg_base = first_gcs_regnum;
>     tdep->gcs_linux_reg_base = first_gcs_linux_regnum;
> +  tdep->poe_regnum = poe_regnum;
>     tdep->fpmr_regnum = fpmr_regnum;
>   
>     /* Set the SME register set details.  The pseudo-registers will be adjusted
> diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
> index dff05a08f84..3b959132ca6 100644
> --- a/gdb/aarch64-tdep.h
> +++ b/gdb/aarch64-tdep.h
> @@ -208,6 +208,16 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
>       return gcs_linux_reg_base != -1;
>     }
>   
> +  /* First POE register.  This is -1 if no POE feature is available.  */

There is only one POE register, so you might want to rename this to:
/* Index of the POE register.  This is -1 if POE is not supported.  */

> +  int poe_regnum = -1;
> +
> +  /* Returns true if the target supports the Linux POE feature.  */
> +  bool
> +  has_poe () const
> +  {
> +    return poe_regnum != -1;
> +  }
> +
>     /* First FPMR register.  This is -1 if FPMR is not supported.  */
>     int fpmr_regnum = -1;
>   
> diff --git a/gdb/arch/aarch64-poe.h b/gdb/arch/aarch64-poe.h
> new file mode 100644
> index 00000000000..1f2ac5c0cd2
> --- /dev/null
> +++ b/gdb/arch/aarch64-poe.h

This file is Linux specific as the comment at the top of the file specifies it.
So it should be named aarch64-poe-linux.h if I refer to others existing ones for PAuth or MTE.

> @@ -0,0 +1,35 @@
> +/* Common Linux target-dependent definitions for AArch64 POE
> +
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GDB_ARCH_AARCH64_POE_H
> +#define GDB_ARCH_AARCH64_POE_H

Same here. Since it is Linux-specific, it should be named GDB_ARCH_AARCH64_POE_LINUX_H

> +
> +/* Feature check for Permission Overlay Extension.  */

E for Enhancement and not Extension.

> +#ifndef HWCAP2_POE

Why this #ifndef ?
which by the way does not match the define.

> +#define AARCH64_HWCAP2_POE (1ULL << 63)
> +#endif
> +
> +#ifndef AARCH64_SEGV_PKUERR

Same question here.

> +#define AARCH64_SEGV_PKUERR 4  /* Protection overlay violation.  */

I propose to make this comment a bit more explicit regarding the two potential origins of such a 
violation. Something like:

/* Data or instruction abort caused by POE violation.  */

> +#endif
> +
> +/* The POE regset consists of 1 64-bit register.  */

one instead of 1 ? It makes things easier to read.

> +#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)

Remove the parenthesis ?

> +
> +#endif /* GDB_ARCH_AARCH64_POE_H */
> diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c
> index 2401a325b7b..a567938d06d 100644
> --- a/gdb/arch/aarch64.c
> +++ b/gdb/arch/aarch64.c
> @@ -28,6 +28,7 @@
>   #include "../features/aarch64-sme2.c"
>   #include "../features/aarch64-tls.c"
>   #include "../features/aarch64-gcs.c"
> +#include "../features/aarch64-poe.c"
>   #include "../features/aarch64-gcs-linux.c"
>   
>   /* See arch/aarch64.h.  */
> @@ -77,6 +78,9 @@ aarch64_create_target_description (const aarch64_features &features)
>     if (features.fpmr)
>       regnum = create_feature_aarch64_fpmr (tdesc.get (), regnum);
>   
> +  if (features.poe)
> +    regnum = create_feature_aarch64_poe (tdesc.get (), regnum);
> +
>     return tdesc;
>   }
>   
> diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
> index cf7318cbe74..4e4b50f729e 100644
> --- a/gdb/arch/aarch64.h
> +++ b/gdb/arch/aarch64.h
> @@ -35,6 +35,7 @@ struct aarch64_features
>     bool pauth = false;
>     bool mte = false;
>     bool fpmr = false;
> +  bool poe = false;
>   

Comments have been added for each of those booleans on master. You probably need to rebase.
See 
https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/arch/aarch64.h;h=cf7318cbe7400ba2869f690e3f94ad92f3eae55b;hb=HEAD#l60

A comment should be added for the new boolean.

>     /* A positive TLS value indicates the number of TLS registers available.  */
>     uint8_t tls = 0;
> @@ -70,7 +71,8 @@ inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs)
>       && lhs.sme2 == rhs.sme2
>       && lhs.gcs == rhs.gcs
>       && lhs.gcs_linux == rhs.gcs_linux
> -    && lhs.fpmr == rhs.fpmr;
> +    && lhs.fpmr == rhs.fpmr
> +    && lhs.poe == rhs.poe;
>   }
>   
>   namespace std
> @@ -103,6 +105,9 @@ namespace std
>   
>         /* FPMR feature.  */
>         h = h << 1 | features.fpmr;
> +
> +      /* POE feature.  */
> +      h = h << 1 | features.poe;
>         return h;
>       }
>     };
> diff --git a/gdb/features/Makefile b/gdb/features/Makefile
> index 161a7453d66..cc77e5bb652 100644
> --- a/gdb/features/Makefile
> +++ b/gdb/features/Makefile
> @@ -207,6 +207,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
>   	aarch64-pauth.xml \
>   	aarch64-mte.xml \
>   	aarch64-gcs.xml \
> +	aarch64-poe.xml \
>   	aarch64-gcs-linux.xml \
>   	arc/v1-core.xml \
>   	arc/v1-aux.xml \
> diff --git a/gdb/features/aarch64-poe.c b/gdb/features/aarch64-poe.c
> new file mode 100644
> index 00000000000..6892b52c1cf
> --- /dev/null
> +++ b/gdb/features/aarch64-poe.c
> @@ -0,0 +1,68 @@
> +/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
> +  Original: aarch64-poe.xml */
> +
> +#include "gdbsupport/tdesc.h"
> +
> +static int
> +create_feature_aarch64_poe (struct target_desc *result, long regnum)
> +{
> +  struct tdesc_feature *feature;
> +
> +  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.poe");
> +  tdesc_type_with_fields *type_with_fields;
> +  type_with_fields = tdesc_create_enum (feature, "por_el0_fmt", 4);
> +  tdesc_add_enum_value (type_with_fields, 0, "---");
> +  tdesc_add_enum_value (type_with_fields, 1, "r--");
> +  tdesc_add_enum_value (type_with_fields, 2, "--x");
> +  tdesc_add_enum_value (type_with_fields, 3, "r-x");
> +  tdesc_add_enum_value (type_with_fields, 4, "-w-");
> +  tdesc_add_enum_value (type_with_fields, 5, "rw-");
> +  tdesc_add_enum_value (type_with_fields, 6, "-wx");
> +  tdesc_add_enum_value (type_with_fields, 7, "rwx");
> +  tdesc_add_enum_value (type_with_fields, 8, "???");
> +  tdesc_add_enum_value (type_with_fields, 9, "???");
> +  tdesc_add_enum_value (type_with_fields, 10, "???");
> +  tdesc_add_enum_value (type_with_fields, 11, "???");
> +  tdesc_add_enum_value (type_with_fields, 12, "???");
> +  tdesc_add_enum_value (type_with_fields, 13, "???");
> +  tdesc_add_enum_value (type_with_fields, 14, "???");
> +  tdesc_add_enum_value (type_with_fields, 15, "???");
> +
> +  type_with_fields = tdesc_create_flags (feature, "por_el0_flags", 8);
> +  tdesc_type *field_type;
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pf", 60, 63, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pe", 56, 59, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pd", 52, 55, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pc", 48, 51, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pb", 44, 47, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "Pa", 40, 43, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P9", 36, 39, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P8", 32, 35, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P7", 28, 31, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P6", 24, 27, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P5", 20, 23, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P4", 16, 19, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P3", 12, 15, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P2", 8, 11, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P1", 4, 7, field_type);
> +  field_type = tdesc_named_type (feature, "por_el0_fmt");
> +  tdesc_add_typed_bitfield (type_with_fields, "P0", 0, 3, field_type);
> +
> +  tdesc_create_reg (feature, "por_el0", regnum++, 1, "system", 64, "por_el0_flags");
> +  return regnum;
> +}
> diff --git a/gdb/features/aarch64-poe.xml b/gdb/features/aarch64-poe.xml
> new file mode 100644
> index 00000000000..e415a0f6bb6
> --- /dev/null
> +++ b/gdb/features/aarch64-poe.xml
> @@ -0,0 +1,50 @@
> +<?xml version="1.0"?>
> +<!-- Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +     Copying and distribution of this file, with or without modification,
> +     are permitted in any medium without royalty provided the copyright
> +     notice and this notice are preserved.  -->
> +
> +<!DOCTYPE feature SYSTEM "gdb-target.dtd">
> +<feature name="org.gnu.gdb.aarch64.poe">
> +
> +  <enum id="por_el0_fmt" size="4">
> +    <evalue name="---" value="0"/>
> +    <evalue name="r--" value="1"/>
> +    <evalue name="--x" value="2"/>
> +    <evalue name="r-x" value="3"/>
> +    <evalue name="-w-" value="4"/>
> +    <evalue name="rw-" value="5"/>
> +    <evalue name="-wx" value="6"/>
> +    <evalue name="rwx" value="7"/>
> +    <evalue name="???" value="8"/>
> +    <evalue name="???" value="9"/>
> +    <evalue name="???" value="10"/>
> +    <evalue name="???" value="11"/>
> +    <evalue name="???" value="12"/>
> +    <evalue name="???" value="13"/>
> +    <evalue name="???" value="14"/>
> +    <evalue name="???" value="15"/>
> +  </enum>
> +
> +  <flags id="por_el0_flags" size="8">
> +    <field name="Pf" start="60" end="63" type="por_el0_fmt"/>
> +    <field name="Pe" start="56" end="59" type="por_el0_fmt"/>
> +    <field name="Pd" start="52" end="55" type="por_el0_fmt"/>
> +    <field name="Pc" start="48" end="51" type="por_el0_fmt"/>
> +    <field name="Pb" start="44" end="47" type="por_el0_fmt"/>
> +    <field name="Pa" start="40" end="43" type="por_el0_fmt"/>
> +    <field name="P9" start="36" end="39" type="por_el0_fmt"/>
> +    <field name="P8" start="32" end="35" type="por_el0_fmt"/>
> +    <field name="P7" start="28" end="31" type="por_el0_fmt"/>
> +    <field name="P6" start="24" end="27" type="por_el0_fmt"/>
> +    <field name="P5" start="20" end="23" type="por_el0_fmt"/>
> +    <field name="P4" start="16" end="19" type="por_el0_fmt"/>
> +    <field name="P3" start="12" end="15" type="por_el0_fmt"/>
> +    <field name="P2" start="8" end="11" type="por_el0_fmt"/>
> +    <field name="P1" start="4" end="7" type="por_el0_fmt"/>
> +    <field name="P0" start="0" end="3" type="por_el0_fmt"/>
> +  </flags>
> +
> +  <reg name="por_el0" bitsize="64" type="por_el0_flags" group="system"/>
> +</feature>
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index a7381677498..44236ebe86e 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -366,8 +366,13 @@ linux_get_siginfo_type (struct gdbarch *gdbarch)
>   
>     /* _sigfault */
>     type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
> -  append_composite_type_field (type, "si_addr", void_ptr_type);
> -  append_composite_type_field (sifields_type, "_sigfault", type);
> +   {
> +     int size_of_ptr = gdbarch_ptr_bit (gdbarch) / HOST_CHAR_BIT;
> +     append_composite_type_field (type, "si_addr", void_ptr_type);
> +     append_composite_type_field (type, "_pad", init_vector_type (builtin_type (gdbarch)->builtin_char, size_of_ptr));
> +     append_composite_type_field (type, "si_pkey", builtin_type (gdbarch)->builtin_uint32);
> +     append_composite_type_field (sifields_type, "_sigfault", type);
> +   }
>   

There is already an upstream patch in review to align this definition of siginfo_t with the latest 
version in the Linux kernel.

https://inbox.sourceware.org/gdb-patches/20260612101610.592338-1-matthieu.longo@arm.com/

Please, rebase your code on this patch.

>     /* _sigpoll */
>     type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT);
> diff --git a/gdb/nat/aarch64-poe.h b/gdb/nat/aarch64-poe.h
> new file mode 100644
> index 00000000000..3221634fd25
> --- /dev/null
> +++ b/gdb/nat/aarch64-poe.h
> @@ -0,0 +1,49 @@
> +/* Common native Linux definitions for AArch64 Permission Overlay Extension.
> +
> +   Copyright (C) 2026 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef GDB_NAT_AARCH64_POE_H
> +#define GDB_NAT_AARCH64_POE_H
> +
> +#include <stdint.h>
> +#include <asm/hwcap.h>
> +#include <asm/ptrace.h>
> +
> +/* Feature check for Permission Overlay Extension.  */
> +#ifndef HWCAP2_POE
> +#define HWCAP2_POE (1ULL << 63)
> +#endif

Same as the next question.
This should be defined by one of the system headers: https://docs.kernel.org/arch/arm64/elf_hwcaps.html

> +
> +#ifndef HAVE_STRUCT_USER_POE
> +
> +/* POE state (NT_ARM_POE).  */
> +#ifndef NT_ARM_POE
> +#define NT_ARM_POE 0x40f
> +#endif

Why is this define needed ?
Should it come from a system header ? --> 
https://github.com/torvalds/linux/blob/6edc20078ad0b05ab2dc2693965d373628d65f80/include/uapi/linux/elf.h#L529
Or is it from non-Linux systems ?

> +
> +struct user_poe
> +{
> +  uint64_t por_el0;
> +};

You don't need to declare a structure for the read operation.
There is only one register.

> +
> +#endif /* HAVE_STRUCT_USER_POE */
> +
> +/* The POE regset consists of 1 64-bit register.  */
> +#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)
> +
> +#endif /* GDB_NAT_AARCH64_POE_H */
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
> new file mode 100644
> index 00000000000..6b0c07e782f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c
> @@ -0,0 +1,52 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2026 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 AArch64's POE Extension.  */
> +
> +/* This test is based on the Linux kernel documentation for Memory
> +   Protection Keys, including the arm64 Permission Overlay Extension
> +   (FEAT_S1POE) support described in
> +   Documentation/core-api/protection-keys.rst.  */
> +
> +#define _GNU_SOURCE
> +#include <sys/mman.h>
> +#include <unistd.h>
> +
> +int
> +main (void)
> +{
> +  long pagesize = sysconf (_SC_PAGESIZE);
> +
> +  int *buf = mmap (NULL, pagesize, PROT_READ | PROT_WRITE,
> +		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +  if (buf == MAP_FAILED)
> +    return 1;
> +
> +  int pkey = pkey_alloc (0, 0);
> +  if (pkey == -1)
> +    return 1;
> +
> +  if (pkey_mprotect (buf, pagesize, PROT_READ | PROT_WRITE, pkey) == -1)
> +    return 1;
> +
> +  if (pkey_set (pkey, PKEY_DISABLE_WRITE) == -1)
> +    return 1;
> +
> +  buf[0] = 42;  /* Expect SIGSEGV POE violation.  */
> +
> +  return 1;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
> new file mode 100644
> index 00000000000..dfd91f652f0
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp

* Question for maintainers: *

All the architectural tests are already in the same directory, so moving them inside subdirectories 
(one per architecture) is out of scope of this patch.
However, would it make sense to do it in a separate patch ?
This directory starts getting very messy.

> @@ -0,0 +1,51 @@
> +# Copyright (C) 2026 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/>.
> +
> +# Test a binary that uses POE and exposed POR_EL0 register.
> +
> +global hex
> +global decimal
> +
> +require is_aarch64_target
> +
> +if {![allow_aarch64_poe_tests]} {
> +    unsupported "AArch64 POE not supported"
> +    return
> +}
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> +    return
> +}
> +
> +if {![runto_main]} {
> +    return
> +}
> +
> +# Display POE violation SIGSEGV error message.
> +set poe_sigsegv_re [multi_line \
> +    "Program received signal SIGSEGV, Segmentation fault" \
> +    "Protection overlay violation while accessing address ${hex}" \
> +    "POR_EL0\\\[Protection-Key=${decimal}\\\] = \[-rwx\]+ \\(${decimal}\\) Thread Id = ${decimal}"]
> +
> +gdb_test_multiple "continue" "display POE violation information" {
> +    -re "$poe_sigsegv_re.*$gdb_prompt $" {
> +	pass $gdb_test_name
> +    }
> +
> +    -re ".*exited with code 01.*$gdb_prompt $" {
> +	unsupported "POE userspace support unavailable"
> +    }
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe.c b/gdb/testsuite/gdb.arch/aarch64-poe.c
> new file mode 100644
> index 00000000000..2c95dc2a99b
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe.c
> @@ -0,0 +1,29 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2026 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 AArch64's POE Extension.  */
> +
> +/* This test is based on the Linux kernel documentation for Memory
> +   Protection Keys, including the arm64 Permission Overlay Extension
> +   (FEAT_S1POE) support described in
> +   Documentation/core-api/protection-keys.rst.  */
> +
> +int
> +main (void)
> +{
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-poe.exp b/gdb/testsuite/gdb.arch/aarch64-poe.exp
> new file mode 100644
> index 00000000000..ae2663a7dbc
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-poe.exp
> @@ -0,0 +1,44 @@
> +# Copyright (C) 2026 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/>.
> +
> +# Test a binary that uses POE and exposed POR_EL0 register.
> +
> +global hex
> +global decimal
> +
> +require is_aarch64_target
> +
> +if {![allow_aarch64_poe_tests]} {
> +    unsupported "AArch64 POE not supported"
> +    return
> +}
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> +    return
> +}
> +
> +if {![runto_main]} {
> +    return
> +}
> +
> +# Validate the presence of the POE register.
> +    gdb_test "info registers por_el0" \
> +	     "por_el0\[ \t\]+$hex.*" \
> +	     "register por_el0 available"
> +
> +    gdb_test "p/x \$por_el0" \
> +	     "\\$\[0-9\]+ = ${hex}" \
> +	     "print por_el0"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 7b1feeaac84..fe2c533791c 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -5616,6 +5616,61 @@ gdb_caching_proc allow_aarch64_gcs_tests {} {
>       return $allow_gcs_tests
>   }
>   
> +# Run a test on the target to see if it supports AArch64 POE extensions.
> +# Return 1 if so, 0 if it does not.  Note this causes a restart of GDB.
> +
> +gdb_caching_proc allow_aarch64_poe_tests {} {
> +    global srcdir subdir gdb_prompt inferior_exited_re
> +
> +    set me "allow_aarch64_poe_tests"
> +
> +    if { ![is_aarch64_target]} {
> +	return 0
> +    }
> +
> +    # Compile a program that tests the POE feature.
> +    set src {
> +	#include <stdbool.h>
> +	#include <sys/auxv.h>
> +
> +	/* Feature check for POE feature.  */
> +	#ifndef HWCAP2_POE
> +	#define HWCAP2_POE (1ULL << 63)
> +	#endif
> +
> +	int main (void) {
> +	    bool poe_supported = getauxval (AT_HWCAP2) & HWCAP2_POE;
> +
> +	    /* Return success if POE is supported.  */
> +	    return !poe_supported;
> +	}
> +    }
> +
> +    if {![gdb_simple_compile $me $src executable]} {
> +	return 0
> +    }
> +
> +    # Compilation succeeded so now run it via gdb.
> +    set allow_poe_tests 0
> +    clean_restart
> +    gdb_load $obj
> +    gdb_run_cmd
> +    gdb_expect {
> +	-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
> +	    verbose -log "\n$me: poe support detected"
> +	    set allow_poe_tests 1
> +	}
> +	-re ".*$inferior_exited_re with code 01.*${gdb_prompt} $" {
> +	    verbose -log "\n$me: poe support not detected"
> +	}
> +    }
> +    gdb_exit
> +    remote_file build delete $obj
> +
> +    verbose "$me:  returning $allow_poe_tests" 2
> +    return $allow_poe_tests
> +}
> +
>   # A helper that compiles a test case to see if __int128 is supported.
>   proc gdb_int128_helper {lang} {
>       return [gdb_can_simple_compile "i128-for-$lang" {
> diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
> index a2588a6e2a9..c27525be1ac 100644
> --- a/gdbserver/linux-aarch64-low.cc
> +++ b/gdbserver/linux-aarch64-low.cc
> @@ -45,6 +45,7 @@
>   #include "linux-aarch32-tdesc.h"
>   #include "linux-aarch64-tdesc.h"
>   #include "nat/aarch64-fpmr-linux.h"
> +#include "nat/aarch64-poe.h"
>   #include "nat/aarch64-gcs-linux.h"
>   #include "nat/aarch64-mte-linux-ptrace.h"
>   #include "nat/aarch64-scalable-linux-ptrace.h"
> @@ -250,6 +251,16 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
>     supply_register (regcache, AARCH64_FPCR_REGNUM, &regset->fpcr);
>   }
>   
> +/* Store the POE (POR_EL0) register set to regcache.  */
> +
> +static void
> +aarch64_store_por_el0_regset (struct regcache *regcache, const void *buf)
> +{
> +  const user_poe *regset = (const user_poe *) buf;
> +  int poe_regnum  = find_regno (regcache->tdesc, "por_el0");
> +  supply_register (regcache, poe_regnum, &regset->por_el0);
> +}
> +
>   /* Fill BUF with the FPMR register set from the regcache.  */
>   
>   static void
> @@ -901,6 +912,10 @@ static struct regset_info aarch64_regsets[] =
>     { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_FPMR,
>       0, OPTIONAL_REGS,
>       aarch64_fill_fpmr_regset, aarch64_store_fpmr_regset },
> +  /* POE register (POR_EL0).  */
> +  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_POE,
> +    0, OPTIONAL_REGS,
> +    nullptr, aarch64_store_por_el0_regset },
>     /* TLS register.  */
>     { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
>       0, OPTIONAL_REGS,
> @@ -980,6 +995,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features)
>   	  if (features.fpmr)
>   	    regset->size = sizeof (uint64_t);
>   	  break;
> +	case NT_ARM_POE:
> +	  if (features.poe)
> +	    regset->size = sizeof (user_poe);
> +	  break;
>   	default:
>   	  gdb_assert_not_reached ("Unknown register set found.");
>   	}
> @@ -1010,6 +1029,7 @@ aarch64_target::low_arch_setup ()
>         features.tls = aarch64_tls_register_count (tid);
>         features.gcs = features.gcs_linux = linux_get_hwcap (pid, 8) & HWCAP_GCS;
>         features.fpmr = linux_get_hwcap2 (pid, 8) & HWCAP2_FPMR;
> +      features.poe = linux_get_hwcap2 (pid, 8) & HWCAP2_POE;
>   
>         /* Scalable Matrix Extension feature and size check.  */
>         if (linux_get_hwcap2 (pid, 8) & HWCAP2_SME)


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

* Re: [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register
  2026-06-18 17:04 ` Matthieu Longo
@ 2026-06-21 11:32   ` Luis
  0 siblings, 0 replies; 5+ messages in thread
From: Luis @ 2026-06-21 11:32 UTC (permalink / raw)
  To: Matthieu Longo, srinath.parvathaneni, gdb-patches
  Cc: guinevere, thiago.bauermann

On 18/06/2026 18:04, Matthieu Longo wrote:
>> +  user_poe user_poe;
>> +  iovec iovec;
>> +
>> +  iovec.iov_base = &user_poe;
>> +  iovec.iov_len = sizeof (user_poe);
>> +
>> +  int tid = get_ptrace_pid (regcache->ptid ());
> 
> * Question for maintainers: *
> 
> It seems that there are different methods to get the thread ID.
> I observed in the same file 3 different ways:
> - int tid = get_ptrace_pid (inferior_ptid);
> - int tid = regcache->ptid ().lwp ();
> - int tid = get_ptrace_pid (regcache->ptid ());
> 
> What is the "correct" method ?
> 

get_ptrace_pid here.

> 
> * Question for maintainers: *
> 
> All the architectural tests are already in the same directory, so moving 
> them inside subdirectories (one per architecture) is out of scope of 
> this patch.
> However, would it make sense to do it in a separate patch ?
> This directory starts getting very messy.
> 

Seems like a worthwhile refactor, but I'm not sure off the top of my 
head how the current makefile infra will handle it. If we decide to run 
gdb.arch tests, will it run gdb.arch/aarch64/*.exp?

I'm all for keeping things clean, but it needs to make it simple as well.

Thanks for the reviews by the way.

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

* Re: [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register
  2026-06-17 17:00 [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register srinath.parvathaneni
  2026-06-17 23:38 ` Ezra Sitorus
  2026-06-18 17:04 ` Matthieu Longo
@ 2026-06-21 11:50 ` Luis
  2 siblings, 0 replies; 5+ messages in thread
From: Luis @ 2026-06-21 11:50 UTC (permalink / raw)
  To: srinath.parvathaneni, gdb-patches; +Cc: guinevere, thiago.bauermann

On Wed, Jun 17, 2026 at 05:00:03PM +0000, srinath.parvathaneni@arm.com 
wrote:
 > From: Srinath Parvathaneni <srinath.parvathaneni@arm.com>
 >
 > Hi,
 >
 > FEAT_S1POE introduces the POR_EL0 register. This patch adds
 > support for POR_EL0 in both native GDB and gdbserver using
 > NT_ARM_POE and HWCAP2_POE detection.

Hi Srinath,

Thanks for the patch. A few comments below (some might overlap with what 
Ezra and Matthieu already raised).

 > +/* Feature check for Permission Overlay Extension.  */

Nit: FEAT_S1POE stands for Stage 1 Permission Overlay Enhancement,
not Extension. Please fix the comment.

 > +#ifndef HWCAP2_POE
 > +#define AARCH64_HWCAP2_POE (1ULL << 63)
 > +#endif

The #ifndef guard checks HWCAP2_POE but the macro being defined is
AARCH64_HWCAP2_POE. If a system header has already provided
HWCAP2_POE, AARCH64_HWCAP2_POE will silently remain undefined.

   #ifndef AARCH64_HWCAP2_POE
   #define AARCH64_HWCAP2_POE (1ULL << 63)
   #endif

 > +#ifndef AARCH64_SEGV_PKUERR
 > +#define AARCH64_SEGV_PKUERR 4  /* Protection overlay violation.  */
 > +#endif

Make it more informative:

   /* Data or instruction abort caused by a POE violation.  */

 > +/* The POE regset consists of 1 64-bit register.  */
 > +#define AARCH64_LINUX_SIZEOF_POE_REGSET (8)

Drop the parenthesis.

 > +#endif /* GDB_ARCH_AARCH64_POE_H */

Once the file is renamed the guard should become
GDB_ARCH_AARCH64_POE_LINUX_H.

 > diff --git a/gdb/nat/aarch64-poe.h b/gdb/nat/aarch64-poe.h
 > new file mode 100644
 > @@ -0,0 +1,49 @@
 > +#ifndef HWCAP2_POE
 > +#define HWCAP2_POE (1ULL << 63)
 > +#endif

<asm/hwcap.h> defines this on kernels >= 6.9. Is this fallback needed, 
and if so, why?

 > +#ifndef NT_ARM_POE
 > +#define NT_ARM_POE 0x40f
 > +#endif

Same question. This is in <uapi/linux/elf.h> on recent kernels.

 > +struct user_poe
 > +{
 > +  uint64_t por_el0;
 > +};

Why a struct for a single scalar? A bare uint64_t works fine here.

 > diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
 > @@ -208,6 +208,16 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
 >       return gcs_linux_reg_base != -1;
 >     }
 >
 > +  /* First POE register.  This is -1 if no POE feature is available.  */
 > +  int poe_regnum = -1;

"First POE register" implies there may be more than one. Since there
is exactly one, please use:

   /* Index of the POE register.  This is -1 if POE is not supported.  */

Upstream master now has comments for every other boolean in this
struct. Please add a comment as well.

 > diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h
 > @@ -35,6 +35,7 @@ struct aarch64_features
 >       bool pauth = false;
 >       bool mte = false;
 >       bool fpmr = false;
 > +  bool poe = false;

Missing comment. Please add:

   /* Whether the Permission Overlay Extension (FEAT_S1POE) is
      supported.  */

 > diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
 > +/* Fill GDB's register array with the POE register value from the 
current
 > +   thread.  */
 > +
 > +static void
 > +fetch_por_el0_from_thread (regcache *regcache)

The convention for fetch functions in this file is to name them after
the feature or register group, not the specific register:
   fetch_fpmr_from_thread
   fetch_gcsregs_from_thread
   fetch_tlsregs_from_thread

Please rename to fetch_poereg_from_thread.

 > +{
 > +  aarch64_gdbarch_tdep *tdep
 > +      = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
 > +
 > +  gdb_assert (tdep->poe_regnum != -1);

Please use:

   gdb_assert (tdep->has_poe ());

 > +  user_poe user_poe;
 > +  iovec iovec;

Letś not use a variable with the same name as the type.

 > +  int tid = get_ptrace_pid (regcache->ptid ());

get_ptrace_pid here looks correct, as we have the regcache information.

 > diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
 > +/* Convert a POR_EL0 Perm<m> overlay permission encoding into 
rwx-style string.
 > +   For example:
 > +      0b0011 -> "r-x" (3)
 > +      0b0101 -> "rw-" (5)
 > +      0b0111 -> "rwx" (7)
 > +      0b0000 -> "---" (0)
 > +   Reserved encodings (0b1xxx) are returned as "???".  */
 > +
 > +static const char*
 > +aarch64_perm_overlay_decode (unsigned int perm)

Missing space before *.

 > +/* For POE SEGSEGV, show additional information.  */

Typo: SEGSEGV should be SIGSEGV.

 > +  else if (si_code == AARCH64_SEGV_PKUERR && si_errno == 0)
 > +    meaning = _("Protection overlay violation");

The si_errno == 0 condition is not meaningful for SEGV_PKUERR. si_errno
is not used to qualify this signal code, is it?

If so...

   else if (si_code == AARCH64_SEGV_PKUERR)
     meaning = _("Protection overlay violation");

 > diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
 > +  if (features.poe)
 > +    regnum = create_feature_aarch64_poe (tdesc.get (), regnum);

Is identation off here?

 > diff --git a/gdbserver/linux-aarch64-low.cc 
b/gdbserver/linux-aarch64-low.cc
 > +static void
 > +aarch64_store_por_el0_regset (struct regcache *regcache, const void 
*buf)
 > +{
 > +  const user_poe *regset = (const user_poe *) buf;
 > +  int poe_regnum  = find_regno (regcache->tdesc, "por_el0");

Single space before =.

 > +  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_POE,
 > +    0, OPTIONAL_REGS,
 > +    nullptr, aarch64_store_por_el0_regset },

Document/Add comment that we don´t support writing for now.

Also document/add comment stating we lack core file support as well.

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

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

end of thread, other threads:[~2026-06-21 11:51 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-17 17:00 [PATCH v1] gdb/aarch64: Add support for FEAT_S1POE POR_EL0 register srinath.parvathaneni
2026-06-17 23:38 ` Ezra Sitorus
2026-06-18 17:04 ` Matthieu Longo
2026-06-21 11:32   ` Luis
2026-06-21 11:50 ` Luis

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