# 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 . # 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" } } if {![is_aarch64_target]} { verbose "Skipping ${gdb_test_file_name}." return } # Run tests foreach_with_prefix mode {"sync" "async"} { test_mode $mode }