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