forked from Imagelibrary/binutils-gdb
In the previous commits I have been working on improving inferior function call support. One thing that worries me about using inferior function calls from a conditional breakpoint is: what happens if the inferior function call fails? If the failure is obvious, e.g. the thread performing the call crashes, or hits a breakpoint, then this case is already well handled, and the error is reported to the user. But what if the thread performing the inferior call just deadlocks? If the user made the call from a 'print' or 'call' command, then the user might have some expectation of when the function call should complete, and, when this time limit is exceeded, the user will (hopefully) interrupt GDB and regain control of the debug session. But, when the inferior function call is from a breakpoint condition it is much harder to understand that GDB is deadlocked within an inferior call. Maybe the breakpoint hasn't been hit yet? Or maybe the condition was always false? Or maybe GDB is deadlocked in an inferior call? The only way to know for sure is for the user to periodically interrupt the inferior, check on the state of all the threads, and then continue. Additionally, the focus of the previous commit was inferior function calls, from a conditional breakpoint, in a multi-threaded inferior. This opens up a whole new set of potential failure conditions. For example, what if the function called relies on interaction with some other thread, and the other thread crashes? Or hits a breakpoint? Given how inferior function calls work (in a synchronous manner), a stop event in some other thread is going to be ignored while the inferior function call is being executed as part of a breakpoint condition, and this means that GDB could get stuck waiting for the original condition thread, which will now never complete. In this commit I propose a solution to this problem. A timeout. For targets that support async-mode we can install an event-loop timer before starting the inferior function call. When the timer expires we will stop the thread performing the inferior function call. With this mechanism in place a user can be sure that any inferior call they make will either complete, or timeout eventually. Adding a timer like this is obviously a change in behaviour for the more common 'call' and 'print' uses of inferior function calls, so, in this patch, I propose having two different timers. One I call the 'direct-call-timeout', which is used for 'call' and 'print' commands. This timeout is by default set to unlimited, which, not surprisingly, means there is no timeout in place. A second timer, which I've called 'indirect-call-timeout', is used for inferior function calls from breakpoint conditions. This timeout has a default value of 30 seconds. This is a reasonably long time to wait, and hopefully should be enough in most cases to allow the inferior call to complete. An inferior call that takes more than 30 seconds, which is installed on a breakpoint condition is really going to slow down the debug session, so hopefully this is not a common use case. The user is, of course, free to reduce, or increase the timeout value, and can always use Ctrl-c to interrupt an inferior function call, but this timeout will ensure that GDB will stop at some point. The new commands added by this commit are: set direct-call-timeout SECONDS show direct-call-timeout set indirect-call-timeout SECONDS show indirect-call-timeout These new timeouts do depend on async-mode, so, if async-mode is disabled (maint set target-async off), or not supported (e.g. target sim), then the timeout is treated as unlimited (that is, no timeout is set). For targets that "fake" non-async mode, e.g. Linux native, where non-async mode is really just async mode, but then we park the target in a sissuspend, we could easily fix things so that the timeouts still work, however, for targets that really are not async aware, like the simulator, fixing things so that timeouts work correctly would be a much bigger task - that effort would be better spent just making the target async-aware. And so, I'm happy for now that this feature will only work on async targets. The two new show commands will display slightly different text if the current target is a non-async target, which should allow users to understand what's going on. There's a somewhat random test adjustment needed in gdb.base/help.exp, the test uses a regexp with the apropos command, and expects to find a single result. Turns out the new settings I added also matched the regexp, which broke the test. I've updated the regexp a little to exclude my new settings. Reviewed-By: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> Reviewed-By: Eli Zaretskii <eliz@gnu.org> Tested-By: Luis Machado <luis.machado@arm.com> Tested-By: Keith Seitz <keiths@redhat.com>
177 lines
8.4 KiB
Plaintext
177 lines
8.4 KiB
Plaintext
# Copyright 1988-2024 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 file was written by Rob Savoye. (rob@cygnus.com)
|
|
|
|
# Test basic help functionality.
|
|
# This is not intended to test the help text of every command,
|
|
# or even more than a few commands - too much of a maintenance burden.
|
|
|
|
gdb_start
|
|
|
|
# Disable pagination.
|
|
gdb_test_no_output "set height 0" "disable pagination"
|
|
|
|
# Test all the help classes.
|
|
test_class_help "aliases" {"User-defined aliases of other commands\.\[\r\n\]+"}
|
|
test_class_help "breakpoints" {
|
|
"Making program stop at certain points\.\[\r\n\]+"
|
|
}
|
|
with_read1_timeout_factor 10 {
|
|
test_class_help "data" {"Examining data\.\[\r\n\]+"}
|
|
test_class_help "files" {"Specifying and examining files\.\[\r\n\]+"}
|
|
test_class_help "internals" {
|
|
"Maintenance commands\.\[\r\n\]+"
|
|
"Some gdb commands are provided just for use by gdb maintainers\.\[\r\n\]+"
|
|
"These commands are subject to frequent change, and may not be as\[\r\n\]+"
|
|
"well documented as user commands\.\[\r\n\]+"
|
|
}
|
|
}
|
|
test_class_help "obscure" {"Obscure features\.\[\r\n\]+"}
|
|
test_class_help "running" {"Running the program\.\[\r\n\]+"}
|
|
test_class_help "stack" {
|
|
"Examining the stack\..*\[\r\n\]+"
|
|
"When the program being debugged stops, gdb selects the innermost frame\.\[\r\n\]+"
|
|
"The commands below can be used to select other frames by number or address\.\[\r\n\]+"
|
|
}
|
|
with_read1_timeout_factor 10 {
|
|
test_class_help "status" {
|
|
"Status inquiries\.\[\r\n\]+"
|
|
}
|
|
test_class_help "support" {"Support facilities\.\[\r\n\]+"}
|
|
test_class_help "tracepoints" {
|
|
"Tracing of program execution without stopping the program\.\[\r\n\]+"
|
|
}
|
|
}
|
|
|
|
with_read1_timeout_factor 10 {
|
|
test_user_defined_class_help
|
|
|
|
# Test help of an abbreviated command. "break" is picked at random.
|
|
set help_breakpoint_text "Set breakpoint at specified location\..*"
|
|
# Test help breakpoint "b" abbreviation.
|
|
gdb_test "help b" $help_breakpoint_text "help breakpoint \"b\" abbreviation"
|
|
# Test help breakpoint "br" abbreviation.
|
|
gdb_test "help br" $help_breakpoint_text "help breakpoint \"br\" abbreviation"
|
|
# Test help breakpoint "bre" abbreviation;
|
|
gdb_test "help bre" $help_breakpoint_text "help breakpoint \"bre\" abbreviation"
|
|
# Test help breakpoint "brea" abbreviation.
|
|
}
|
|
gdb_test "help brea" $help_breakpoint_text "help breakpoint \"brea\" abbreviation"
|
|
# Test help breakpoint "break" abbreviation.
|
|
gdb_test "help break" $help_breakpoint_text "help breakpoint \"break\" abbreviation"
|
|
|
|
# Test help of an aliased command. "bt" is picked at random.
|
|
set help_backtrace_text "Print backtrace of all stack frames, or innermost COUNT frames\..*"
|
|
# Test help backtrace "bt" abbreviation.
|
|
gdb_test "help bt" $help_backtrace_text "help backtrace \"bt\" abbreviation"
|
|
# Test help backtrace.
|
|
gdb_test "help backtrace" $help_backtrace_text
|
|
|
|
# Test help commands.
|
|
gdb_test "help commands" "Set commands to be executed when the given breakpoints are hit\.\[\r\n\]+Give a space-separated breakpoint list as argument after \"commands\"\.\[\r\n\]+A list element can be a breakpoint number \\(e.g. `5'\\) or a range of numbers\[\r\n\]+\\(e.g. `5-7'\\)\.\[\r\n\]+With no argument, the targeted breakpoint is the last one set\.\[\r\n\]+The commands themselves follow starting on the next line\.\[\r\n\]+Type a line containing \"end\" to indicate the end of them\.\[\r\n\]+Give \"silent\" as the first line to make the breakpoint silent;\[\r\n\]+then no output is printed when it is hit, except what the commands print\."
|
|
|
|
# Test a prefix command. "delete" is picked at random.
|
|
# Test help delete "d" abbreviation.
|
|
set expected_help_delete {
|
|
"Delete all or some breakpoints\.\[\r\n\]+"
|
|
"Usage: delete \\\[BREAKPOINTNUM\\\]...\[\r\n\]+"
|
|
"Arguments are breakpoint numbers with spaces in between\.\[\r\n\]+"
|
|
"To delete all breakpoints, watchpoints, tracepoints, and catchpoints,\.\[\r\n\]+"
|
|
"give no argument\.\[\r\n\]+"
|
|
"Also a prefix command for deletion of other GDB objects\.\[\r\n\]+"
|
|
}
|
|
test_prefix_command_help {"d" "delete"} $expected_help_delete "help delete \"d\" abbreviation"
|
|
# Test help delete.
|
|
test_prefix_command_help "delete" $expected_help_delete
|
|
|
|
# Make sure help for help itself is present.
|
|
# Test help help "h" abbreviation.
|
|
gdb_test "help h" "Print list of commands\." "help help \"h\" abbreviation"
|
|
# Test help help.
|
|
gdb_test "help help" "Print list of commands\."
|
|
|
|
# The startup banner refers to "show copying" and "show warranty",
|
|
# might as well test for them.
|
|
# Test help info copying.
|
|
gdb_test "help show copying" "Conditions for redistributing copies of GDB\."
|
|
# Test help info warranty.
|
|
gdb_test "help show warranty" "Various kinds of warranty you do not have\."
|
|
|
|
# Test a few other random "help show" commands.
|
|
# Test help show commands.
|
|
gdb_test "help show commands" "Show the history of commands you typed\.\[\r\n\]+You can supply a command number to start with, or a `\[+\]' to start after\[\r\n\]+the previous command number shown\."
|
|
# Test help show confirm.
|
|
gdb_test "help show confirm" "Show whether to confirm potentially dangerous operations\."
|
|
|
|
# Test help info bogus-gdb-command.
|
|
gdb_test "help info bogus-gdb-command" "Undefined info command: \"bogus-gdb-command\"\. Try \"help info\"\."
|
|
# Test help gotcha.
|
|
gdb_test "help gotcha" "Undefined command: \"gotcha\"\. Try \"help\"\."
|
|
|
|
# Test apropos regex.
|
|
gdb_test "apropos \\\(print\[\^\[ bsiedf\\\"'.-\]\\\)" "handle -- Specify how to handle signals\."
|
|
# Test apropos >1 word string.
|
|
gdb_test "apropos handle signal" "handle -- Specify how to handle signals\."
|
|
# Test apropos apropos.
|
|
gdb_test "apropos apropos" "apropos -- Search for commands matching a REGEXP.*"
|
|
|
|
# Test apropos for commands having aliases.
|
|
gdb_test_no_output "alias mybt = backtrace" "define mybt alias"
|
|
gdb_test_no_output "alias mybt10 = backtrace 10" "define mybt10 alias"
|
|
|
|
gdb_test "apropos Print backtrace of all stack frames, or innermost COUNT frames\." \
|
|
"backtrace, mybt10, mybt, where, bt -- Print backtrace of all stack frames, or innermost COUNT frames\.\[\r\n\]+ alias mybt10 = backtrace 10"
|
|
|
|
# Test help for commands having aliases.
|
|
gdb_test "help bt" "backtrace, mybt10, mybt, where, bt\[\r\n\]+ alias mybt10 = backtrace 10\[\r\n\]+Print backtrace of all stack frames, or innermost COUNT frames\..*"
|
|
|
|
# Document the aliases. The apropos and help commands should then consider them
|
|
# as "standalone" commands.
|
|
gdb_test_multiple "document mybt" "document alias: mybt" {
|
|
-re "Type documentation for \"mybt\".\r\nEnd with a line saying just \"end\".\r\n>$" {
|
|
gdb_test "An alias of command backtrace without any args.\nend" \
|
|
"" \
|
|
"document alias: mybt"
|
|
}
|
|
}
|
|
gdb_test_multiple "document mybt10" "document alias: mybt10" {
|
|
-re "Type documentation for \"mybt10\".\r\nEnd with a line saying just \"end\".\r\n>$" {
|
|
gdb_test "An alias of command backtrace with arg 10.\nend" \
|
|
"" \
|
|
"document alias: mybt10"
|
|
}
|
|
}
|
|
|
|
# As the aliases are now documented, they do not appear in apropos/help backtrace output anymore.
|
|
gdb_test "apropos Print backtrace of all stack frames, or innermost COUNT frames\." \
|
|
"backtrace, where, bt -- Print backtrace of all stack frames, or innermost COUNT frames\." \
|
|
"apropos after documenting aliases"
|
|
|
|
gdb_test "help bt" "backtrace, where, bt\[\r\n\]+Print backtrace of all stack frames, or innermost COUNT frames\..*" \
|
|
"help after documenting aliases"
|
|
|
|
# Check apropos and help use the alias documentation.
|
|
gdb_test "apropos An alias of command backtrace with arg 10" \
|
|
"mybt10 -- An alias of command backtrace with arg 10\." \
|
|
"apropos after documenting aliases showing mybt10 doc"
|
|
|
|
gdb_test "help mybt" " alias mybt = backtrace \[\r\n\]+An alias of command backtrace without any args\." \
|
|
"help mybt after documenting aliases showing mybt doc"
|
|
|
|
# Check pre-defined aliases cannot be documented.
|
|
gdb_test "document where" "Alias \"where\" is built-in.*" \
|
|
"documenting builtin where alias disallowed"
|