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 v4 1/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE
Date: Tue, 1 Sep 2026 09:12:12 +0000 [thread overview]
Message-ID: <20260901091216.5711-2-srinath.parvathaneni@arm.com> (raw)
In-Reply-To: <20260901091216.5711-1-srinath.parvathaneni@arm.com>
[-- Attachment #1: Type: text/plain, Size: 3125 bytes --]
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 | 2 +
gdb/aarch64-linux-nat.c | 64 ++++++++
gdb/aarch64-tdep.c | 274 +++++++++++++++++++++++++++++++++++
gdb/aarch64-tdep.h | 12 ++
gdb/arch/aarch64-poe-linux.h | 29 ++++
gdb/arch/aarch64.c | 4 +
gdb/arch/aarch64.h | 8 +-
gdb/features/Makefile | 1 +
gdb/features/aarch64-poe.c | 14 ++
gdb/features/aarch64-poe.xml | 11 ++
gdb/nat/aarch64-poe-linux.h | 29 ++++
11 files changed, 447 insertions(+), 1 deletion(-)
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
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: v4-0001-PATCH-1-5-gdb-aarch64-Add-POR_EL0-register-suppor.patch --]
[-- Type: text/x-patch; name="v4-0001-PATCH-1-5-gdb-aarch64-Add-POR_EL0-register-suppor.patch", Size: 23964 bytes --]
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c6bfc2949fc..0b5bf45545a 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1292,6 +1292,7 @@ HFILES_NO_SRCDIR = \
arch/aarch32.h \
arch/aarch64-fpmr-linux.h \
arch/aarch64-gcs-linux.h \
+ arch/aarch64-poe-linux.h \
arch/aarch64.h \
arch/aarch64-insn.h \
arch/aarch64-mte.h \
@@ -1540,6 +1541,7 @@ HFILES_NO_SRCDIR = \
namespace.h \
nat/aarch64-fpmr-linux.h \
nat/aarch64-gcs-linux.h \
+ nat/aarch64-poe-linux.h \
nat/aarch64-hw-point.h \
nat/aarch64-linux.h \
nat/aarch64-linux-hw-point.h \
diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c
index 52ace4aab41..8e29c42908c 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 contents from GDB's REGCACHE to the
+ thread associated with REGCACHE. */
+
+static void
+store_poeregs_to_thread (struct 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..763321bdcb4 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 (struct 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,132 @@ 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 (struct 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 (struct 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));
+ struct 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, (unsigned) 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 (struct gdbarch *gdbarch,
+ struct 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 +3318,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 +3449,38 @@ 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 ().data (),
+ result->type ()->length (),
+ gdbarch_byte_order (gdbarch),
+ pseudo_reg_value);
return result;
}
@@ -3322,6 +3512,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 +3621,50 @@ 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 ().data (),
+ por_value->type ()->length (),
+ 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 +3701,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 +4383,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 +4807,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 struct 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 +5025,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 +5068,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 +5166,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-poe-linux.h b/gdb/arch/aarch64-poe-linux.h
new file mode 100644
index 00000000000..8623fa43b54
--- /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. */
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/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..9222d026a6d
--- /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 (struct target_desc *result, long regnum)
+{
+ struct 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..f3d0256da3f
--- /dev/null
+++ b/gdb/nat/aarch64-poe-linux.h
@@ -0,0 +1,29 @@
+/* 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/>. */
+
+#include <asm/hwcap.h>
+#ifndef GDB_NAT_AARCH64_POE_LINUX_H
+#define GDB_NAT_AARCH64_POE_LINUX_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. */
next prev parent reply other threads:[~2026-09-01 9:14 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 9:12 [PATCH v4 0/5] " srinath.parvathaneni
2026-09-01 9:12 ` srinath.parvathaneni [this message]
2026-09-10 7:01 ` [PATCH v4 1/5] " Thiago Jung Bauermann
2026-09-10 22:32 ` Thiago Jung Bauermann
2026-09-12 21:43 ` Luis
2026-09-01 9:12 ` [PATCH v4 2/5] gdb: Improve SIGSEGV diagnostics for POE faults srinath.parvathaneni
2026-09-01 9:12 ` [PATCH v4 3/5] gdbserver/aarch64: Add POR_EL0 register support srinath.parvathaneni
2026-09-01 9:12 ` [PATCH v4 4/5] gdb/aarch64: Add core file and signal frame support for FEAT_S1POE srinath.parvathaneni
2026-09-10 7:02 ` Thiago Jung Bauermann
2026-09-01 9:12 ` [PATCH v4 5/5] gdb/testsuite: Add FEAT_S1POE testcases srinath.parvathaneni
2026-09-10 7:13 ` Thiago Jung Bauermann
2026-09-07 12:52 ` [PATCH v4 0/5] gdb/aarch64: Add POR_EL0 register support for FEAT_S1POE 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=20260901091216.5711-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