1# Copyright (C) 2004-2021 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# Test making hand function calls in multiple threads. 17 18set NR_THREADS 4 19 20standard_testfile 21 22if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "additional_flags=-DNR_THREADS=$NR_THREADS"]] != "" } { 23 return -1 24} 25 26# Some targets can't do function calls, so don't even bother with this 27# test. 28if [target_info exists gdb,cannot_call_functions] { 29 unsupported "this target can not call functions" 30 continue 31} 32 33proc get_dummy_frame_number { } { 34 global gdb_prompt 35 36 gdb_test_multiple "bt" "" { 37 -re "#(\[0-9\]*) *<function called from gdb>.*$gdb_prompt $" { 38 return $expect_out(1,string) 39 } 40 -re "$gdb_prompt $" { 41 return "" 42 } 43 timeout { 44 return "" 45 } 46 } 47 return "" 48} 49 50clean_restart ${binfile} 51 52if { ![runto_main] } { 53 fail "can't run to main" 54 return 0 55} 56 57gdb_test "break all_threads_running" \ 58 "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ 59 "breakpoint on all_threads_running" 60 61gdb_test "break hand_call" \ 62 "Breakpoint 3 at .*: file .*${srcfile}, line .*" \ 63 "breakpoint on hand_call" 64 65# Run the program and make sure GDB reports that we stopped after 66# hitting breakpoint 2 in all_threads_running(). 67 68gdb_test "continue" \ 69 ".*Breakpoint 2, all_threads_running ().*" \ 70 "run to all_threads_running" 71 72# Before we start making hand function calls, turn on scheduler locking. 73 74gdb_test_no_output "set scheduler-locking on" "enable scheduler locking" 75gdb_test "show scheduler-locking" ".* locking scheduler .* is \"on\"." "show scheduler locking on" 76 77# Now hand-call a function in each thread, having the function 78# stop without returning. 79 80# Add one for the main thread. 81set total_nr_threads [expr $NR_THREADS + 1] 82 83# Thread numbering in gdb is origin-1, so begin numbering at 1. 84for { set i 1 } { $i <= $total_nr_threads } { incr i } { 85 set thread_nr $i 86 gdb_test "thread $thread_nr" \ 87 ".*Switching to thread $thread_nr.*" \ 88 "prepare to make hand call, thread $thread_nr" 89 gdb_test_multiple "call hand_call()" "" { 90 -re "Breakpoint 3, .*$gdb_prompt $" { 91 pass "hand call, thread $thread_nr" 92 } 93 -re "$gdb_prompt $" { 94 fail "hand call, thread $thread_nr (got gdb prompt)" 95 } 96 timeout { 97 # If the target fails to stop at the breakpoint, it just ends 98 # up in an infinite loop in hand_call(). If this happens 99 # and we have lost the GDB prompt, no further tests in 100 # this file will work and there is no point in continuing. 101 fail "hand call, thread $thread_nr (runaway target)" 102 return 0 103 } 104 } 105} 106 107# Now have each hand-called function return. 108 109# Turn confirmation off for the "return" command. 110gdb_test_no_output "set confirm off" 111 112clear_xfail "*-*-*" 113 114for { set i 1 } { $i <= $total_nr_threads } { incr i } { 115 set thread_nr $i 116 gdb_test "thread $thread_nr" ".*" \ 117 "prepare to discard hand call, thread $thread_nr" 118 set frame_number [get_dummy_frame_number] 119 if { "$frame_number" == "" } { 120 fail "dummy stack frame number, thread $thread_nr" 121 # Need something. 122 set frame_number 0 123 } else { 124 pass "dummy stack frame number, thread $thread_nr" 125 } 126 # Pop the dummy frame. 127 gdb_test "frame $frame_number" ".*" "setting frame, thread $thread_nr" 128 gdb_test "return" ".*" "discard hand call, thread $thread_nr" 129 # In case getting the dummy frame number failed, re-enable for next iter. 130 clear_xfail "*-*-*" 131} 132 133# Make sure all dummy frames got popped. 134 135gdb_test_multiple "maint print dummy-frames" "all dummies popped" { 136 -re ".*stack=.*$gdb_prompt $" { 137 fail "all dummies popped" 138 } 139 -re ".*$gdb_prompt $" { 140 pass "all dummies popped" 141 } 142} 143 144# Before we resume the full program, turn off scheduler locking. 145gdb_test_no_output "set scheduler-locking off" "disable scheduler locking" 146gdb_test "show scheduler-locking" ".* locking scheduler .* is \"off\"." "show scheduler locking off" 147 148# Continue one last time, the program should exit normally. 149# 150# ??? This currently doesn't work because gdb doesn't know how to singlestep 151# over reported breakpoints that weren't in the last thread to run. 152# Commented out until then. 153# 154# For reference sake ... 155# An alternative is to manually work around the issue by manually setting 156# the thread back to the first thread: the program is still at the 157# all_threads_running breakpoint, which wasn't the last thread to run, 158# and gdb doesn't know how to singlestep over reported breakpoints that 159# weren't in the last thread to run. 160#gdb_test "thread 1" ".*" "set thread to 1, prepare to resume" 161# 162#gdb_continue_to_end "hand-call-in-threads" 163 164return 0 165