1# Copyright 2016-2023 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# This is to test whether GDBserver or other remote stubs deliver signal 17# to the inferior while step over thread. The program signal.c sends 18# signal SIGABRT to itself via kill syscall. The test sets tracepoints 19# syscall instruction and the next one, and it is quite likely that 20# GDBserver gets the signal when it steps over thread and does the 21# collection. If GDBserver doesn't deliver signal in thread step over, 22# one collection is got for one tracepoint hit. Otherwise, there may 23# be two collections for one tracepoint hit, because tracepoint is 24# collected once before step over, the program goes into signal handler 25# (because signal is delivered in step over), and program goes back 26# to the tracepoint again (one more collection) after returns from 27# signal handler. 28 29load_lib "trace-support.exp" 30 31if [target_info exists gdb,nosignals] { 32 verbose "Skipping signal.exp because of nosignals." 33 return -1 34} 35 36standard_testfile 37 38if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { 39 return -1 40} 41 42if ![runto_main] { 43 return -1 44} 45 46if ![gdb_target_supports_trace] { 47 unsupported "target does not support trace" 48 return -1 49} 50 51# Step 1, find the syscall instruction address. 52 53set syscall_insn "" 54 55# Define the syscall instruction for each target. 56 57if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } { 58 set syscall_insn "\[ \t\](int|syscall|sysenter)" 59} elseif { [istarget "aarch64*-*-linux*"] || [istarget "arm*-*-linux*"] } { 60 set syscall_insn "\[ \t\](swi|svc)\[ \t\]" 61} else { 62 unsupported "unknown syscall instruction" 63 return -1 64} 65 66# Start with a fresh gdb. 67clean_restart ${testfile} 68if ![runto_main] { 69 return -1 70} 71 72gdb_breakpoint "kill" qualified 73gdb_test "handle SIGABRT nostop noprint pass" ".*" "pass SIGABRT" 74 75# Hit the breakpoint on $syscall for the first time. In this time, 76# we will let PLT resolution done, and the number single steps we will 77# do later will be reduced. 78gdb_test "continue" "Continuing\\..*Breakpoint $decimal, (.* in |__libc_|)kill \\(\\).*" \ 79 "continue to kill, 1st time" 80 81# Hit the breakpoint on $syscall for the second time. In this time, 82# the address of syscall insn and next insn of syscall are recorded. 83gdb_test "continue" "Continuing\\..*Breakpoint $decimal, (.* in |__libc_|)kill \\(\\).*" \ 84 "continue to kill, 2nd time" 85 86gdb_test "display/i \$pc" ".*" 87 88# Single step until we see a syscall insn or we reach the 89# upper bound of loop iterations. 90set msg "find syscall insn in kill" 91set steps 0 92set max_steps 1000 93gdb_test_multiple "stepi" $msg { 94 -re ".*$syscall_insn.*$gdb_prompt $" { 95 pass $msg 96 } 97 -re "x/i .*=>.*\r\n$gdb_prompt $" { 98 incr steps 99 if {$steps == $max_steps} { 100 fail $msg 101 } else { 102 send_gdb "stepi\n" 103 exp_continue 104 } 105 } 106} 107 108if {$steps == $max_steps} { 109 return 110} 111 112# Remove the display 113gdb_test_no_output "delete display 1" 114 115set syscall_insn_addr [get_hexadecimal_valueof "\$pc" "0"] 116set syscall_insn_next 0 117set test "x/2i \$pc" 118gdb_test_multiple $test $test { 119 -re "$hex .*:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" { 120 set syscall_insn_next $expect_out(1,string) 121 } 122} 123 124delete_breakpoints 125gdb_breakpoint "start" qualified 126gdb_continue_to_breakpoint "continue to start" 127 128with_test_prefix "counter is zero" { 129 gdb_assert { 0 == [get_integer_valueof "counter" "1"] } "assert check" 130} 131 132delete_breakpoints 133 134# Step 2, set tracepoints on syscall instruction and the next one. 135# It is more likely to get signal on these two places when GDBserver 136# is doing step-over. 137gdb_test "trace *$syscall_insn_addr" "Tracepoint $decimal at .*" \ 138 "tracepoint on syscall instruction" 139set tpnum [get_integer_valueof "\$bpnum" 0] 140gdb_test "trace *$syscall_insn_next" "Tracepoint $decimal at .*" \ 141 "tracepoint on instruction following syscall instruction" 142 143gdb_breakpoint "end" qualified 144 145gdb_test_no_output "tstart" 146gdb_test "continue" ".*Breakpoint.* end .*at.*$srcfile.*" \ 147 "continue to end" 148gdb_test_no_output "tstop" 149 150set iterations [get_integer_valueof "iterations" "0"] 151 152with_test_prefix "iterations equals to counter" { 153 gdb_assert { $iterations == [get_integer_valueof "counter" "0"] } \ 154 "assert check" 155} 156 157# Record the hit times of each tracepoint in this array. 158array set tracepoint_hits { } 159for { set i $tpnum } { $i < [expr $tpnum + 2] } { incr i } { 160 set tracepoint_hits($i) 0 161} 162 163while { 1 } { 164 set test "tfind" 165 set idx 0 166 gdb_test_multiple $test $test { 167 -re "Found trace frame $decimal, tracepoint ($decimal).*\r\n$gdb_prompt $" { 168 set idx [expr $expect_out(1,string)] 169 incr tracepoint_hits($idx) 170 } 171 -re "Target failed to find requested trace frame\..*\r\n$gdb_prompt $" { 172 set idx 0 173 } 174 } 175 if {$idx == 0} { 176 break 177 } 178} 179 180# Step 3, check the number of collections on each tracepoint. 181 182for { set i $tpnum } { $i < [expr $tpnum + 2] } { incr i } { 183 184 if { $tracepoint_hits($i) == $iterations } { 185 pass "tracepoint $i hit $iterations times" 186 } elseif { $tracepoint_hits($i) > $iterations } { 187 # GDBserver deliver the signal while stepping over tracepoint, 188 # so it is possible that a tracepoint is collected twice. 189 pass "tracepoint $i hit $iterations times (spurious collection)" 190 } else { 191 fail "tracepoint $i hit $iterations times" 192 } 193} 194