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 . + +# 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 . */ + +/* 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 +#include +#include + +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 . + +# 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 . */ + +/* 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 +#include + +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 . + +# 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 . */ + +/* 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 . + +# 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 1eb643cdf1a..9747561b488 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -5651,6 +5651,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 + #include + + /* 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" {