# Copyright 2019 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 the -catch-throw, -catch-rethrow, and -catch-catch MI commands. if { [skip_cplus_tests] } { continue } load_lib mi-support.exp set MIFLAGS "-i=mi" standard_testfile .cc if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { untested "failed to compile" return -1 } # Grab some line numbers we'll need. set catch_1_lineno [gdb_get_line_number "Catch 1"] set catch_2_lineno [gdb_get_line_number "Catch 2"] set throw_1_lineno [gdb_get_line_number "Throw 1"] set throw_2_lineno [gdb_get_line_number "Throw 2"] set main_lineno [gdb_get_line_number "Stop here"] # Restart this test, load the test binary and set a breakpoint in # main. proc restart_for_test {} { global srcdir subdir binfile srcfile global main_lineno if {[mi_gdb_start]} { continue } mi_delete_breakpoints mi_gdb_reinitialize_dir $srcdir/$subdir mi_gdb_load ${binfile} mi_runto main mi_create_breakpoint \ "$srcfile:${main_lineno}" "break before exiting program" \ -disp keep -func "main.*" \ -file ".*mi-catch-cpp-exceptions.cc" -line ${main_lineno} } # Issue an -exec-continue then wait for GDB to catch a C++ exception # event in FUNC on LINE. Use TESTNAME to make tests unique. proc continue_to_next_exception { func line testname } { global hex mi_send_resuming_command "exec-continue" \ "exec-continue" mi_expect_stop "exception-caught" ".*" ".*" ".*" ".*" \ {} "run until an exception is caught: $testname" mi_gdb_test "-stack-list-frames 1 1" \ "\\^done,stack=\\\[frame=\{level=\"1\",addr=\"$hex\",func=\"${func}\",.*,line=\"${line}\".*\}\\\]" \ "check previous frame: $testname" } # Issue an -exec-continue and stop at the breakpoint in main. proc continue_to_breakpoint_in_main {} { global main_lineno mi_send_resuming_command "exec-continue" "exec-continue to main" mi_expect_stop "breakpoint-hit" "main" ".*" ".*" "${main_lineno}" \ {.* disp="keep"} "run until breakpoint in main" } # TYPE is one of throw, rethrow, or catch. This proc creates a catch # point using -catch-TYPE. The optional string EXTRA is any extra # arguments to pass when setting up the catchpoint. proc setup_catchpoint {type {extra ""}} { global decimal mi_gdb_test "-catch-${type} ${extra}" \ "\\^done,bkpt=\{number=\"$decimal\".*what=\"exception ${type}\",catch-type=\"${type}\".*\}" \ "Setup -catch-${type}" } # Ensure that -catch-throw will catch only throws and nothing else. with_test_prefix "-catch-throw" { restart_for_test setup_catchpoint "throw" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4" continue_to_breakpoint_in_main } # Ensure that -catch-rethrow catches only rethrows and nothing else. with_test_prefix "-catch-rethrow" { restart_for_test setup_catchpoint "rethrow" continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1" continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2" continue_to_breakpoint_in_main } # Ensure that -catch-catch catches only catch points, and nothing # else. with_test_prefix "-catch-catch" { restart_for_test setup_catchpoint "catch" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2" continue_to_next_exception "main" "${catch_2_lineno}" "catch 3" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5" continue_to_next_exception "main" "${catch_2_lineno}" "catch 6" continue_to_breakpoint_in_main } # Now check that all of the command with a regexp that doesn't match, # don't trigger. with_test_prefix "all with invalid regexp" { restart_for_test setup_catchpoint "throw" "-r blahblah" setup_catchpoint "rethrow" "-r woofwoof" setup_catchpoint "catch" "-r miowmiow" # Would like to use 'continue_to_breakpoint_in_main' here, if # there wasn't a bug that requires a use of kfail. mi_send_resuming_command "exec-continue" \ "exec-continue" set testname "run until breakpoint in main" gdb_expect { -re "could not find minimal symbol for typeinfo address.*$mi_gdb_prompt$" { kfail "gdb/24541" "${testname}" } -re "\\*stopped,bkptno=\"$decimal\",reason=\"breakpoint-hit\",disp=\"keep\".*func=\"__cxa_throw\".*$mi_gdb_prompt$" { kfail "gdb/24541" "${testname}" } -re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*line=\"${main_lineno}\".*$mi_gdb_prompt$" { pass "${testname}" } timeout { fail "${testname} (timeout)" } } } # Now check that all of the commands with a regexp that does match, # still trigger. with_test_prefix "all with valid regexp" { restart_for_test setup_catchpoint "throw" "-r my_ex" setup_catchpoint "rethrow" "-r _except" setup_catchpoint "catch" "-r my_exception" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2" continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1" continue_to_next_exception "main" "${catch_2_lineno}" "catch 3" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5" continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2" continue_to_next_exception "main" "${catch_2_lineno}" "catch 6" continue_to_breakpoint_in_main } # Check that the temporary switch works on its own. with_test_prefix "all with -t" { restart_for_test setup_catchpoint "throw" "-t" setup_catchpoint "rethrow" "-t" setup_catchpoint "catch" "-t" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1" continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1" continue_to_breakpoint_in_main } # Check that the temporary switch works when used with a regexp. restart_for_test with_test_prefix "all with -t and regexp" { setup_catchpoint "throw" "-t -r my_ex" setup_catchpoint "rethrow" "-t -r _except" setup_catchpoint "catch" "-t -r my_exception" continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1" continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1" continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1" continue_to_breakpoint_in_main }