Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE
@ 2026-09-16  9:17 srinath.parvathaneni
  2026-09-16  9:17 ` [PATCH v5 1/5] " srinath.parvathaneni
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: srinath.parvathaneni @ 2026-09-16  9:17 UTC (permalink / raw)
  To: gdb-patches
  Cc: simark, luis.machado.foss, thiago.bauermann, guinevere,
	Ezra.Sitorus, Matthieu.Longo, peter.maydell,
	Srinath Parvathaneni

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

Changes v4 -> V5:

Patch 1:
* Remove "struct" from the all declarations.
* Use the gdb::array_view overload of store_unsigned_integer when
  storing/featching the pseudo-register value.
* Make gdb/arch/aarch64-poe-linux.h check-include-guards.py compliant
  and move this file to patch 2 instead.
* Update the gdb/Makefine.in.
* <asm/hwcap.h> included inside the macro guard in nat/arch/aarch64-poe-linux.h.
* Add documentation for AArch64 POE register support, including the
  decoded POR_EL0 display, individual permission pseudo-registers and
  the POR register group.

Patch 2:
* Move the file gdb/arch/aarch64-poe-linux.h from patch 1 to patch 2.
* Update the gdb/Makefine.in.

Patch 3:
Patch 4:
Patch 5:
* No functional changes.
---------------------------------------------------------------------

Changes v3 -> v4:

Patch 1:
* Address review comments and update the POR_EL0 interface based on the
  discussion.
* Keep POR_EL0 as a raw uint64 in the target description and move the
  permission decoding out of the XML.
* Add por_p0 through por_p15 pseudo-registers, with each pseudo-register
  mapping to the corresponding 4-bit field in POR_EL0.
* Add read/write support for the POE pseudo-registers. Writing a
  pseudo-register updates the corresponding field in POR_EL0.
* Add the "por" register group containing POR_EL0 and the POE
  pseudo-registers.
* Update the POR_EL0 display to omit zero valued fields and split long
  output across multiple lines.
* Add custom permission display for the POE pseudo-registers.

Patch 2:
* Address review comments.
* Rebase to use the generic gdb_si accessors for si_code, si_errno,
  si_addr and si_pkey.
* Fix the SIGSEGV comment and mark the protection-key diagnostic for
  translation.

Patch 3:
* Rebased.
* No functional changes.

Patch 4:
* Rebased.
* Update the patch subject to mention both core file and signal frame
  support.
* Address review comments.

Patch 5:
* Address review comments.
* Add a POE signal frame test to verify that POR_EL0 is restored from
  the saved signal context while unwinding.
* Add tests for the new "por" register group and POE pseudo-registers.
* Use "require allow_aarch64_poe_tests" in the POE tests.
* Remove the stray aarch64-poe-sigsegv. file.
* Update the tests for the new POR_EL0 interface.

-----------------------------
Changes v2 -> v3:
Patch 1:
* Address review comments.
* After discussion, retain the _EL0 suffix for the POE register.
* Merge the POR_EL0 custom printing support from v2 Patch 2.
* Update the XML description to use the POR_EL0_FLAGS type for
  custom register printing.

Patch 2:
* Corresponds to v2 Patch 3.
* No functional changes.
* Approved by Thiago Jung Bauermann.

Patch 3:
* Corresponds to v2 Patch 4.
* No functional changes.
* Approved by Thiago Jung Bauermann.

Patch 4:
* The BFD/readelf changes from v2 Patch 5 have been posted separately
  to binutils-gdb and have since been approved and committed.
* Corresponds to v2 Patch 6.
* Address review comments on the GDB core file support.

Patch 5:
* Corresponds to v2 Patch 7.
* Address review comments.
* Update the tests to reflect the POR_EL0 custom string shown by
  `info registers por_el0` and `print $por_el0`.
* Fix aarch64-poe-core.exp test issues.

* Rebased onto current upstream master, including:
  * Matthieu Longo's "gdb: align siginfo_t with the Linux kernel definition".
  * My "gdb: Fix assignment to TYPE_CODE_FLAGS registers" patch.
----------------

Changes v1 -> v2:

* Rebased the SIGSEGV diagnostic support on Matthieu Longo's generic
  "siginfo_t" changes, using the new "_._addr_pkey.si_pkey" layout
  instead of introducing a target-specific "siginfo_t" extension.
* Split the original series into smaller, subsystem-specific patches:
  * GDB register support
  * POR_EL0 pretty printing
  * SIGSEGV diagnostics
  * gdbserver support
  * BFD/readelf core file support
  * GDB core file support
  * Testsuite
* Separated BFD/readelf and GDB core file support into independent
  patches.
* Retained FEAT_S1POE expansion as "Permission Overlay Extension" after internal discussion.
* Removed the POR_EL0 permission decoding string (e.g. `por_el0[pkey=<value>] = rwx`) from
  SIGSEGV diagnostics, as displaying permissions without also showing base and effective
  permissions can be misleading to users.
* Rebased the series onto current upstream master + Matthieu's patch
  "gdb: align siginfo_t with the Linux kernel definition"

-------------------------------

Hi,

This series adds support for the AArch64 Permission Overlay Extension
(FEAT_S1POE) in GDB and gdbserver.

The series adds support for the POR_EL0 register, allowing GDB to read
and write it using the Linux NT_ARM_POE regset.

It also adds POE pseudo-registers por_p0 through por_p15, with each
pseudo-register mapping to the corresponding 4-bit permission field in
POR_EL0. POR_EL0 and the pseudo-registers are added to the "por"
register group so they can be displayed together using
"info registers por".

The series also improves SIGSEGV diagnostics for Permission Overlay
violations, adds gdbserver support for POR_EL0, adds core file support
and restores POR_EL0 while unwinding through signal frames.

The BFD/readelf support for the NT_ARM_POE core note was posted
separately and has already been approved and committed:

commit d15490528409305f97004a2860fdb04543862774
Author: Srinath Parvathaneni srinath.parvathaneni@arm.com
Date: Thu Jul 2 13:57:25 2026 +0000

bfd/readelf: Add core file support for FEAT_S1POE

The series consists of the following patches:

[1/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE

Add support for reading and writing POR_EL0 using the Linux NT_ARM_POE
regset. Add por_p0 through por_p15 pseudo-registers for accessing the
individual permission fields in POR_EL0, and add the "por" register
group for displaying the POE register state.

[2/5] gdb: Improve SIGSEGV diagnostics for POE faults

Report the faulting address together with the associated protection key
for Permission Overlay violations.

[3/5] gdbserver/aarch64: Add POR_EL0 register support

Transfer POR_EL0 using the Linux NT_ARM_POE regset during remote
debugging.

[4/5] gdb/aarch64: Add core file and signal frame support for FEAT_S1POE

Restore POR_EL0 from Linux core files and from the POE context while
unwinding through signal frames.

[5/5] gdb/testsuite: Add FEAT_S1POE testcases

Add tests for POR_EL0 and the POE pseudo-registers, the "por" register
group, SIGSEGV diagnostics, fix-and-continue support, core file support
and signal frame unwinding.

The series has been tested natively and using gdbserver with remote GDB
on an FVP built using shrinkwrap with a Linux kernel configured with
CONFIG_ARM64_POE=y and a glibc version providing userspace POE support.

Regression tested on aarch64-none-linux-gnu with no regressions.

Ok for GDB master?

Srinath Parvathaneni (5):
  gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE
  gdb: Improve SIGSEGV diagnostics for POE faults
  gdbserver/aarch64: Add POR_EL0 register support
  gdb/aarch64: Add core file and signal frame support for FEAT_S1POE
  gdb/testsuite: Add FEAT_S1POE testcases

 gdb/Makefile.in                               |   2 +
 gdb/aarch64-linux-nat.c                       |  64 +++++
 gdb/aarch64-linux-tdep.c                      |  68 ++++-
 gdb/aarch64-tdep.c                            | 268 ++++++++++++++++++
 gdb/aarch64-tdep.h                            |  12 +
 gdb/arch/aarch64-poe-linux.h                  |  29 ++
 gdb/arch/aarch64.c                            |   4 +
 gdb/arch/aarch64.h                            |   8 +-
 gdb/doc/gdb.texinfo                           |  38 +++
 gdb/features/Makefile                         |   1 +
 gdb/features/aarch64-poe.c                    |  14 +
 gdb/features/aarch64-poe.xml                  |  11 +
 gdb/nat/aarch64-poe-linux.h                   |  30 ++
 gdb/testsuite/gdb.arch/aarch64-poe-core.exp   | 101 +++++++
 gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c |  45 +++
 .../gdb.arch/aarch64-poe-sigframe.exp         |  55 ++++
 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c  |  52 ++++
 .../gdb.arch/aarch64-poe-sigsegv.exp          |  55 ++++
 gdb/testsuite/gdb.arch/aarch64-poe.c          |  29 ++
 gdb/testsuite/gdb.arch/aarch64-poe.exp        |  60 ++++
 gdb/testsuite/lib/gdb.exp                     |  55 ++++
 gdbserver/linux-aarch64-low.cc                |  30 ++
 22 files changed, 1027 insertions(+), 4 deletions(-)
 create mode 100644 gdb/arch/aarch64-poe-linux.h
 create mode 100644 gdb/features/aarch64-poe.c
 create mode 100644 gdb/features/aarch64-poe.xml
 create mode 100644 gdb/nat/aarch64-poe-linux.h
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-core.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigframe.exp
 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

-- 
2.43.0


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

* [PATCH v5 1/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE
  2026-09-16  9:17 [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE srinath.parvathaneni
@ 2026-09-16  9:17 ` srinath.parvathaneni
  2026-09-16  9:18 ` [PATCH v5 2/5] gdb: Improve SIGSEGV diagnostics for POE faults srinath.parvathaneni
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: srinath.parvathaneni @ 2026-09-16  9:17 UTC (permalink / raw)
  To: gdb-patches
  Cc: simark, luis.machado.foss, thiago.bauermann, guinevere,
	Ezra.Sitorus, Matthieu.Longo, peter.maydell,
	Srinath Parvathaneni

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

Add support for the FEAT_S1POE POR_EL0 register on AArch64.

This patch adds POR_EL0 to the AArch64 register set and reads/writes it
using the NT_ARM_POE ptrace regset.

It also adds POE pseudo-registers por_p0 through por_p15, with each
pseudo-register mapping to a 4-bit field in POR_EL0, starting from the
least-significant nibble.

POR_EL0 and the POE pseudo-registers are added to the "por" register
group, allowing them to be displayed together using the
"info registers por" command.

With this change, POR_EL0 is accessible through:

* info registers
* info registers por_el0
* info registers por
* p $por_el0
* p/x $por_el0
* set $por_el0 = <value>

The individual POE fields can also be accessed and modified through
$por_p0 to $por_p15.

Example:
(gdb) info register por_el0
por_el0        0x7                 [ P0=rwx ]
(gdb) set $por_el0=0xffffffff77777777
(gdb) info registers por_el0
por_el0        0xffffffff77777777 [ P15=??? P14=??? P13=??? P12=???
                                    P11=??? P10=??? P9=??? P8=???
                                    P7=rwx P6=rwx P5=rwx P4=rwx
                                    P3=rwx P2=rwx P1=rwx P0=rwx ]
(gdb) info registers por
por_el0        0xffffffff77777777 [ P15=??? P14=??? P13=??? P12=???
                                    P11=??? P10=??? P9=??? P8=???
                                    P7=rwx P6=rwx P5=rwx P4=rwx
                                    P3=rwx P2=rwx P1=rwx P0=rwx ]
por_p0         0x7                rwx
por_p1         0x7                rwx
por_p2         0x7                rwx
por_p3         0x7                rwx
por_p4         0x7                rwx
por_p5         0x7                rwx
por_p6         0x7                rwx
por_p7         0x7                rwx
por_p8         0xf                ???
por_p9         0xf                ???
por_p10        0xf                ???
por_p11        0xf                ???
por_p12        0xf                ???
por_p13        0xf                ???
por_p14        0xf                ???
por_p15        0xf                ???

Individual POE pseudo-registers can be written independently, with the
corresponding 4-bit field in POR_EL0 updated accordingly.  For example:

(gdb) set $por_el0=0x7
(gdb) info registers por_el0
por_el0        0x0000000000000007 [ P0=rwx ]
(gdb) set $por_p1=0x7
(gdb) info registers por_el0
por_el0        0x0000000000000077 [ P1=rwx P0=rwx ]
---
 gdb/Makefile.in              |   1 +
 gdb/aarch64-linux-nat.c      |  64 +++++++++
 gdb/aarch64-tdep.c           | 268 +++++++++++++++++++++++++++++++++++
 gdb/aarch64-tdep.h           |  12 ++
 gdb/arch/aarch64.c           |   4 +
 gdb/arch/aarch64.h           |   8 +-
 gdb/doc/gdb.texinfo          |  38 +++++
 gdb/features/Makefile        |   1 +
 gdb/features/aarch64-poe.c   |  14 ++
 gdb/features/aarch64-poe.xml |  11 ++
 gdb/nat/aarch64-poe-linux.h  |  30 ++++
 11 files changed, 450 insertions(+), 1 deletion(-)
 create mode 100644 gdb/features/aarch64-poe.c
 create mode 100644 gdb/features/aarch64-poe.xml
 create mode 100644 gdb/nat/aarch64-poe-linux.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index d1574ec2d2c..6909123e863 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1545,6 +1545,7 @@ HFILES_NO_SRCDIR = \
 	nat/aarch64-linux-hw-point.h \
 	nat/aarch64-mte-linux-ptrace.h \
 	nat/aarch64-pauth-linux.h \
+	nat/aarch64-poe-linux.h \
 	nat/aarch64-scalable-linux-ptrace.h \
 	nat/aarch64-scalable-linux-sigcontext.h \
 	nat/amd64-linux.h \
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 52ace4aab41..f1de070695d 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-linux.h"
 #include "nat/aarch64-linux.h"
 #include "nat/aarch64-linux-hw-point.h"
 #include "nat/aarch64-mte-linux-ptrace.h"
@@ -602,6 +603,54 @@ store_gcsregs_to_thread (regcache *regcache)
     perror_with_name (_("Unable to store GCS registers"));
 }
 
+/* Fill GDB's register array with the POE register value from the current
+   thread.  */
+
+static void
+fetch_poeregs_from_thread (regcache *regcache)
+{
+  aarch64_gdbarch_tdep *tdep
+    = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+  gdb_assert (tdep->has_poe ());
+
+  uint64_t 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);
+}
+
+/* Store the NT_ARM_POE register value from GDB's REGCACHE to the thread
+   associated with REGCACHE.  */
+
+static void
+store_poeregs_to_thread (regcache *regcache)
+{
+  aarch64_gdbarch_tdep *tdep
+    = gdbarch_tdep<aarch64_gdbarch_tdep> (regcache->arch ());
+
+  gdb_assert (tdep->has_poe ());
+
+  int tid = regcache->ptid ().lwp ();
+
+  iovec iovec;
+  uint64_t user_poe;
+  iovec.iov_base = &user_poe;
+  iovec.iov_len = sizeof (user_poe);
+
+  regcache->raw_collect (tdep->poe_regnum, &user_poe);
+
+  if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_POE, &iovec) != 0)
+    perror_with_name (_("Unable to store POE register"));
+}
+
 /* Fill GDB's REGCACHE with the FPMR register set content from the
    thread associated with REGCACHE.  */
 
@@ -683,6 +732,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
       if (tdep->has_gcs_linux ())
 	fetch_gcsregs_from_thread (regcache);
 
+      if (tdep->has_poe ())
+	fetch_poeregs_from_thread (regcache);
+
       if (tdep->has_fpmr ())
 	fetch_fpmr_from_thread (regcache);
     }
@@ -722,6 +774,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno)
 	   && (regno == tdep->gcs_reg_base || regno == tdep->gcs_linux_reg_base
 	       || regno == tdep->gcs_linux_reg_base + 1))
     fetch_gcsregs_from_thread (regcache);
+  /* POE register?  */
+  else if (tdep->has_poe () && (regno == tdep->poe_regnum))
+    fetch_poeregs_from_thread (regcache);
   /* FPMR?  */
   else if (tdep->has_fpmr () && (regno == tdep->fpmr_regnum))
     fetch_fpmr_from_thread (regcache);
@@ -802,6 +857,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
 
       if (tdep->has_fpmr ())
 	store_fpmr_to_thread (regcache);
+
+      if (tdep->has_poe ())
+	store_poeregs_to_thread (regcache);
     }
   /* General purpose register?  */
   else if (regno < AARCH64_V0_REGNUM)
@@ -836,6 +894,9 @@ aarch64_store_registers (struct regcache *regcache, int regno)
   /* FPMR?  */
   else if (tdep->has_fpmr () && regno == tdep->fpmr_regnum)
     store_fpmr_to_thread (regcache);
+  /* POE register?  */
+  else if (tdep->has_poe () && regno == tdep->poe_regnum)
+    store_poeregs_to_thread (regcache);
 
   /* PAuth registers are read-only.  */
 }
@@ -1024,6 +1085,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-tdep.c b/gdb/aarch64-tdep.c
index 950ad4f6aae..10b74ff1438 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -164,6 +164,11 @@ static const char *const aarch64_gcs_register_names[] = {
   "gcspr"
 };
 
+static const char *const aarch64_poe_register_names[] = {
+  /* Permission Overlay Extension Register.  */
+  "por_el0"
+};
+
 static const char *const aarch64_gcs_linux_register_names[] = {
   /* Field in struct user_gcs.  */
   "gcs_features_enabled",
@@ -2892,6 +2897,21 @@ is_w_pseudo_register (struct gdbarch *gdbarch, int regnum)
   return false;
 }
 
+/* Return TRUE if REGNUM is a POE pseudo-register number.  Return FALSE
+   otherwise.  */
+
+static bool
+is_poe_pseudo_register (gdbarch *gdbarch, int regnum)
+{
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+  if (tdep->poe_pseudo_base <= regnum
+      && regnum < tdep->poe_pseudo_base + tdep->poe_pseudo_count)
+    return true;
+
+  return false;
+}
+
 /* Return TRUE if REGNUM is a SME pseudo-register number.  Return FALSE
    otherwise.  */
 
@@ -3088,6 +3108,21 @@ aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
   if (tdep->has_pauth () && regnum == tdep->ra_sign_state_regnum)
     return "";
 
+  if (tdep->has_poe ())
+    {
+      static const char *const poe_name[] =
+	{
+	  "por_p0", "por_p1", "por_p2", "por_p3",
+	  "por_p4", "por_p5", "por_p6", "por_p7",
+	  "por_p8", "por_p9", "por_p10", "por_p11",
+	  "por_p12", "por_p13", "por_p14", "por_p15",
+	};
+
+      /* POE pseudo-registers.  */
+      if (is_poe_pseudo_register (gdbarch, regnum))
+	return poe_name[regnum - tdep->poe_pseudo_base];
+    }
+
   internal_error (_("aarch64_pseudo_register_name: bad register number %d"),
 		  p_regnum);
 }
@@ -3130,10 +3165,130 @@ aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
   if (tdep->has_pauth () && regnum == tdep->ra_sign_state_regnum)
     return builtin_type (gdbarch)->builtin_uint64;
 
+  /* POE pseudo-registers are 8-bit.  */
+  if (is_poe_pseudo_register (gdbarch, regnum))
+    return builtin_type (gdbarch)->builtin_uint8;
+
   internal_error (_("aarch64_pseudo_register_type: bad register number %d"),
 		  p_regnum);
 }
 
+/* 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 "???";
+   }
+}
+
+/* Display POE register POR_EL0 in the following format for the 'info registers'
+   and 'info all-registers' commands:
+   <register-name> <hex-value> [<decoded per-protection-key permissions>]  */
+
+static void
+aarch64_print_poe_register_info (ui_file *file, int regnum, const char *name,
+				 const frame_info_ptr &frame)
+{
+  value *val = value_of_register (regnum, get_next_frame_sentinel_okay (frame));
+  ULONGEST por_el0 = (ULONGEST) value_as_long (val);
+  gdb_printf (file, "%-14s 0x%s [ ", name, phex (por_el0, 8));
+  const int line_wrap_count = 36;
+
+  for (int i = 15, line_wrap = 0; i >= 0; --i)
+    {
+      unsigned int perm = (por_el0 >> (i * 4)) & 0xf;
+      if (perm)
+	{
+	  if (line_wrap != 0 && (line_wrap % 4) == 0)
+	    gdb_printf (file, "\n%*s", line_wrap_count, "");
+	  gdb_printf (file, "P%d=%s ", i, aarch64_perm_overlay_decode (perm));
+	  line_wrap++;
+	}
+    }
+  gdb_puts ("]\n", file);
+}
+
+/* Custom display for POE pseudo registers.  */
+
+static void
+aarch64_print_poe_pseudo_register_info (ui_file *file, int regnum,
+					const char *name,
+					const frame_info_ptr &frame)
+{
+  value *val = value_of_register (regnum, get_next_frame_sentinel_okay (frame));
+  gdbarch *gdbarch = get_frame_arch (frame);
+  unsigned int perm = extract_unsigned_integer (val->contents (),
+						gdbarch_byte_order (gdbarch));
+
+  /* Extract only the least significant 4 bits.  */
+  perm &= 0xf;
+
+  gdb_printf (file, "%-14s 0x%-16x %s\n", name, perm,
+	      aarch64_perm_overlay_decode (perm));
+}
+
+/* For 'info registers' and 'info all-registers', print POE POR_EL0 register and
+   POE pseudo registers using the custom register printer and all other
+   registers using the default register printer.  */
+
+static void
+aarch64_print_registers_info (gdbarch *gdbarch, ui_file *file,
+			      const frame_info_ptr &frame,
+			      int regnum,
+			      bool print_all)
+{
+  const int numregs = gdbarch_num_cooked_regs (gdbarch);
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+  /* When no register is specified.  */
+  if (regnum == -1)
+    {
+      for (int i = 0; i < numregs; i++)
+	{
+	  if (i == tdep->poe_regnum)
+	    {
+	      aarch64_print_poe_register_info
+		(file, i, gdbarch_register_name (gdbarch, i), frame);
+	      continue;
+	    }
+	  else if (is_poe_pseudo_register (gdbarch, i))
+	    {
+	      aarch64_print_poe_pseudo_register_info
+		(file, i, gdbarch_register_name (gdbarch, i), frame);
+	      continue;
+	    }
+	  default_print_registers_info (gdbarch, file, frame, i, print_all);
+	}
+    }
+  /* When POE por_el0 register is specified.  */
+  else if (regnum == tdep->poe_regnum)
+    aarch64_print_poe_register_info
+      (file, regnum, gdbarch_register_name (gdbarch, regnum), frame);
+  /* When individual POE pseudo register is specified.  */
+  else if (is_poe_pseudo_register (gdbarch, regnum))
+    aarch64_print_poe_pseudo_register_info
+      (file, regnum, gdbarch_register_name (gdbarch, regnum), frame);
+  else
+    default_print_registers_info (gdbarch, file, frame, regnum, print_all);
+}
+
 /* Implement the "pseudo_register_reggroup_p" tdesc_arch_data method.  */
 
 static bool
@@ -3161,6 +3316,8 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
     return group == all_reggroup || group == vector_reggroup;
   else if (is_sme_pseudo_register (gdbarch, regnum))
     return group == all_reggroup || group == vector_reggroup;
+  else if (is_poe_pseudo_register (gdbarch, regnum))
+    return group == all_reggroup || group == reggroup_find (gdbarch, "por");
   /* RA_STATE is used for unwinding only.  Do not assign it to any groups.  */
   if (tdep->has_pauth () && regnum == tdep->ra_sign_state_regnum)
     return false;
@@ -3290,7 +3447,36 @@ aarch64_sme_pseudo_register_read (gdbarch *gdbarch, const frame_info_ptr &next_f
       za_value->contents_copy (result, dst_offset, src_offset,
 			       offsets.chunk_size);
     }
+  return result;
+}
+
+/* Given REGNUM, a POE pseudo-register number, return its value in RESULT.  */
+
+static value *
+aarch64_poe_pseudo_register_read (gdbarch *gdbarch,
+				  const frame_info_ptr &next_frame,
+				  const int pseudo_reg_num)
+{
+  aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+  gdb_assert (tdep->has_poe ());
+  gdb_assert (tdep->poe_pseudo_base <= pseudo_reg_num);
+  gdb_assert (pseudo_reg_num < tdep->poe_pseudo_base + tdep->poe_pseudo_count);
+
+  unsigned int pkey = pseudo_reg_num - tdep->poe_pseudo_base;
+  unsigned int shift = pkey * 4;
+
+  value *por_value = value_of_register (tdep->poe_regnum, next_frame);
+  value *result = value::allocate_register (next_frame, pseudo_reg_num);
 
+  ULONGEST por_el0
+    = extract_unsigned_integer (por_value->contents (),
+				gdbarch_byte_order (gdbarch));
+
+  ULONGEST pseudo_reg_value = (por_el0 >> shift) & 0xf;
+
+  store_unsigned_integer (result->contents_raw (), gdbarch_byte_order (gdbarch),
+			  pseudo_reg_value);
   return result;
 }
 
@@ -3322,6 +3508,9 @@ aarch64_pseudo_read_value (gdbarch *gdbarch, const frame_info_ptr &next_frame,
   else if (is_sme_pseudo_register (gdbarch, pseudo_reg_num))
     return aarch64_sme_pseudo_register_read (gdbarch, next_frame,
 					     pseudo_reg_num);
+  else if (is_poe_pseudo_register (gdbarch, pseudo_reg_num))
+    return aarch64_poe_pseudo_register_read (gdbarch, next_frame,
+					     pseudo_reg_num);
 
   /* Offset in the "pseudo-register space".  */
   int pseudo_offset = pseudo_reg_num - gdbarch_num_regs (gdbarch);
@@ -3428,6 +3617,48 @@ aarch64_sme_pseudo_register_write (gdbarch *gdbarch, const frame_info_ptr &next_
 		      za_value->contents_raw ());
 }
 
+/* Given PSEUDO_REG_NUM, a POE pseudo-register number, store DATA in the
+   corresponding field of POR_EL0.  */
+
+static void
+aarch64_poe_pseudo_register_write (gdbarch *gdbarch,
+				   const frame_info_ptr &next_frame,
+				   const int pseudo_reg_num,
+				   gdb::array_view<const gdb_byte> data)
+{
+  aarch64_gdbarch_tdep *tdep
+    = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
+
+  gdb_assert (tdep->has_poe ());
+  gdb_assert (tdep->poe_pseudo_base <= pseudo_reg_num);
+  gdb_assert (pseudo_reg_num < tdep->poe_pseudo_base + tdep->poe_pseudo_count);
+
+  unsigned int pkey = pseudo_reg_num - tdep->poe_pseudo_base;
+  unsigned int shift = pkey * 4;
+
+  ULONGEST pseudo_reg_value
+    = extract_unsigned_integer (data, gdbarch_byte_order (gdbarch));
+
+  if (pseudo_reg_value > 0xf)
+    error (_("POE pseudo-register value must be between 0 and 15."));
+
+  /* Fetch the current POR_EL0 value.  */
+  value *por_value = value_of_register (tdep->poe_regnum, next_frame);
+
+  ULONGEST por_el0
+    = extract_unsigned_integer (por_value->contents (),
+				gdbarch_byte_order (gdbarch));
+
+  ULONGEST mask = ULONGEST (0xf) << shift;
+
+  por_el0 = (por_el0 & ~mask) | (pseudo_reg_value << shift);
+
+  store_unsigned_integer (por_value->contents_writeable (),
+			  gdbarch_byte_order (gdbarch), por_el0);
+
+  put_frame_register (next_frame, tdep->poe_regnum, por_value->contents_raw ());
+}
+
 /* Implement the "pseudo_register_write" gdbarch method.  */
 
 static void
@@ -3464,6 +3695,12 @@ aarch64_pseudo_write (gdbarch *gdbarch, const frame_info_ptr &next_frame,
 					 buf);
       return;
     }
+  else if (is_poe_pseudo_register (gdbarch, pseudo_reg_num))
+    {
+      aarch64_poe_pseudo_register_write (gdbarch, next_frame, pseudo_reg_num,
+					 buf);
+      return;
+    }
 
   /* Offset in the "pseudo-register space".  */
   int pseudo_offset = pseudo_reg_num - gdbarch_num_regs (gdbarch);
@@ -4140,6 +4377,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;
 }
 
@@ -4560,6 +4801,24 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 					  fpmr_regnum, "fpmr");
     }
 
+  int poe_regnum = -1;
+  int first_poe_pseudo_regnum = -1;
+  const tdesc_feature *feature_poe
+      = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.poe");
+  if (feature_poe != nullptr)
+    {
+      poe_regnum = num_regs;
+      for (i = 0; i < ARRAY_SIZE (aarch64_poe_register_names); i++)
+	valid_p &= tdesc_numbered_register (feature_poe, tdesc_data.get (),
+					    poe_regnum + i,
+					    aarch64_poe_register_names[i]);
+
+      /* POE pseudo-registers.  */
+      first_poe_pseudo_regnum = num_pseudo_regs;
+      num_pseudo_regs += 16;
+      num_regs++;
+    }
+
   int first_sme_regnum = -1;
   int first_sme2_regnum = -1;
   int first_sme_pseudo_regnum = -1;
@@ -4760,6 +5019,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->gcs_reg_base = first_gcs_regnum;
   tdep->gcs_linux_reg_base = first_gcs_linux_regnum;
   tdep->fpmr_regnum = fpmr_regnum;
+  tdep->poe_regnum = poe_regnum;
 
   /* Set the SME register set details.  The pseudo-registers will be adjusted
      later.  */
@@ -4802,6 +5062,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_tdesc_pseudo_register_reggroup_p (gdbarch,
 					aarch64_pseudo_register_reggroup_p);
   set_gdbarch_cannot_store_register (gdbarch, aarch64_cannot_store_register);
+  set_gdbarch_print_registers_info (gdbarch, aarch64_print_registers_info);
 
   /* Set the allocation tag granule size to 16 bytes.  */
   set_gdbarch_memtag_granule_size (gdbarch, AARCH64_MTE_GRANULE_SIZE);
@@ -4899,6 +5160,13 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->w_pseudo_base = first_w_regnum + num_regs;
   tdep->w_pseudo_count = 31;
 
+  /* Setup POE pseudo-register numbers.  */
+  if (tdep->has_poe () && first_poe_pseudo_regnum != -1)
+    {
+      tdep->poe_pseudo_base = first_poe_pseudo_regnum + num_regs;
+      tdep->poe_pseudo_count = 16;
+    }
+
   /* Pointer authentication pseudo-registers.  */
   if (tdep->has_pauth ())
     tdep->ra_sign_state_regnum = ra_sign_state_offset + num_regs;
diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h
index dff05a08f84..3e6320740d1 100644
--- a/gdb/aarch64-tdep.h
+++ b/gdb/aarch64-tdep.h
@@ -208,6 +208,18 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base
     return gcs_linux_reg_base != -1;
   }
 
+  /* POE register.  This is -1 if no POE feature is available.  */
+  int poe_regnum = -1;
+  int poe_pseudo_base = 0;
+  int poe_pseudo_count = 0;
+
+  /* Returns true if the target supports the 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.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..ba90d55c3bb 100644
--- a/gdb/arch/aarch64.h
+++ b/gdb/arch/aarch64.h
@@ -35,6 +35,8 @@ struct aarch64_features
   bool pauth = false;
   bool mte = false;
   bool fpmr = false;
+  /* Whether the Permission Overlay Extension (FEAT_S1POE) is supported.  */
+  bool poe = false;
 
   /* A positive TLS value indicates the number of TLS registers available.  */
   uint8_t tls = 0;
@@ -70,7 +72,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 +106,9 @@ namespace std
 
       /* FPMR feature.  */
       h = h << 1 | features.fpmr;
+
+      /* POE feature.  */
+      h = h << 1 | features.poe;
       return h;
     }
   };
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 9d57fffbab2..caee1d33ce2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -27306,6 +27306,44 @@ p $fpmr
 $1 = [ F8S1=E5M2 F8S2=E5M2 F8D=E5M2 OSM=Inf OSC=Inf/NaN LSCALE=0 NSCALE=0 LSCALE2=0 ]
 @end smallexample
 
+@subsubsection AArch64 Permission Overlay Extension
+@cindex Permission Overlay Extension, AArch64
+@cindex POE, AArch64
+
+When @value{GDBN} is debugging the AArch64 architecture and the Permission
+Overlay Extension (@acronym{POE}) is available, then @value{GDBN} will make the
+@code{por_el0} register available.
+
+To aid debugging, @value{GDBN} interprets the permissions of each feild in
+@code{por_el0} when displayed using the @code{info registers} command.
+
+@smallexample
+(gdb) info registers por_el0
+por_el0 0x0000000000000007 [ P0=rwx ]
+@end smallexample
+
+@value{GDBN} also provides pseudo-registers named @code{por_p0} through
+@code{por_p15} for accessing the individual permission fields in
+@code{por_el0}. These pseudo-registers can be read and written independently.
+Writing a pseudo-register updates the corresponding 4-bit field in
+@code{por_el0}.
+
+@smallexample
+(gdb) set $por_el0 = 0x7
+(gdb) set $por_p1 = 0x7
+(gdb) info registers por_el0
+por_el0 0x0000000000000077 [ P1=rwx P0=rwx ]
+(gdb) info registers por_p1
+por_p1		0x7		rwx
+@end smallexample
+
+The @code{por} register group can be used to display @code{por_el0} and all
+the POE pseudo-registers.
+
+@smallexample
+(gdb) info registers por
+@end smallexample
+
 For more information about @acronym{FPMR}, please refer to the official
 @uref{https://developer.arm.com/documentation/ddi0601/latest,ignored,
 architecture registers documentation}.
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..a1552e26516
--- /dev/null
+++ b/gdb/features/aarch64-poe.c
@@ -0,0 +1,14 @@
+/* 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 (target_desc *result, long regnum)
+{
+  tdesc_feature *feature;
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.poe");
+  tdesc_create_reg (feature, "por_el0", regnum++, 1, "por", 64, "uint64");
+  return regnum;
+}
diff --git a/gdb/features/aarch64-poe.xml b/gdb/features/aarch64-poe.xml
new file mode 100644
index 00000000000..aa2a2713ac8
--- /dev/null
+++ b/gdb/features/aarch64-poe.xml
@@ -0,0 +1,11 @@
+<?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">
+  <reg name="por_el0" bitsize="64" type="uint64" group="por"/>
+</feature>
diff --git a/gdb/nat/aarch64-poe-linux.h b/gdb/nat/aarch64-poe-linux.h
new file mode 100644
index 00000000000..74678c7771d
--- /dev/null
+++ b/gdb/nat/aarch64-poe-linux.h
@@ -0,0 +1,30 @@
+/* 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_LINUX_H
+#define GDB_NAT_AARCH64_POE_LINUX_H
+
+#include <asm/hwcap.h>
+
+/* Feature check for Permission Overlay Extension.  */
+#ifndef HWCAP2_POE
+#define HWCAP2_POE (1ULL << 63)
+#endif /* HWCAP2_POE.  */
+
+#endif /* GDB_NAT_AARCH64_POE_LINUX_H.  */
-- 
2.43.0


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

* [PATCH v5 2/5] gdb: Improve SIGSEGV diagnostics for POE faults
  2026-09-16  9:17 [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE srinath.parvathaneni
  2026-09-16  9:17 ` [PATCH v5 1/5] " srinath.parvathaneni
