# Copyright 2009-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 .
load_lib "ada.exp"
load_lib "gdb-guile.exp"
load_lib "gdb-python.exp"
require allow_ada_tests
standard_ada_testfile foo
if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
return -1
}
clean_restart ${testfile}
set bp_location [gdb_get_line_number "STOP_HERE" ${testdir}/foo.adb]
runto "foo.adb:$bp_location"
# Make sure that all tasks appear in the "info tasks" listing, and
# that the active task is the environment task.
gdb_test "info tasks" \
[join {" +ID +TID P-ID Pri State +Name" \
"\\* +1 .* main_task" \
" +2 .* task_list\\(1\\)" \
" +3 .* task_list\\(2\\)" \
" +4 .* task_list\\(3\\)"} \
"\r\n"] \
"info tasks before inserting breakpoint"
# Confirm that the "info threads" output lines up with the tasks list.
gdb_test "info threads" \
[multi_line \
"\\*\\s+1\\s+\[^\r\n\]+\\s\"foo\"\\s\[^\r\n\]+" \
"\\s+2\\s+\[^\r\n\]+\\s\"task_list\\(1\\)\"\\s\[^\r\n\]+" \
"\\s+3\\s+\[^\r\n\]+\\s\"task_list\\(2\\)\"\\s\[^\r\n\]+" \
"\\s+4\\s+\[^\r\n\]+\\s\"task_list\\(3\\)\"\\s\[^\r\n\]+"]
# Check that multiple uses of the 'task' keyword will give an error.
gdb_test "break break_me task 1 task 3" "You can specify only one task\\."
gdb_test "watch j task 1 task 3" "You can specify only one task\\."
# Check that attempting to combine 'task' and 'thread' gives an error.
gdb_test "break break_me task 1 thread 1" \
"You can specify only one of thread or task\\."
gdb_test "break break_me thread 1 task 1" \
"You can specify only one of thread or task\\."
gdb_test "watch j task 1 thread 1" \
"You can specify only one of thread or task\\."
gdb_test "watch j thread 1 task 1" \
"You can specify only one of thread or task\\."
# Insert a breakpoint that should stop only if task 1 stops. Since
# task 1 never calls break_me, this shouldn't actually ever trigger.
# The fact that this breakpoint is created _before_ the next one
# matters. GDB used to have a bug where it would report the first
# breakpoint in the list that matched the triggered-breakpoint's
# address, no matter which task it was specific to.
gdb_test "break break_me task 1" "Breakpoint .* at .*"
set bp_number [get_integer_valueof "\$bpnum" "INVALID" \
"get number of breakpoint for task 1"]
gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 1" \
"check info breakpoints for task 1 breakpoint"
# Now, insert a breakpoint that should stop only if task 3 stops, and
# extract its number. Use gdb_test here so that we can validate that
# the 'Breakpoint ... also set at' line correctly includes the task
# number of the previous breakpoint.
gdb_test "break break_me task 3" \
[multi_line \
"Note: breakpoint $bp_number \\(task 1\\) also set at pc $hex\\." \
"Breakpoint $decimal at $hex: \[^\r\n\]+"]
set bp_number [get_integer_valueof "\$bpnum" "INVALID" \
"get number of breakpoint for task 3"]
gdb_test "info breakpoints" "foo.adb:${decimal}\r\n\\s+stop only in task 3" \
"check info breakpoints for task 3 breakpoint"
# Test the Python API for the breakpoint task attribute.
if {[allow_python_tests]} {
gdb_test_no_output "python bp = gdb.breakpoints()\[$bp_number - 1\]" \
"get gdb.Breakpoint from list"
gdb_test "python print(bp.task)" "3"
gdb_test "python print(bp.thread)" "None"
gdb_test "python bp.thread = 1" \
[multi_line \
"RuntimeError: Cannot set both task and thread attributes\\." \
"Error while executing Python code\\."] \
"try setting the thread, but expect an error"
gdb_test_no_output "python bp.task = None"
gdb_test_no_output "python bp.thread = 1"
gdb_test "python bp.task = 3" \
[multi_line \
"RuntimeError: Cannot set both task and thread attributes\\." \
"Error while executing Python code\\."] \
"try setting the task, but expect an error"
# Reset the breakpoint to the state required for the rest of this
# test.
gdb_test_no_output "python bp.thread = None"
gdb_test_no_output "python bp.task = 3"
}
# Test the Guile API for the breakpoint task attribute.
if {[allow_guile_tests]} {
gdb_install_guile_utils
gdb_install_guile_module
gdb_scm_test_silent_cmd "guile (define blist (breakpoints))" \
"get breakpoint list"
gdb_scm_test_silent_cmd "guile (define bp (list-ref blist (- $bp_number 1)))" \
"get from list"
gdb_test "guile (print (breakpoint-task bp))" "= 3"
gdb_test "guile (print (breakpoint-thread bp))" "= #f"
gdb_test "guile (set-breakpoint-thread! bp 1)" \
[multi_line \
"ERROR: In procedure set-breakpoint-thread!:" \
"(ERROR: )?In procedure gdbscm_set_breakpoint_thread_x:\
cannot set both task and thread attributes" \
"Error while executing Scheme code."] \
"attempt to set thread, but expect an error"
gdb_scm_test_silent_cmd "guile (set-breakpoint-task! bp #f)" \
"clear breakpoint task attribute"
gdb_scm_test_silent_cmd "guile (set-breakpoint-thread! bp 1)" \
"set breakpoint thread now task is unset"
gdb_test "guile (set-breakpoint-task! bp 1)" \
[multi_line \
"ERROR: In procedure set-breakpoint-task!:" \
"(ERROR: )?In procedure gdbscm_set_breakpoint_task_x:\
cannot set both task and thread attributes" \
"Error while executing Scheme code."] \
"attempt to set task, but expect an error"
# Reset the breakpoint to the state required for the rest of this
# test.
gdb_scm_test_silent_cmd "guile (set-breakpoint-thread! bp #f)" \
"clear breakpoint thread attribute"
gdb_scm_test_silent_cmd "guile (set-breakpoint-task! bp 3)" \
"restore breakpoint task attribute"
}
# Continue to that breakpoint. Task 2 should hit it first, and GDB
# is expected to ignore that hit and resume the execution. Only then
# task 3 will hit our breakpoint, and GDB is expected to stop at that
# point. Also make sure that GDB reports the correct breakpoint number.
gdb_test "continue" \
".*Breakpoint $bp_number, foo.break_me \\(\\).*" \
"continue to breakpoint"
# Check that it is indeed task 3 that hit the breakpoint by checking
# which is the active task.
gdb_test "info tasks" \
[join {" +ID +TID P-ID Pri State +Name" \
" +1 .* main_task" \
" +2 .* task_list\\(1\\)" \
"\\* +3 .* task_list\\(2\\)" \
" +4 .* task_list\\(3\\)"} \
"\r\n"] \
"info tasks after hitting breakpoint"
# Now, resume the execution and make sure that GDB does not stop when
# task 4 hits the breakpoint. Continuing thus results in our program
# running to completion.
set bp_location [gdb_get_line_number "STOP_HERE_2" ${testdir}/foo.adb]
gdb_breakpoint foo.adb:$bp_location
gdb_continue_to_breakpoint second ".*foo.adb:$bp_location.*null; -- STOP_HERE_2"
# A regression test for a crash caused by trying to find the thread
# for a terminated task.
gdb_test "interpreter-exec mi \"-ada-task-info\"" ".*"