# quicksort.exp -- Expect script to test gdb with quicksort.c # Copyright (C) 1992 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # Please email any bugs, comments, and/or additions to this file to: # bug-gdb@prep.ai.mit.edu # use this to debug: # #log_user 1 if $tracelevel then { strace $tracelevel } if { ![istarget "hppa*-*-hpux10.30"] && ![istarget "hppa*-*-hpux11.*"] } { verbose "HPUX thread test ignored for non-hppa or pre-HP/UX-10.30 targets." return 0 } set testfile quicksort set srcfile ${srcdir}/${subdir}/${testfile}.c set binfile ${objdir}/${subdir}/${testfile} if [get_compiler_info ${binfile}] { return -1 } # To build the executable we need to link against the thread library. # # cc -Ae -g -o quicksort -lpthread quicksort.c # #compile "${srcfile} -Ae -g -lpthread -o ${binfile}" if {$gcc_compiled == 0} { set additional_flags "additional_flags=-Ae" } else { set additional_flags "" } if { [gdb_compile "${srcdir}/${subdir}/${testfile}.c" "${binfile}.o" object [list debug $additional_flags]] != "" } { gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail." } remote_exec build "ld /usr/ccs/lib/crt0.o ${binfile}.o -lcl -lpthread -lc /opt/langtools/lib/end.o -o ${binfile}" # Thread stuff is _slow_; prepare for long waits. # set oldtimeout $timeout set timeout [expr "$timeout + 300"] set oldverbose $verbose #set verbose 40 # Further, this test has some "null" lines designed # to consume output from gdb that was too late to be # matched (sequence is "gdb_test" sends; timeout and # on to next send; result finally comes in; mismatch). # # The null command is 'gdb_test "p \$pc" ".*" ""' # # NOTE: to pass a literal "$", "/" or "*" (etc.) to gdb_test, # remember that the pattern will be escaped once and # $-evaluated twice: # # "\\\*" matches "\*" # "\$" matches "$" # proc fix_timeout {} { gdb_test "p \$pc" ".*" "" } #========================= # # Simple sanity test first. # gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} gdb_test "tb 122" ".*Breakpoint.*" "" gdb_test "r" ".*122.*" "" gdb_test "thr 99" ".*Thread ID 99 not known.*" "Check too-big thread number" gdb_test "tb 145 thr 3" ".*Breakpoint.*" "set thread-specific bp 145" gdb_test "tb 146 thr 4" ".*Breakpoint.*" "set thread-specific bp 146" gdb_test "c" ".*Switched to thread.*145.*" "auto switch" gdb_test "c" ".*Switched to thread.*146.*" "auto switch 2" gdb_test "c" ".*Program exited normally.*" "" #========================= # # Test that you can't do a thread select after a program runs. # gdb_test "thread" ".*No stack.*" "No live thread after run" gdb_test "thr 2" ".*No stack.*" "Can't set thread after run" #========================= # # Test thread command changes, look for frame level reset bug. # gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} gdb_test "b 122" ".*" "" gdb_test "r" ".*122.*" "" # Prep for frame level test--go up/info thread/check frame # gdb_test "up" ".*quick_sort.*" "" gdb_test "up" ".*main.*" "" send_gdb "i th\n" gdb_expect { -re ".*7 thread.* in .* from .* in .* from .* 6 thread.*$gdb_prompt $" { fail "old thread command, says things twice" } -re ".*7 system thread.*6 system th.*5 sys.*4.*3.*2.*1.*work_init.*$gdb_prompt $" { pass "info threads" } -re ".*$gdb_prompt $" { fail "no info thread command" } timeout { fail "timeout" } } # We should have been restored two frames up--check. # send_gdb "up\n" gdb_expect { -re ".*Initial frame selected.*$gdb_prompt $" { pass "Frame correctly reset after 'info threads'" } -re ".*quick_sort.*$gdb_prompt $" { fail "Old gdb bug; should be fixed someday" } -re ".*$gdb_prompt $" { fail "real bug--FIX!" } timeout { fail "timeout" } } # Do it again, only just go to a middle frame, and use another thread. # gdb_test "thr 5" ".*" "" gdb_test "bt" ".* ___ksleep.*_lwp_cond_timedwait.*pthread_cond_wait.*worker.*__pthread_create_system.*" "" gdb_test "up" ".*1.*_lwp_cond_timedwait.*" "" gdb_test "up" ".*2.*pthread_cond_wait.*" "" gdb_test "up" ".*3.*worker.*" "" gdb_test "i th" ".*7.*6.*work_init.*" "" gdb_test "f" ".*3.*worker.*" "Frame restored" gdb_test "p wp->max_pile" ".*= 128.*" "can see vars in frame" # Thread command changes # gdb_test "thr" ".*Current thread is 5.*" "threads-no-num" gdb_test "thr 6" ".*Switching to thread 6.*" "new switch" gdb_test "thr" ".*Current thread is 6.*" "check switch" #gdb_test "thr 6" ".*Current thread is already 6.*" "dup, no switch" gdb_test "thr app all p x" ".*No symbol.*" "" gdb_test "thr" ".*Current thread is 6.*" "restore current thread" #========================= # # Test new stepping # proc get_hit { } { global hit2 global hit3 global hit4 global hit5 global hit6 global hit7 global gdb_prompt send_gdb "cont\n" gdb_expect { -re ".*Breakpoint.*145.*$gdb_prompt $" { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { set hit7 [expr "$hit7 + 1"] } -re ".*is 6.*$gdb_prompt $" { set hit6 [expr "$hit6 + 1"] } -re ".*is 5.*$gdb_prompt $" { set hit5 [expr "$hit5 + 1"] } -re ".*is 4.*$gdb_prompt $" { set hit4 [expr "$hit4 + 1"] } -re ".*is 3.*$gdb_prompt $" { set hit3 [expr "$hit3 + 1"] } -re ".*is 2.*$gdb_prompt $" { set hit2 [expr "$hit2 + 1"] } -re ".*$gdb_prompt $" { fail "can't see which thread" } timeout { fail "timeout" } } } -re ".*$gdb_prompt $" { fail "thread command" } timeout { fail "timeout" } } } gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} gdb_test "break 122" ".*" "" gdb_test "run" ".*122.*" "" # Make sure we hit a bp on every thread. # # Try one, via thread-specific bps # gdb_test "break 145 thr 2" ".*" "set thread-specific bp thr 2" gdb_test "break 145 thr 3" ".*" "set thread-specific bp thr 3" gdb_test "break 145 thr 4" ".*" "set thread-specific bp thr 4" gdb_test "break 145 thr 5" ".*" "set thread-specific bp thr 5" gdb_test "break 145 thr 6" ".*" "set thread-specific bp thr 6" gdb_test "break 145 thr 7" ".*" "set thread-specific bp thr 7" set hit2 0 set hit3 0 set hit4 0 set hit5 0 set hit6 0 set hit7 0 get_hit get_hit get_hit get_hit get_hit get_hit if { [expr "$hit2 == 1"] && [expr "$hit3 == 1"] && [expr "$hit4 == 1"] && [expr "$hit5 == 1"] && [expr "$hit6 == 1"] && [expr "$hit7 == 1"] } { pass "thread-specific bps 1" } else { fail "thread-specific bps 1" } #==================== # # Now use generic bps # gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} gdb_test "b 122" ".*" "" gdb_test "r" ".*122.*" "" # Make sure we hit a bp on every thread. # # Try two, via non-thread-specific bp # gdb_test "b 145" ".*" "b 145" set hit2 0 set hit3 0 set hit4 0 set hit5 0 set hit6 0 set hit7 0 get_hit get_hit get_hit get_hit get_hit get_hit if { [expr "$hit2 == 1"] && [expr "$hit3 == 1"] && [expr "$hit4 == 1"] && [expr "$hit5 == 1"] && [expr "$hit6 == 1"] && [expr "$hit7 == 1"] } { pass "thread-specific bps 2" } else { fail "thread-specific bps 2" } #==================== # # Complicated (original) test next. # gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} if ![runto_main] then { fail "Can't run to main" return 0 } # OK, we're at "main", there should be one thread. # gdb_test "info thread" ".*\\\* 1 system thread .*main.*" "initial thread" # Try to see the threads being created: set a breakpoint # after the creation and go around the loop a few times. # gdb_test "break 109" "Breakpoint.*109.*" "set bpt" gdb_test "c" ".*New thread.*Breakpoint.*109.*" "first continue" fix_timeout # Make sure we don't wait (waiting is for attach test) # gdb_test "set wait_here = 0" ".*" "" send_gdb "info thr\n" gdb_expect { -re ".*2 system th.*1 sy.*109.*$gdb_prompt $" { pass "saw thread create" } -re ".*1 system thread.*87.*$gdb_prompt $" { fail "didn't see thread create" } -re ".*$gdb_prompt $" { fail "no info thread command" } timeout { fail "timeout" } } gdb_test "c" ".*New thread.*Breakpoint.*109.*" "continue" fix_timeout send_gdb "info thr\n" gdb_expect { -re ".*3 system thread.*2 sys.*\\\* 1 system thread.*109.*$gdb_prompt $" { pass "saw thread create" } -re ".*2 system thread.*1 sys.*109.*$gdb_prompt $" { fail "didn't see thread create" } -re ".*1 system thread.*109.*$gdb_prompt $" { fail "didn't see thread create" } -re ".*$gdb_prompt $" { fail "no info thread command" } timeout { fail "timeout" } } fix_timeout gdb_test "clear" ".*Deleted breakpoint.*" "" # Now go on to the end of thread creation. # gdb_test "b 122" ".*" "set bpt 122" gdb_test "c" ".*New thread.*New thread.*New thread.*122.*" "" gdb_test "p \$pc" ".*" "" gdb_test "clear" ".*Deleted breakpoint.*" "" send_gdb "info thr\n" gdb_expect { -re ".*7 system thread.*6 sys.*5.*1 system thread.*122.*$gdb_prompt $" { pass "saw thread creates" } -re ".*$gdb_prompt $" { fail "no info thread command" } timeout { fail "timeout" } } # Try a thread-specific breakpoint; we expect the other threads to # be waiting at this point. # gdb_test "thr 3" ".*Switching to thread.*ksleep.*" "thread switch" gdb_test "i th" ".*\\\* 3 system thread.*" "show new current thread" gdb_test "up" ".*lwp_cond_timedwait.*" "" gdb_test "up" ".*pthread_cond_wait.*" "" gdb_test "up" ".*worker.*144.*" "" gdb_test "b 145 th 3" ".*Breakpoint.*145.*" "set thread-specific bp" gdb_test "i b" ".*breakpoint.*breakpoint.*145 thread 3.*" "show thread-specific bp" gdb_test "c" ".*Breakpoint.*145.*145.*" "hit thread-specific bp" gdb_test "p \$pc" ".*" "" # Test thread apply command on thread specific data. # gdb_test "thre app all p \$pc" ".*Thread 7.*Thread 6.*Thread 5.*Thread 4.*Thread 3.*Thread 2.*Thread 1.*" "thread apply all" gdb_test "thr ap 1 3 5 p \$pc" ".*Thread 1.*Thread 3.*Thread 5.*" "thr app 1 3 5" # Switch again, and test that others continue on a "next" # This test _could_ fail due to timing issues, but that's # unlikely. # gdb_test "thr 7" ".*Switching to thread.*" "" # Make sure that "up" stops at __pthread_exit, or # __pthread_create, the pseudo-roots, and that we # only see that pseudo-root once. # send_gdb "bt\n" gdb_expect { -re ".*Error accessing memory address.*" { fail "bt" } -re ".*pthread_create.*pthread_create.*" { fail "bt" } -re ".*worker.*pthread_create.*" { pass "bt" } -re ".*pthread_exit.*" { pass "bt" } timeout { fail "timeout on bt" } } gdb_test "up" ".*" "" gdb_test "up" ".*" "" gdb_test "up" ".*144.*" "Up 3" gdb_test "up" ".*pthread_.*" "Up 4" gdb_test "up" ".*Initial frame selected; you cannot go up.*" "catch end of thread stack" #===================== # # Things get iffy here; when we step, sometimes the step # completes, sometimes it doesn't. When it doesn't, we # hit a bp somewhere else and the step never completes # (wait_for_inferior just evaporates it). # # I think the right answer is that any failures here # should stick around to trigger later fixing. # # Here's the plan: # # Bps at 148 (5) and 154 (6) on thread 7 (two bps so we # see the difference between going around the loop and # reporting the same bp hit twice). # # Bp at 144 on thread 3. # # Step out of a library routine. # # Either the step will finish or a bp will hit. Try to # handle all the cases. # gdb_test "b 148 thr 7" ".*Breakpoint.*148.*" "" gdb_test "b 154 thr 7" ".*Breakpoint.*154.*" "set bpt 2" set hit_154_bp 0 set hit_148_bp 0 set hit_145_bp 0 set step_completed 0 # Expect zero hits # gdb_test "i b" ".*" "" send_gdb "n\n" gdb_expect { -re ".*Single stepping.*_lwp_cond_timedwait.*$gdb_prompt $" { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { set step_completed 1 pass "completed step in library code" } -re ".*$gdb_prompt $" { fail "completed step in library code, but in wrong thread" } timeout { fail "timeout" } } } -re ".*Single stepping.*Switched to thread 3.*Breakpoint.*$gdb_prompt $" { pass "step cancelled; hit bp due to thread parallelism" set hit_145_bp 1 } -re ".*Single stepping.*Switched to thread 7.*Breakpoint.*148.*$gdb_prompt $" { pass "step cancelled; hit bp due to thread parallelism" set hit_148_bp 1 } -re ".*Single stepping.*Switched to thread 7.*Breakpoint.*154.*$gdb_prompt $" { pass "step cancelled; hit bp due to thread parallelism" set hit_154_bp 1 } -re ".*$gdb_prompt $" { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { fail "No event?" } -re ".*$gdb_prompt $" { fail "No event" } timeout { fail "timeout" } } } timeout { fail "timeout" } } # Sometimes used to get SIGTRAP here; that should be fixed # # Expect appropriate hits of bpt; too much work to parse # result and check... # gdb_test "i b" ".*" "" send_gdb "c\n" gdb_expect { -re ".*SIGTRAP.*$gdb_prompt $" { fail "got SIGTRAP" } -re ".*Switched to thread 7.*Breakpoint.*154.*$gdb_prompt $" { if { $hit_154_bp == 1 } { fail "re-hit old bp" } else { pass "continue; hit parallel event after continue" } set hit_154_bp 1 } -re ".*Switched to thread 7.*Breakpoint.*148.*$gdb_prompt $" { if { $hit_148_bp == 1 } { fail "re-hit old bp" } else { pass "continue; hit parallel event after continue" } set hit_148_bp 1 } -re ".*Breakpoint.*154.*$gdb_prompt $" { if { $hit_154_bp == 1 } { fail "re-hit old bp" } else { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { pass "continue; hit parallel event after continue" } -re ".*$gdb_prompt $" { fail "hit bp in wrong thread" } timeout { fail "timeout" } } } set hit_154_bp 1 } -re ".*Breakpoint.*148.*$gdb_prompt $" { if { $hit_148_bp == 1 } { fail "re-hit old bp" } else { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { pass "continue; hit parallel event after continue" } -re ".*$gdb_prompt $" { fail "hit bp in wrong thread" } timeout { fail "timeout" } } } set hit_148_bp 1 } -re ".*Breakpoint.*145.*$gdb_prompt $" { if { $hit_145_bp == 1 } { fail "re-hit old bp" } else { send_gdb "thr\n" gdb_expect { -re ".*is 3.*$gdb_prompt $" { pass "continue; hit parallel event after continue" } -re ".*$gdb_prompt $" { fail "hit bp in wrong thread" } timeout { fail "timeout" } } } set hit_145_bp 1 } -re ".*_lwp_cond_timedwait.*$gdb_prompt $" { pass "continue; hit step completion after continue" } -re ".*Program exited normally.*" { fail "Program ended? HOW?" } -re ".*$gdb_prompt $" { fail "Unexpected event" } timeout { fail "timeout" } } # There are a number of places we _could_ be now; # this is the price of really running in parallel. # send_gdb "n\n" gdb_expect { -re ".*Switched to thread 7.*pthread_cond_wait.*$gdb_prompt $" { if { $step_completed } { fail "step already completed" } else { pass "finish step" } } -re ".*pthread_cond_wait.*$gdb_prompt $" { # # Unlikely, but we might finish the range step from inside # ksleep, before anything else. # if { $step_completed } { fail "step already completed" } else { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { pass "finish step" } -re ".*$gdb_prompt $" { fail "step in wrong thread" } timeout { fail "timeout" } } } } -re ".*Switched to thread.*Breakpoint.*145.*$gdb_prompt $" { pass "auto-switch thread" } -re ".*Breakpoint.*145.*$gdb_prompt $" { pass "auto-switch not needed, ok" } -re ".*140.*while.*n_pile.*$gdb_prompt $" { # # This is just going around the loop from the 154 bp. # send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { pass "finish step" } -re ".*$gdb_prompt $" { fail "step in wrong thread" } timeout { fail "timeout" } } } -re ".*149.*ptr = wp.*pile.*$gdb_prompt $" { # # This is just going around the loop from the 148 bp. # if { $hit_154_bp } { send_gdb "thr\n" gdb_expect { -re ".*is 7.*$gdb_prompt $" { pass "finish step" } -re ".*$gdb_prompt $" { fail "step in wrong thread" } timeout { fail "timeout" } } } else { pass "step from 149 but didn't hit it first" } } -re ".*Breakpoint 5.*154.*$gdb_prompt $" { gdb_test "i b" ".*" "" if { $hit_154_bp } { fail "hit bp again?" } else { pass "hit bp" } } -re ".*Breakpoint 5.*148.*$gdb_prompt $" { gdb_test "i b" ".*" "" if { $hit_148_bp } { fail "hit bp again?" } else { pass "hit bp" } } -re ".*$gdb_prompt $" { fail "no step finished" } timeout { fail "timeout on 'next'" } } # Let's get into some kind of known state again. # gdb_test "thr 7" ".*" "" gdb_test "info thread" ".*" "" #gdb_test "i b" ".*" "" # Leave breakpoint "154 thr 7" as only live bp. # gdb_test "d 1" ".*" "del main bp" gdb_test "d 4" ".*" "thread-specific bpt delete" gdb_test "d 5" ".*" "other bp delete" send_gdb "i b\n" gdb_expect { -re ".*breakpoint.*breakpoint.*$gdb_prompt $" { fail "more than one bp left" } -re ".*breakpoint.*154.*thread.*7.*$gdb_prompt $" { pass "Only one bp left" } -re ".*$gdb_prompt $" { fail "Wrong or no bp left" } timeout { fail "timeout on info b" } } send_gdb "c\n" gdb_expect { -re ".*SIGTRAP.*Switched to thread.*$gdb_prompt $" { fail "SIGTRAP error; lost thread-specific bpt" } -re ".*SIGTRAP.*Switched to thread.*154.*$gdb_prompt $" { fail "SIGTRAP, but hit right thread-specific bpt" } -re ".*Switched to thread.*Breakpoint.*154.*$gdb_prompt $" { pass "auto-switch back" } -re ".*Breakpoint.*154.*$gdb_prompt $" { pass "step to bp" } -re ".*$gdb_prompt $" { fail "auto-switch back" } -re ".*Program exited normally.*$gdb_prompt $" { fail "step lost" } timeout { fail "timeout" } } fix_timeout gdb_test "cle" ".*Deleted breakpoint.*" "delete last breakpoint" # Sometimes get SIGTRAP here. Continue sometimes gets another... # send_gdb "c\n" gdb_expect { -re ".*SIGTRAP.*154.*154.*$gdb_prompt $" { fail "SIGTRAP on deleted bp 154 " send_gdb "c\n" gdb_expect { -re ".*$gdb_prompt $" { pass "fixup"} timeout { fail "fixup" } } } -re ".*SIGTRAP.*144.*145.*$gdb_prompt $" { fail "SIGTRAP on deleted bp 145 " send_gdb "c\n" gdb_expect { -re ".*$gdb_prompt $" { pass "fixup"} timeout { fail "fixup" } } } -re ".*SIGTRAP.*148.*148.*$gdb_prompt $" { fail "SIGTRAP on deleted bp 148 " send_gdb "c\n" gdb_expect { -re ".*$gdb_prompt $" { pass "fixup"} timeout { fail "fixup" } } } -re ".*SIGTRAP.*$gdb_prompt $" { fail "unknown SIGTRAP" send_gdb "c\n" gdb_expect { -re ".*$gdb_prompt $" { pass "fixup"} timeout { fail "fixup" } } } -re ".*Program exited.*$gdb_prompt $" { pass "run to end" } -re ".*$gdb_prompt $" { fail "run to end" send_gdb "c\n" gdb_expect { -re ".*$gdb_prompt $" { pass "fixup"} timeout { fail "fixup" } } } timeout { fail "timeout" } } gdb_test "p \$pc" ".*No registers.*" "program done" # Done! # gdb_exit set timeout $oldtimeout set verbose $oldverbose # execute_anywhere "rm -f ${binfile}" # return 0