blob: c72ce73fd6d779493ba55b01396e4b8e9e6be773 [file] [log] [blame]
# This testcase is part of GDB, the GNU debugger.
# Copyright 2023 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 3 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, see <http://www.gnu.org/licenses/>.
# This test case looks at GDB's ability to get correct backtraces for a
# crashed inferior, recreating it from a live inferior, a corefile and
# a gcore.
set have_sleep -1
set have_pthread_kill -1
# Use 'thread apply all backtrace' to check if all expected threads
# are present, and stopped in the expected locations. Set the global
# TEST_LIST to be the a list of regexps expected to match all the
# threads. We generate it now so that the list is in the order that
# GDB sees the threads.
proc thread_apply_all {} {
global have_sleep
global have_pthread_kill
global test_list
set test_list { }
set unwind_fail false
set eol "(?=\r\n)"
set hs "\[^\r\n\]*"
set cmd "thread apply all backtrace"
gdb_test_multiple $cmd "Get thread information" {
-re "^$cmd$eol" {
exp_continue
}
-re "^\r\n#$::decimal\\\?\\\?$hs$eol" {
set unwind_fail true
exp_continue
}
-re "^\r\n${hs}syscall_task .location=SIGNAL_ALT_STACK$hs$eol" {
lappend test_list 1
exp_continue
}
-re "^\r\n${hs}syscall_task .location=SIGNAL_HANDLER$hs$eol" {
lappend test_list 2
exp_continue
}
-re "^\r\n${hs}syscall_task .location=NORMAL$hs$eol" {
lappend test_list 3
exp_continue
}
-re "^\r\n${hs}spin_task .location=SIGNAL_ALT_STACK$hs$eol" {
lappend test_list 4
exp_continue
}
-re "^\r\n${hs}spin_task .location=SIGNAL_HANDLER$hs$eol" {
lappend test_list 5
exp_continue
}
-re "^\r\n${hs}spin_task .location=NORMAL$hs$eol" {
lappend test_list 6
exp_continue
}
-re "^\r\n${hs}main$hs$eol" {
lappend test_list 7
exp_continue
}
-re "^\r\n${hs} in sleep $hs$eol" {
set have_sleep 1
exp_continue
}
-re "^\r\n${hs} in pthread_kill $hs$eol" {
set have_pthread_kill 1
exp_continue
}
-re "^\r\n$hs$eol" {
exp_continue
}
-re "^\r\n$::gdb_prompt $" {
pass $gdb_test_name
}
}
gdb_assert {$unwind_fail == false}
if { $have_sleep == -1 } {
set have_sleep 0
}
if { $have_pthread_kill == -1 } {
set have_pthread_kill 0
}
}
# Perform all the tests we're interested in. They are:
# * test if we have 7 threads
# * Creating the list of backtraces for all threads seen
# * testing if GDB recreated the full backtrace we expect for all threads
proc do_full_test {} {
global have_sleep
global have_pthread_kill
global test_list
set thread_count [get_valueof "" "\$_inferior_thread_count" 0]
gdb_assert {$thread_count == 7}
thread_apply_all
gdb_assert {$thread_count == [llength $test_list]}
if { $have_sleep } {
set sleep ".*sleep.*"
} else {
set sleep ".*"
}
if { $have_pthread_kill } {
set pthread_kill ".*pthread_kill.*"
} else {
set pthread_kill ".*"
}
for {set i 0} {$i < $thread_count } {incr i} {
set thread_num [expr [llength $test_list] - $i]
set type [lindex $test_list $i]
if { $type == 1 } {
set re \
[multi_line \
$sleep \
".*do_syscall_task .location=SIGNAL_ALT_STACK.*" \
".*signal_handler.*" \
".*signal handler called.*" \
$pthread_kill \
".*thread_function.*"]
} elseif { $type == 2 } {
set re \
[multi_line \
$sleep \
".*do_syscall_task .location=SIGNAL_HANDLER.*" \
".*signal_handler.*" \
".*signal handler called.*" \
$pthread_kill \
".*thread_function.*"]
} elseif { $type == 3 } {
set re \
[multi_line \
$sleep \
".*do_syscall_task .location=NORMAL.*" \
".*thread_function.*"]
} elseif { $type == 4 } {
set re \
[multi_line \
".*do_spin_task .location=SIGNAL_ALT_STACK.*" \
".*signal_handler.*" \
".*signal handler called.*" \
$pthread_kill \
".*thread_function.*"]
} elseif { $type == 5 } {
set re \
[multi_line \
".*do_spin_task .location=SIGNAL_HANDLER.*" \
".*signal_handler.*" \
".*signal handler called.*" \
$pthread_kill \
".*thread_function.*"]
} elseif { $type == 6 } {
set re \
[multi_line \
".*do_spin_task .location=NORMAL..*" \
".*thread_function.*"]
} elseif { $type == 7 } {
set re ".*main.*"
} else {
error "invalid type: $type"
}
gdb_test "thread apply $thread_num backtrace" $re
}
}
# Do all preparation steps for running the corefile tests, then
# call do_full_test to actually run the tests.
proc_with_prefix test_live_inferior {} {
gdb_test "handle SIGUSR1 nostop print pass" \
".*SIGUSR1.*No.*Yes.*Yes.*User defined signal 1" \
"setup SIGUSR1"
gdb_test "handle SIGUSR2 nostop print pass" \
".*SIGUSR2.*No.*Yes.*Yes.*User defined signal 2" \
"setup SIGUSR2"
if {![runto_main]} {
return
}
gdb_breakpoint "breakpt"
gdb_continue_to_breakpoint "running to breakpoint" ".*"
do_full_test
}
# Do all preparation steps for running the corefile tests, then
# call do_full_test to actually run the tests.
proc_with_prefix test_corefile {} {
set corefile [core_find $::binfile]
if { $corefile == "" } {
untested "couldn't generate corefile"
return
}
set corefile [gdb_remote_download host $corefile]
gdb_test "core-file $corefile" \
"" \
"loading_corefile" \
"A program is being debugged already\\\. Kill it\\\? \\\(y or n\\\) " \
"y"
do_full_test
}
# Do all preparation steps for running the gcore tests, then
# call do_full_test to actually run the tests.
proc_with_prefix test_gcore {} {
clean_restart "$::binfile"
gdb_test "handle SIGUSR1 nostop print pass" \
".*SIGUSR1.*No.*Yes.*Yes.*User defined signal 1" \
"setup SIGUSR1"
gdb_test "handle SIGUSR2 nostop print pass" \
".*SIGUSR2.*No.*Yes.*Yes.*User defined signal 2" \
"setup SIGUSR2"
if {![runto_main]} {
return -1
}
gdb_test "continue" ".*Segmentation fault.*" "continue to crash"
set gcore_name "${::binfile}.gcore"
set gcore_supported [gdb_gcore_cmd "$gcore_name" "saving gcore"]
if {!$gcore_supported} {
unsupported "couldn't generate gcore file"
return
}
set corefile [gdb_remote_download host $gcore_name]
gdb_test "core-file $corefile" \
"" \
"loading_corefile" \
"A program is being debugged already\\\. Kill it\\\? \\\(y or n\\\) " \
"y"
do_full_test
}
standard_testfile
if [prepare_for_testing "failed to prepare" $testfile $srcfile \
{debug pthreads}] {
return -1
}
clean_restart ${binfile}
gdb_test_no_output "set backtrace limit unlimited"
test_live_inferior
test_corefile
test_gcore