| # Copyright 2025 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/>. |
| |
| # Test multiple situations in which we may use the maintenance command to |
| # disable and enable frame unwinders, and check that they really are |
| # disabled when they say the are. |
| |
| standard_testfile |
| |
| # Proc to check if the unwinder of the given name is in the desired state. |
| # STATE can be either Y or N. |
| proc check_unwinder_state { unwinder_name state {testname ""} } { |
| set should_pass false |
| set command "maint info frame-unwinders" |
| if {${testname} == ""} { |
| set testname "checking state ${state} for ${unwinder_name}" |
| } |
| gdb_test_multiple ${command} ${testname} -lbl { |
| -re "${unwinder_name}\\s+\\w+\\s+\\w+\\s+${state}\\s+(?=\r\n)" { |
| set should_pass true |
| exp_continue |
| } |
| -re ${command} { |
| exp_continue |
| } |
| -re "\\w+\\s+\\w+\\s+\\w+\\s+\\w+\\s+(?=\r\n)" { |
| exp_continue |
| } |
| -re -wrap "" { |
| gdb_assert ${should_pass} ${gdb_test_name} |
| } |
| } |
| } |
| |
| # Check if all unwinders of class UNWINDER_CLASS are in the state STATE. |
| # STATE can be either Y or N. |
| # UNWINDER_CLASS can be one of: GDB, ARCH, EXTENSION, DEBUGINFO. It can |
| # also be \\w+ if checking all unwinders. |
| proc check_unwinder_class { unwinder_class state {testname ""} } { |
| set command "maint info frame-unwinders" |
| set should_pass true |
| if {$testname == ""} { |
| set testname "checking if ${unwinder_class} state is ${state}" |
| } |
| gdb_test_multiple ${command} ${testname} -lbl { |
| -re "^\[^\r\n\]+\\s+\\w+\\s+${unwinder_class}\\s+\(\[YN\]\)\\s+(?=\r\n)" { |
| # The unwinder name may have multiple words, so we need to use the |
| # more generic [^\r\n] pattern to match the unwinders. |
| set cur_state $expect_out(1,string) |
| if {$cur_state == $state} { |
| set should_pass false |
| } |
| exp_continue |
| } |
| -re ${command} { |
| exp_continue |
| } |
| -re -wrap "" { |
| gdb_assert ${should_pass} ${gdb_test_name} |
| } |
| } |
| } |
| |
| if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} { |
| return -1 |
| } |
| |
| if {![runto_main]} { |
| untested "couldn't run to main" |
| return |
| } |
| |
| # Test disabling all unwinders. |
| check_unwinder_class "\\w+" "Y" \ |
| "all unwinders enabled before any changes" |
| gdb_test_no_output "maint frame-unwinder disable -all" |
| check_unwinder_class "\\w+" "N" \ |
| "all unwinders were properly disabled" |
| |
| # Test if GDB can still make a backtrace once all unwinders are disabled. |
| # It should be impossible. |
| gdb_test "backtrace" \ |
| ".*Required frame unwinder may have been disabled, see 'maint info frame-unwinders'.*" \ |
| "no suitable unwinders should be found" |
| |
| # Reenable all unwinders. |
| gdb_test_no_output "maint frame-unwinder enable -all" |
| check_unwinder_class "\\w+" "Y" \ |
| "all unwinders should be re-enabled" |
| |
| # Check that we are able to get backtraces once again. |
| gdb_test "backtrace" ".0\\s+main .. at.*" \ |
| "we can get usable backtraces again" |
| |
| # Check if we can disable an unwinder based on the name. |
| check_unwinder_state "dummy" "Y" |
| gdb_test_no_output "maint frame-unwinder disable -name dummy" |
| check_unwinder_state "dummy" "N" |
| # And verify what happens if you try to disable it again. |
| gdb_test "maint frame-unwinder disable -name dummy" \ |
| "unwinder dummy is already disabled" \ |
| "disable already disabled unwinder" |
| check_unwinder_state "dummy" "N" "dummy should continue disabled" |
| |
| foreach class {GDB ARCH DEBUGINFO EXTENSION} { |
| # Disable all unwinders of type CLASS, and check that the command worked. |
| gdb_test_no_output "maint frame-unwinder disable ${class}" |
| check_unwinder_class ${class} "N" |
| } |
| |
| # Now check if we are able to enable a single unwinder, and what happens if we |
| # enable it twice. |
| gdb_test_no_output "maint frame-unwinder enable -name dummy" |
| check_unwinder_state "dummy" "Y" "successfully enabled dummy unwinder" |
| gdb_test "maint frame-unwinder enable -name dummy" \ |
| "unwinder dummy is already enabled" \ |
| "enable already enabled unwinder" |
| check_unwinder_state "dummy" "Y" "dummy should continue enabled" |
| |
| foreach class {GDB ARCH DEBUGINFO EXTENSION} { |
| # Enable all unwinders of type CLASS, and check that the command worked, |
| # using "-class" option to ensure it works. Should make no difference. |
| gdb_test_no_output "maint frame-unwinder enable -class ${class}" |
| check_unwinder_class ${class} "Y" |
| } |