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 (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 (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 (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 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: + [] */ + +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 (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 (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 data) +{ + aarch64_gdbarch_tdep *tdep + = 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 . */ + +#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 @@ + + + + + + + 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 . */ + +#include +#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. */