@ 2026-09-16  9:18 ` srinath.parvathaneni
  2026-09-16  9:18 ` [PATCH v5 3/5] gdbserver/aarch64: Add POR_EL0 register support srinath.parvathaneni
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: srinath.parvathaneni @ 2026-09-16  9:18 UTC (permalink / raw)
  To: gdb-patches
  Cc: simark, luis.machado.foss, thiago.bauermann, guinevere,
	Ezra.Sitorus, Matthieu.Longo, peter.maydell,
	Srinath Parvathaneni

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

When a SIGSEGV is caused by a Permission Overlay violation, include
additional information in GDB's error message to help identify the
failing address along with the responsible protection key causing
this fault.

Example:
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault
Protection Key Violation while accessing address 0x0000fffff7ff3000 with Protection Key = 1.
0x0000aaaaaaaa0a3c in main () at poe_sigsegv.c:26

Approved-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
---
 gdb/Makefile.in              |  1 +
 gdb/aarch64-linux-tdep.c     | 21 ++++++++++++++++++---
 gdb/arch/aarch64-poe-linux.h | 29 +++++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 3 deletions(-)
 create mode 100644 gdb/arch/aarch64-poe-linux.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6909123e863..cc04f0de68e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1297,6 +1297,7 @@ HFILES_NO_SRCDIR = \
 	arch/aarch64-mte.h \
 	arch/aarch64-mte-linux.h \
 	arch/aarch64-pauth-linux.h \
