Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: <srinath.parvathaneni@arm.com>
To: <gdb-patches@sourceware.org>
Cc: <simark@simark.ca>, <luis.machado.foss@gmail.com>,
	<thiago.bauermann@linaro.org>, <guinevere@redhat.com>,
	<Ezra.Sitorus@arm.com>, <Matthieu.Longo@arm.com>,
	<peter.maydell@linaro.org>,
	 Srinath Parvathaneni <srinath.parvathaneni@arm.com>
Subject: [PATCH v5 1/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE
Date: Wed, 16 Sep 2026 09:17:59 +0000	[thread overview]
Message-ID: <20260916091803.110110-2-srinath.parvathaneni@arm.com> (raw)
In-Reply-To: <20260916091803.110110-1-srinath.parvathaneni@arm.com>

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


  reply	other threads:[~2026-09-16  9:19 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-16  9:17 [PATCH v5 0/5] " srinath.parvathaneni
2026-09-16  9:17 ` srinath.parvathaneni [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260916091803.110110-2-srinath.parvathaneni@arm.com \
    --to=srinath.parvathaneni@arm.com \
    --cc=Ezra.Sitorus@arm.com \
    --cc=Matthieu.Longo@arm.com \
    --cc=gdb-patches@sourceware.org \
    --cc=guinevere@redhat.com \
    --cc=luis.machado.foss@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=simark@simark.ca \
    --cc=thiago.bauermann@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox