| # Copyright (C) 2018-2023 Free Software Foundation, Inc. |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
| # This file is part of the gdb testsuite. |
| |
| # Test generating and reading a core file with MTE memory tags. |
| |
| proc test_mte_core_file { core_filename mode } { |
| # Load the core file and make sure we see the tag violation fault |
| # information. |
| if {$mode == "sync"} { |
| gdb_test "core $core_filename" \ |
| [multi_line \ |
| "Core was generated by.*\." \ |
| "Program terminated with signal SIGSEGV, Segmentation fault" \ |
| "Memory tag violation while accessing address ${::hex}" \ |
| "Allocation tag ${::hex}" \ |
| "Logical tag ${::hex}\." \ |
| "#0.*${::hex} in main \\(.*\\) at .*" \ |
| ".*mmap_pointers\\\[0\\\] = 0x4;"] \ |
| "core file shows $mode memory tag violation" |
| } else { |
| gdb_test "core $core_filename" \ |
| [multi_line \ |
| "Core was generated by.*\." \ |
| "Program terminated with signal SIGSEGV, Segmentation fault" \ |
| "Memory tag violation" \ |
| "Fault address unavailable\." \ |
| "#0 ${::hex} in .* from .*"] \ |
| "core file shows $mode memory tag violation" |
| } |
| |
| # Make sure we have the tag_ctl register. |
| gdb_test "info register tag_ctl" \ |
| "tag_ctl.*${::hex}.*${::decimal}" \ |
| "tag_ctl is available" |
| |
| # In ASYNC mode, there is nothing left to test, as the program stops at |
| # a place where further source code inspection is not possible. |
| if {$mode == "async"} { |
| return |
| } |
| |
| # First, figure out the page size. |
| set page_size [get_valueof "" "page_sz" "0" \ |
| "fetch value of page size"] |
| |
| # Get the number of maps for the test |
| set nmaps [get_valueof "" "NMAPS" "0" \ |
| "fetch number of maps"] |
| set tag 1 |
| |
| # Iterate over all of the MTE-protected memory mappings and make sure |
| # GDB retrieves the correct allocation tags for each one. If the tag |
| # has the expected value, that means the core file was generated correctly |
| # and that GDB read the contents correctly. |
| for {set i 0} {$i < $nmaps} {incr i} { |
| for {set offset 0} {$offset < $page_size} {set offset [expr $offset + 16]} { |
| set hex_tag [format "%x" $tag] |
| gdb_test "memory-tag print-allocation-tag mmap_pointers\[$i\] + $offset" \ |
| "= 0x$hex_tag" \ |
| "mmap_ponters\[$i\] + $offset contains expected tag" |
| # Update the expected tag. The test writes tags in sequential |
| # order. |
| set tag [expr ($tag + 1) % 16] |
| } |
| } |
| } |
| |
| # Exercise MTE corefile support using mode MODE (Async or Sync) |
| |
| proc test_mode { mode } { |
| |
| set compile_flags {"debug" "macros" "additional_flags=-march=armv8.5-a+memtag"} |
| |
| # If we are testing async mode, we need to force the testcase to use |
| # such mode. |
| if {$mode == "async"} { |
| lappend compile_flags "additional_flags=-DASYNC" |
| } |
| |
| standard_testfile |
| set executable "${::testfile}-${mode}" |
| if {[prepare_for_testing "failed to prepare" ${executable} ${::srcfile} ${compile_flags}]} { |
| return -1 |
| } |
| set binfile [standard_output_file ${executable}] |
| |
| if ![runto_main] { |
| untested "could not run to main" |
| return -1 |
| } |
| |
| # Targets that don't support memory tagging should not execute the |
| # runtime memory tagging tests. |
| if {![supports_memtag]} { |
| unsupported "memory tagging unsupported" |
| return -1 |
| } |
| |
| # Run until a crash and confirm GDB displays memory tag violation |
| # information. |
| if {$mode == "sync"} { |
| gdb_test "continue" \ |
| [multi_line \ |
| "Program received signal SIGSEGV, Segmentation fault" \ |
| "Memory tag violation while accessing address ${::hex}" \ |
| "Allocation tag 0x1" \ |
| "Logical tag 0x0\." \ |
| "${::hex} in main \\(.*\\) at .*" \ |
| ".*mmap_pointers\\\[0\\\] = 0x4;"] \ |
| "run to memory $mode tag violation" |
| } else { |
| gdb_test "continue" \ |
| [multi_line \ |
| "Program received signal SIGSEGV, Segmentation fault" \ |
| "Memory tag violation" \ |
| "Fault address unavailable\." \ |
| "${::hex} in .* from .*"] \ |
| "run to memory $mode tag violation" |
| } |
| |
| # Generate the gcore core file. |
| set gcore_filename [standard_output_file "${executable}.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 ${binfile} |
| with_test_prefix "gcore corefile" { |
| test_mte_core_file $gcore_filename $mode |
| } |
| } else { |
| fail "gcore corefile not generated" |
| } |
| |
| if {$core_generated} { |
| clean_restart ${binfile} |
| with_test_prefix "native corefile" { |
| test_mte_core_file $core_filename $mode |
| } |
| } else { |
| untested "native corefile not generated" |
| } |
| |
| } |
| |
| require is_aarch64_target |
| |
| require {have_compile_flag -march=armv8.5-a+memtag} |
| |
| # Run tests |
| foreach_with_prefix mode {"sync" "async"} { |
| test_mode $mode |
| } |