+	arch/aarch64-poe-linux.h \
 	arch/aarch64-scalable-linux.h \
 	arch/amd64.h \
 	arch/amd64-linux-tdesc.h \
diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 235b35bcfb4..1b2d4435088 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-linux.h"
 #include "arch/aarch64-mte.h"
 #include "arch/aarch64-mte-linux.h"
 #include "arch/aarch64-pauth-linux.h"
@@ -2675,11 +2676,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
     {
@@ -2689,6 +2691,8 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
 	 violation.  */
       si_code = parse_and_eval_long (gdb_si::get (si_key::siginfo_code));
       si_errno = parse_and_eval_long (gdb_si::get (si_key::siginfo_errno));
+      if (tdep->has_poe ())
+	si_pkey = parse_and_eval_long (gdb_si::get (si_key::siginfo_pkey));
 
       fault_addr
 	= parse_and_eval_long (gdb_si::get (si_key::siginfo_addr));
@@ -2705,6 +2709,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)
+    meaning = _("Protection Key Violation");
   else
     return;
 
@@ -2736,6 +2742,15 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
 	  uiout->field_string ("logical-tag", hex_string (ltag));
 	}
     }
+  /* Additional information for SIGSEGV caused by a permission overlay
+     violation.  */
+  else if (si_code == AARCH64_SEGV_PKUERR)
+    {
+      uiout->text (_(" while accessing address "));
+      uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
+      uiout->text (_(" with Protection Key = "));
+      uiout->field_signed ("protection-key", si_pkey);
+    }
   else if (si_code != AARCH64_SEGV_CPERR)
     {
       uiout->text ("\n");
@@ -3056,7 +3071,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/arch/aarch64-poe-linux.h b/gdb/arch/aarch64-poe-linux.h
new file mode 100644
index 00000000000..d6e4a001cbf
--- /dev/null
+++ b/gdb/arch/aarch64-poe-linux.h
@@ -0,0 +1,29 @@
+/* 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_LINUX_H
+#define GDB_ARCH_AARCH64_POE_LINUX_H
+
+/* Feature check for Permission Overlay Extension.  */
+#define AARCH64_HWCAP2_POE (1ULL << 63)
+
+/* Data or instruction abort caused by Protection Key Violation.  */
+#define AARCH64_SEGV_PKUERR 4
+
+#endif /* GDB_ARCH_AARCH64_POE_LINUX_H */
-- 
2.43.0


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

* [PATCH v5 3/5] gdbserver/aarch64: Add POR_EL0 register support
  2026-09-16  9:17 [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE srinath.parvathaneni
  2026-09-16  9:17 ` [PATCH v5 1/5] " srinath.parvathaneni
  2026-09-16  9:18 ` [PATCH v5 2/5] gdb: Improve SIGSEGV diagnostics for POE faults srinath.parvathaneni
@ 2026-09-16  9:18 ` srinath.parvathaneni
  2026-09-16  9:18 ` [PATCH v5 4/5] gdb/aarch64: Add core file and signal frame support for FEAT_S1POE srinath.parvathaneni
  2026-09-16  9:18 ` [PATCH v5 5/5] gdb/testsuite: Add FEAT_S1POE testcases srinath.parvathaneni
  4 siblings, 0 replies; 6+ messages in thread
From: srinath.parvathaneni @ 2026-09-16  9:18 UTC (permalink / raw)
  To: gdb-patches
  Cc: simark, luis.machado.foss, thiago.bauermann, guinevere,
	Ezra.Sitorus, Matthieu.Longo, peter.maydell,
	Srinath Parvathaneni

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

Add support for transferring the POR_EL0 register between the Linux
kernel and GDB during remote debugging.

This patch implements the necessary `fill` and `store` operations using
the `NT_ARM_POE` regset, allowing GDB to read and write the POR_EL0
register when debugging a remote target that supports FEAT_S1POE.

Approved-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
---
 gdbserver/linux-aarch64-low.cc | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index a2588a6e2a9..d326341e63a 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-linux.h"
 #include "nat/aarch64-gcs-linux.h"
 #include "nat/aarch64-mte-linux-ptrace.h"
 #include "nat/aarch64-scalable-linux-ptrace.h"
@@ -250,6 +251,26 @@ aarch64_store_fpregset (struct regcache *regcache, const void *buf)
   supply_register (regcache, AARCH64_FPCR_REGNUM, &regset->fpcr);
 }
 
+/* Fill BUF with the POE (POR_EL0) register set from the regcache.  */
+
+static void
+aarch64_fill_por_el0_regset (struct regcache *regcache, void *buf)
+{
+  uint64_t *poe = (uint64_t *) buf;
+  int poe_regnum = find_regno (regcache->tdesc, "por_el0");
+  collect_register (regcache, poe_regnum, poe);
+}
+
+/* Store the POE (POR_EL0) register set to regcache.  */
+
+static void
+aarch64_store_por_el0_regset (struct regcache *regcache, const void *buf)
+{
+  uint64_t *poe = (uint64_t *) buf;
+  int poe_regnum = find_regno (regcache->tdesc, "por_el0");
+  supply_register (regcache, poe_regnum, poe);
+}
+
 /* Fill BUF with the FPMR register set from the regcache.  */
 
 static void
@@ -901,6 +922,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,
+    aarch64_fill_por_el0_regset, aarch64_store_por_el0_regset },
   /* TLS register.  */
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_TLS,
     0, OPTIONAL_REGS,
@@ -980,6 +1005,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 (uint64_t);
+	  break;
 	default:
 	  gdb_assert_not_reached ("Unknown register set found.");
 	}
@@ -1010,6 +1039,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] 6+ messages in thread

* [PATCH v5 4/5] gdb/aarch64: Add core file and signal frame support for FEAT_S1POE
  2026-09-16  9:17 [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE srinath.parvathaneni
                   ` (2 preceding siblings ...)
  2026-09-16  9:18 ` [PATCH v5 3/5] gdbserver/aarch64: Add POR_EL0 register support srinath.parvathaneni
@ 2026-09-16  9:18 ` srinath.parvathaneni
  2026-09-16  9:18 ` [PATCH v5 5/5] gdb/testsuite: Add FEAT_S1POE testcases srinath.parvathaneni
  4 siblings, 0 replies; 6+ messages in thread
From: srinath.parvathaneni @ 2026-09-16  9:18 UTC (permalink / raw)
  To: gdb-patches
  Cc: simark, luis.machado.foss, thiago.bauermann, guinevere,
	Ezra.Sitorus, Matthieu.Longo, peter.maydell,
	Srinath Parvathaneni

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

Add support for POR_EL0 dumps/reads for core files and also the
support for reading the POE values in the signal frame.

Approved-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
---
 gdb/aarch64-linux-tdep.c | 47 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 1b2d4435088..a9cf6e3127f 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -171,6 +171,7 @@
 #define AARCH64_ZT_MAGIC			0x5a544e01
 #define AARCH64_GCS_MAGIC			0x47435300
 #define AARCH64_FPMR_MAGIC			0x46504d52
+#define AARCH64_POE_MAGIC			0x504f4530
 
 /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC.  */
 #define AARCH64_EXTRA_DATAP_OFFSET		8
@@ -220,6 +221,9 @@
 /* FPMR constants.  */
 #define AARCH64_FPMR_OFFSET			8
 
+/* POE constants.  */
+#define AARCH64_POE_OFFSET			8
+
 /* Holds information about the signal frame.  */
 struct aarch64_linux_sigframe
 {
@@ -273,6 +277,10 @@ struct aarch64_linux_sigframe
   /* FPMR value.  */
   CORE_ADDR fpmr = 0;
 
+  /* True if we have a POE entry in the signal context, false otherwise.  */
+  bool poe_available = false;
+  /* POE value.  */
+  CORE_ADDR poe = 0;
 };
 
 /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the
@@ -605,6 +613,22 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame,
 	    section += size;
 	    break;
 	  }
+	case AARCH64_POE_MAGIC:
+	  {
+	    gdb_byte buf[8];
+	    if (target_read_memory (section + AARCH64_POE_OFFSET,
+				    buf, 8) != 0)
+	      {
+		warning (_("Failed to read the POE section address from the"
+			   " signal frame context."));
+		section += size;
+		break;
+	      }
+	    signal_frame.poe = extract_unsigned_integer (buf, 8, byte_order);
+	    signal_frame.poe_available = true;
+	    section += size;
+	    break;
+	  }
 	case AARCH64_EXTRA_MAGIC:
 	  {
 	    /* Extra is always the last valid section in reserved and points to
@@ -775,6 +799,10 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self,
 			      signal_frame.fpmr);
   }
 
+  /* Handle POE register.  */
+  if (tdep->has_poe () && signal_frame.poe_available)
+    trad_frame_set_reg_value (this_cache, tdep->poe_regnum, signal_frame.poe);
+
   /* Restore the tpidr2 register, if the target supports it and if there is
      an entry for it.  */
   if (signal_frame.tpidr2_section != 0 && tdep->has_tls ()
@@ -828,6 +856,7 @@ aarch64_linux_sigframe_prev_arch (const frame_info_ptr &this_frame,
   features.vq = sve_vq_from_vl (signal_frame.vl);
   features.svq = (uint8_t) sve_vq_from_vl (signal_frame.svl);
   features.fpmr = signal_frame.fpmr_available;
+  features.poe = signal_frame.poe_available;
 
   struct gdbarch_info info;
   info.bfd_arch_info = bfd_lookup_arch (bfd_arch_aarch64, bfd_mach_aarch64);
@@ -1655,6 +1684,23 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 	  &aarch64_linux_fpmr_regset, "FPMR", cb_data);
     }
 
+  if (tdep->has_poe ())
+    {
+      const struct regcache_map_entry poe_regmap[] =
+	{
+	  { 1, tdep->poe_regnum, sizeof (uint64_t) },
+	  { 0 }
+	};
+
+      const struct regset aarch64_linux_poe_regset =
+	{
+	  poe_regmap, regcache_supply_regset, regcache_collect_regset
+	};
+
+      cb (".reg-aarch-poe", sizeof (uint64_t), sizeof (uint64_t),
+	  &aarch64_linux_poe_regset, "POE register", cb_data);
+    }
+
   if (tdep->has_pauth ())
     {
       /* Create this on the fly in order to handle the variable location.  */
@@ -1768,6 +1814,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch,
   features.gcs = features.gcs_linux = hwcap & AARCH64_HWCAP_GCS;
   features.mte = hwcap2 & AARCH64_HWCAP2_MTE;
   features.fpmr = hwcap2 & AARCH64_HWCAP2_FPMR;
+  features.poe = hwcap2 & AARCH64_HWCAP2_POE;
 
   /* Handle the TLS section.  */
   asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls");
-- 
2.43.0


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

* [PATCH v5 5/5] gdb/testsuite: Add FEAT_S1POE testcases
  2026-09-16  9:17 [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE srinath.parvathaneni
                   ` (3 preceding siblings ...)
  2026-09-16  9:18 ` [PATCH v5 4/5] gdb/aarch64: Add core file and signal frame support for FEAT_S1POE srinath.parvathaneni
@ 2026-09-16  9:18 ` srinath.parvathaneni
  4 siblings, 0 replies; 6+ messages in thread
From: srinath.parvathaneni @ 2026-09-16  9:18 UTC (permalink / raw)
  To: gdb-patches
  Cc: simark, luis.machado.foss, thiago.bauermann, guinevere,
	Ezra.Sitorus, Matthieu.Longo, peter.maydell,
	Srinath Parvathaneni

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

Add testcases for POR_EL0 register access, POE pseudo-register access, SIGSEGV
diagnostics, fix-and-continue support (updating $por_el0 after SIGSEGV and
continuing with signal 0), core file support and the test for signal frame
unwinding support.

Approved-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
---
 gdb/testsuite/gdb.arch/aarch64-poe-core.exp   | 101 ++++++++++++++++++
 gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c |  45 ++++++++
 .../gdb.arch/aarch64-poe-sigframe.exp         |  55 ++++++++++
 gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.c  |  52 +++++++++
 .../gdb.arch/aarch64-poe-sigsegv.exp          |  55 ++++++++++
 gdb/testsuite/gdb.arch/aarch64-poe.c          |  29 +++++
 gdb/testsuite/gdb.arch/aarch64-poe.exp        |  60 +++++++++++
 gdb/testsuite/lib/gdb.exp                     |  55 ++++++++++
 8 files changed, 452 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-core.exp
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c
 create mode 100644 gdb/testsuite/gdb.arch/aarch64-poe-sigframe.exp
 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/testsuite/gdb.arch/aarch64-poe-core.exp b/gdb/testsuite/gdb.arch/aarch64-poe-core.exp
new file mode 100644
index 00000000000..22fe646ac43
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe-core.exp
@@ -0,0 +1,101 @@
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+# Test generating and reading a core file with POR_EL0.
+
+proc check_poe_core_file {core_filename} {
+    # Load the core file.
+    if {
+	[gdb_test "core $core_filename" \
+	    [multi_line \
+		"Core was generated by .*" \
+		"Program terminated with signal SIGSEGV, Segmentation fault" \
+		"Protection Key Violation while accessing address ${::hex} with Protection Key = ${::decimal}\\." \
+		"#0  ${::hex} in main \\(.*\\) at .*" \
+		".*buf\\\[0\\\] = 42;.*"] \
+	    "load core file"]
+    } {
+	untested "failed to load core file"
+	return -1
+    }
+
+    # Check the value of POR_EL0 in the core file.
+    gdb_test "print/x \$por_el0" " = 0x37" \
+	"por_el0 contents from core file"
+}
+
+require allow_aarch64_poe_tests
+
+standard_testfile aarch64-poe-sigsegv.c
+
+if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
+    return
+}
+
+set binfile [standard_output_file ${testfile}]
+
+if {![runto_main]} {
+    return
+}
+
+set poe_crash_re [multi_line \
+    "Program received signal SIGSEGV, Segmentation fault" \
+    "Protection Key Violation while accessing address ${::hex} with Protection Key = ${::decimal}\\." \
+    ".*buf\\\[0\\\] = 42;.*"]
+
+gdb_test_multiple "continue" "run to POE crash" {
+    -re "$poe_crash_re$gdb_prompt $" {
+	pass $gdb_test_name
+    }
+
+    -re ".*exited with code 01.*$gdb_prompt $" {
+	unsupported "POE userspace support unavailable"
+	return
+    }
+}
+
+# Generate the gcore core file.
+set gcore_filename [standard_output_file "${testfile}.gcore"]
+set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"]
+
+# Generate a native core file.
+set core_filename [core_find ${binfile}]
+set core_generated [expr {$core_filename != ""}]
+
+# At this point we have a couple core files, the gcore one generated by GDB
+# and the native one generated by the Linux Kernel.  Make sure GDB can read
+# both correctly.
+
+if {$gcore_generated} {
+    clean_restart
+    gdb_load ${binfile}
+    with_test_prefix "gcore corefile" {
+	check_poe_core_file $gcore_filename
+    }
+} else {
+    fail "gcore corefile not generated"
+}
+
+if {$core_generated} {
+    clean_restart
+    gdb_load ${binfile}
+    with_test_prefix "native corefile" {
+	check_poe_core_file $core_filename
+    }
+} else {
+    untested "native corefile not generated"
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c b/gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c
new file mode 100644
index 00000000000..dd72f560c87
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigframe.c
@@ -0,0 +1,45 @@
+/* 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 signal frame unwinding.  */
+
+/* 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.  */
+
+#include <sys/auxv.h>
+#include <stdlib.h>
+#include <signal.h>
+
+static int count = 0;
+
+static void
+handler (int sig)
+{
+  count++;
+}
+
+int
+main (int argc, char **argv)
+{
+  signal (SIGUSR1, handler);
+
+  raise (SIGUSR1);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-poe-sigframe.exp b/gdb/testsuite/gdb.arch/aarch64-poe-sigframe.exp
new file mode 100644
index 00000000000..349c3a84ce0
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigframe.exp
@@ -0,0 +1,55 @@
+# 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 to unwind POR_EL0 from the signal frame context.
+
+global hex
+global decimal
+
+require allow_aarch64_poe_tests
+
+standard_testfile
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+    return
+}
+
+if {![runto_main]} {
+    return
+}
+
+# Set POR_EL0 register in main.
+gdb_test_no_output "set \$por_el0=0x777"
+
+gdb_breakpoint "handler"
+
+gdb_test "handle SIGUSR1 nostop" \
+	 ".*SIGUSR1.*No.*Yes.*Yes.*"
+
+gdb_test "continue" \
+	 ".*Breakpoint ${::decimal}, handler \\(sig=10\\).*"
+
+# Update POR_EL0 in the current signal handler frame.
+gdb_test_no_output "set \$por_el0=0x007"
+
+# Select the frame above the signal handler frame, which makes GDB unwind the
+# POR_EL0 from the signal frame POE context.
+gdb_test "frame 2" "#2  ($hex in )?\\S+ \\(.*\\) (at|from) \\S+.*" \
+	 "reached frame 2"
+
+# Print POR_EL0 and verify that it reflects the value from frame above the
+# signal handler frame.
+gdb_test "p/x \$por_el0" \
+	 "\\$\[0-9\]+ = 0x777" \
+	 "print/x por_el0 from the frame before the signal handler"
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..5346e51dbba
--- /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 0;
+}
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..e8bd0c0f22f
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe-sigsegv.exp
@@ -0,0 +1,55 @@
+# 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 supports FEAT_S1POE and exposes POR_EL0 register.
+
+global hex
+global decimal
+
+require allow_aarch64_poe_tests
+
+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 Key Violation while accessing address ${hex} with Protection Key = ${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"
+	return
+    }
+}
+
+# Fix the POE permissions (set $por_el0) and continue without delivering SIGSEGV.
+gdb_test_no_output "set \$por_el0 = 0x57" \
+    "allow write access by updating POR_EL0"
+
+gdb_test_multiple "signal 0" "continue after fixing POE fault" {
+    -re ".*exited normally.*$gdb_prompt $" {
+	pass $gdb_test_name
+    }
+}
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..9d8c472409c
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-poe.exp
@@ -0,0 +1,60 @@
+# 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 allow_aarch64_poe_tests
+
+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.*" \
+	 "info register por_el0 available"
+
+gdb_test "p \$por_el0" \
+	"\\$\[0-9\]+ = .*" \
+	"print por_el0 available"
+
+gdb_test "p/x \$por_el0" \
+	 "\\$\[0-9\]+ = ${hex}" \
+	 "print/x por_el0 available"
+
+gdb_test "info registers por" \
+	 "por_el0\[ \t\]+$hex.*por_p\[0-9\]+\[ \t\]+$hex.*" \
+	 "info registers por group available"
+
+gdb_test_no_output "set \$por_el0 = 0x007" \
+	 "initialize POR_EL0"
+
+gdb_test_no_output "set \$por_p1 = 0x07" \
+	 "write por_p1 pseudo-register"
+
+gdb_test_no_output "set \$por_p3 = 0x07" \
+	 "write por_p3 pseudo-register"
+
+gdb_test "p/x \$por_el0" \
+	 "\\$\[0-9\]+ = 0x7077" \
+	 "POE pseudo-register writes reflected in POR_EL0"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 1ebdaf6ba10..9b007d9b130 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5691,6 +5691,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" {
-- 
2.43.0


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

end of thread, other threads:[~2026-09-16  9:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16  9:17 [PATCH v5 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE srinath.parvathaneni
2026-09-16  9:17 ` [PATCH v5 1/5] " srinath.parvathaneni
2026-09-16  9:18 ` [PATCH v5 2/5] gdb: Improve SIGSEGV diagnostics for POE faults srinath.parvathaneni
2026-09-16  9:18 ` [PATCH v5 3/5] gdbserver/aarch64: Add POR_EL0 register support srinath.parvathaneni
2026-09-16  9:18 ` [PATCH v5 4/5] gdb/aarch64: Add core file and signal frame support for FEAT_S1POE srinath.parvathaneni
2026-09-16  9:18 ` [PATCH v5 5/5] gdb/testsuite: Add FEAT_S1POE testcases srinath.parvathaneni

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