1# Copyright 2016-2020 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 fail "can't run to main to check for trace support" 44 return -1 45} 46 47if ![gdb_target_supports_trace] { 48 unsupported "target does not support trace" 49 return -1 50} 51 52# Step 1, find the syscall instruction address. 53 54set syscall_insn "" 55 56# Define the syscall instruction for each target. 57 58if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } { 59 set syscall_insn "\[ \t\](int|syscall|sysenter)\[ \t\]" 60} elseif { [istarget "aarch64*-*-linux*"] || [istarget "arm*-*-linux*"] } { 61 set syscall_insn "\[ \t\](swi|svc)\[ \t\]" 62} else { 63 unsupported "unknown syscall instruction" 64 return -1 65} 66 67# Start with a fresh gdb. 68clean_restart ${testfile} 69if ![runto_main] { 70 fail "can't run to main" 71 return -1 72} 73 74gdb_breakpoint "kill" qualified 75gdb_test "handle SIGABRT nostop noprint pass" ".*" "pass SIGABRT" 76 77# Hit the breakpoint on $syscall for the first time. In this time, 78# we will let PLT resolution done, and the number single steps we will 79# do later will be reduced. 80gdb_test "continue" "Continuing\\..*Breakpoint $decimal, (.* in |__libc_|)kill \\(\\).*" \ 81 "continue to kill, 1st time" 82 83# Hit the breakpoint on $syscall for the second time. In this time, 84# the address of syscall insn and next insn of syscall are recorded. 85gdb_test "continue" "Continuing\\..*Breakpoint $decimal, (.* in |__libc_|)kill \\(\\).*" \ 86 "continue to kill, 2nd time" 87 88gdb_test "display/i \$pc" ".*" 89 90# Single step until we see a syscall insn or we reach the 91# upper bound of loop iterations. 92set msg "find syscall insn in kill" 93set steps 0 94set max_steps 1000 95gdb_test_multiple "stepi" $msg { 96 -re ".*$syscall_insn.*$gdb_prompt $" { 97 pass $msg 98 } 99 -re "x/i .*=>.*\r\n$gdb_prompt $" { 100 incr steps 101 if {$steps == $max_steps} { 102 fail $msg 103 } else { 104 send_gdb "stepi\n" 105 exp_continue 106 } 107 } 108} 109 110if {$steps == $max_steps} { 111 return 112} 113 114# Remove the display 115gdb_test_no_output "delete display 1" 116 117set syscall_insn_addr [get_hexadecimal_valueof "\$pc" "0"] 118set syscall_insn_next 0 119set test "x/2i \$pc" 120gdb_test_multiple $test $test { 121 -re "$hex .*:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" { 122 set syscall_insn_next $expect_out(1,string) 123 } 124} 125 126delete_breakpoints 127gdb_breakpoint "start" qualified 128gdb_continue_to_breakpoint "continue to start" 129 130gdb_assert { 0 == [get_integer_valueof "counter" "1"] } "counter is zero" 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 152gdb_assert { $iterations == [get_integer_valueof "counter" "0"] } \ 153 "iterations equals to counter" 154 155# Record the hit times of each tracepoint in this array. 156array set tracepoint_hits { } 157for { set i $tpnum } { $i < [expr $tpnum + 2] } { incr i } { 158 set tracepoint_hits($i) 0 159} 160 161while { 1 } { 162 set test "tfind" 163 set idx 0 164 gdb_test_multiple $test $test { 165 -re "Found trace frame $decimal, tracepoint ($decimal).*\r\n$gdb_prompt $" { 166 set idx [expr $expect_out(1,string)] 167 incr tracepoint_hits($idx) 168 } 169 -re "Target failed to find requested trace frame\..*\r\n$gdb_prompt $" { 170 set idx 0 171 } 172 } 173 if {$idx == 0} { 174 break 175 } 176} 177 178# Step 3, check the number of collections on each tracepoint. 179 180for { set i $tpnum } { $i < [expr $tpnum + 2] } { incr i } { 181 182 if { $tracepoint_hits($i) == $iterations } { 183 pass "tracepoint $i hit $iterations times" 184 } elseif { $tracepoint_hits($i) > $iterations } { 185 # GDBserver deliver the signal while stepping over tracepoint, 186 # so it is possible that a tracepoint is collected twice. 187 pass "tracepoint $i hit $iterations times (spurious collection)" 188 } else { 189 fail "tracepoint $i hit $iterations times" 190 } 191} 192