1# Copyright (C) 2023-2024 Free Software Foundation, Inc. 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16# Check that when GDB fails to evaluate the condition of a conditional 17# breakpoint we only get one *stopped notification. In this test case 18# the breakpoint condition fails due to throwing an uncaught C++ 19# excpetion. 20 21require allow_cplus_tests 22 23load_lib mi-support.exp 24set MIFLAGS "-i=mi" 25 26standard_testfile .cc 27 28if [build_executable ${testfile}.exp ${binfile} ${srcfile} {debug c++}] { 29 return -1 30} 31 32# Create a breakpoint with a condition that invokes an inferior 33# function call, that will segfault. Run until GDB hits the 34# breakpoint and check how GDB reports the failed condition check. 35# 36# UNWIND_ON_EXCEPTION is either 'on' or 'off'. This is used to configure 37# GDB's 'set unwind-on-terminating-exception' setting. 38 39proc run_test { unwind_on_exception } { 40 41 if {[mi_clean_restart $::binfile]} { 42 return 43 } 44 45 if {[mi_runto_main] == -1} { 46 return 47 } 48 49 mi_gdb_test "-gdb-set unwind-on-terminating-exception ${unwind_on_exception}" {\^done} \ 50 "set unwind-on-terminating-exception" 51 52 # Create the conditional breakpoint. 53 set bp_location [gdb_get_line_number "Set breakpoint here"] 54 mi_create_breakpoint "-c \"cond_throw ()\" $::srcfile:$bp_location" \ 55 "insert conditional breakpoint" \ 56 -func "foo\\(\\)" -file ".*$::srcfile" -line "$bp_location" \ 57 -cond "cond_throw \\(\\)" 58 59 # Number of the previous breakpoint. 60 set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID" \ 61 "get number for breakpoint"] 62 63 # The line where we expect the inferior to crash. 64 set crash_linenum 0 65 #[gdb_get_line_number "Crash here"] 66 67 # Run the inferior and wait for it to stop. 68 mi_send_resuming_command "exec-continue" "continue the inferior" 69 70 if {$unwind_on_exception} { 71 mi_gdb_test "" \ 72 [multi_line \ 73 "&\"Error in testing condition for breakpoint $bpnum:\\\\n\"" \ 74 "&\"The program being debugged entered a std::terminate call, most likely\\\\n\"" \ 75 "&\"caused by an unhandled C\\+\\+ exception. GDB blocked this call in order\\\\n\"" \ 76 "&\"to prevent the program from being terminated, and has restored the\\\\n\"" \ 77 "&\"context to its original state before the call.\\\\n\"" \ 78 "&\"To change this behaviour use \\\\\"set unwind-on-terminating-exception off\\\\\"\\.\\\\n\"" \ 79 "&\"Evaluation of the expression containing the function \\(cond_throw\\(\\)\\)\\\\n\"" \ 80 "&\"will be abandoned.\\\\n\"" \ 81 "=breakpoint-modified,bkpt={number=\"$bpnum\",type=\"breakpoint\",\[^\r\n\]+times=\"1\",\[^\r\n\]+}" \ 82 "~\"\\\\n\"" \ 83 "~\"Breakpoint $bpnum, foo \\(\\) at \[^\r\n\]+/${::srcfile}:${bp_location}\\\\n\"" \ 84 "~\"${bp_location}\\\\t\[^\r\n\]+Set breakpoint here\\.\[^\r\n\]+\\\\n\"" \ 85 "\\*stopped,reason=\"breakpoint-hit\",disp=\"keep\",bkptno=\"$bpnum\",frame=\\{addr=\"$::hex\",func=\"foo\"\\,args=\\\[\\\],file=\"\[^\r\n\]+\",fullname=\"\[^\r\n\]+\",line=\"$bp_location\",\[^\r\n\]+}\[^\r\n\]+"] \ 86 "wait for stop" 87 88 mi_info_frame "check the current frame" \ 89 -level 0 -func foo -line $bp_location 90 } else { 91 # This pattern matches multiple lines being sent to MI's 92 # stdout stream (that is wrapped in ~"..."). Depending on 93 # where exactly the thread stops, and which debug info is 94 # available, the following stop will produce different numbers 95 # of lines. 96 set out_ln_re "(?:\r\n\[~&\]\"\[^\r\n\]+\")*" 97 98 mi_gdb_test "" \ 99 [multi_line \ 100 ".*~\"\\\\nProgram\"" \ 101 "~\" received signal SIGABRT, Aborted\\.\\\\n\"${out_ln_re}" \ 102 "\\*stopped,reason=\"signal-received\",signal-name=\"SIGABRT\"\[^\r\n\]+frame=\\{addr=\"$::hex\",\[^\r\n\]+\\}\[^\r\n\]+" \ 103 "&\"Error in testing condition for breakpoint $bpnum:\\\\n\"" \ 104 "&\"The program being debugged was signaled while in a function called from GDB\\.\\\\n\"" \ 105 "&\"GDB remains in the frame where the signal was received\\.\\\\n\"" \ 106 "&\"To change this behavior use \\\\\"set unwind-on-signal on\\\\\"\\.\\\\n\"" \ 107 "&\"Evaluation of the expression containing the function\\\\n\"" \ 108 "&\"\\(cond_throw\\(\\)\\) will be abandoned\\.\\\\n\"" \ 109 "&\"When the function is done executing, GDB will silently stop\\.\\\\n\"" \ 110 "=breakpoint-modified,bkpt={number=\"$bpnum\",type=\"breakpoint\",\[^\r\n\]+times=\"1\",\[^\r\n\]+}"] \ 111 "wait for stop" 112 113 # Don't try to check the current frame here, the inferior will 114 # be stopped somewhere in the C++ runtime at the point where 115 # it is determined that the exception has not been handled. 116 } 117} 118 119foreach_with_prefix unwind_on_exception { off } { 120 run_test $unwind_on_exception 121} 122