mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
4a94e36819
This commit brings all the changes made by running gdb/copyright.py as per GDB's Start of New Year Procedure. For the avoidance of doubt, all changes in this commits were performed by the script.
145 lines
5.5 KiB
Plaintext
145 lines
5.5 KiB
Plaintext
# Copyright (C) 2021-2022 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 checks for an edge case when unwinding inline frames which
|
|
# occur towards the older end of the stack when the stack ends with a
|
|
# cycle. Consider this well formed stack:
|
|
#
|
|
# main -> normal_frame -> inline_frame
|
|
#
|
|
# Now consider that, for whatever reason, the stack unwinding of
|
|
# "normal_frame" becomes corrupted, such that the stack appears to be
|
|
# this:
|
|
#
|
|
# .-> normal_frame -> inline_frame
|
|
# | |
|
|
# '------'
|
|
#
|
|
# When confronted with such a situation we would expect GDB to detect
|
|
# the stack frame cycle and terminate the backtrace at the first
|
|
# instance of "normal_frame" with a message:
|
|
#
|
|
# Backtrace stopped: previous frame identical to this frame (corrupt stack?)
|
|
#
|
|
# However, at one point there was a bug in GDB's inline frame
|
|
# mechanism such that the fact that "inline_frame" was inlined into
|
|
# "normal_frame" would cause GDB to trigger an assertion.
|
|
#
|
|
# This text makes use of a Python unwinder which can fake the cyclic
|
|
# stack cycle, further the test sets up multiple levels of normal and
|
|
# inline frames. At the point of testing the stack looks like this:
|
|
#
|
|
# main -> normal_func -> inline_func -> normal_func -> inline_func -> normal_func -> inline_func
|
|
#
|
|
# Where "normal_func" is a normal frame, and "inline_func" is an inline frame.
|
|
#
|
|
# The python unwinder is then used to force a stack cycle at each
|
|
# "normal_func" frame in turn, we then check that GDB can successfully unwind
|
|
# the stack.
|
|
|
|
standard_testfile
|
|
|
|
if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
|
|
return -1
|
|
}
|
|
|
|
# Skip this test if Python scripting is not enabled.
|
|
if { [skip_python_tests] } { continue }
|
|
|
|
if ![runto_main] then {
|
|
return 0
|
|
}
|
|
|
|
set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
|
|
|
|
# Run to the breakpoint where we will carry out the test.
|
|
gdb_breakpoint [gdb_get_line_number "Break here"]
|
|
gdb_continue_to_breakpoint "stop at test breakpoint"
|
|
|
|
# Load the script containing the unwinder, this must be done at the
|
|
# testing point as the script will examine the stack as it is loaded.
|
|
gdb_test_no_output "source ${pyfile}"\
|
|
"import python scripts"
|
|
|
|
# Check the unbroken stack.
|
|
gdb_test_sequence "bt" "backtrace when the unwind is left unbroken" {
|
|
"\\r\\n#0 \[^\r\n\]* inline_func \\(\\) at "
|
|
"\\r\\n#1 \[^\r\n\]* normal_func \\(\\) at "
|
|
"\\r\\n#2 \[^\r\n\]* inline_func \\(\\) at "
|
|
"\\r\\n#3 \[^\r\n\]* normal_func \\(\\) at "
|
|
"\\r\\n#4 \[^\r\n\]* inline_func \\(\\) at "
|
|
"\\r\\n#5 \[^\r\n\]* normal_func \\(\\) at "
|
|
"\\r\\n#6 \[^\r\n\]* main \\(\\) at "
|
|
}
|
|
|
|
with_test_prefix "cycle at level 5" {
|
|
# Arrange to introduce a stack cycle at frame 5.
|
|
gdb_test_no_output "python stop_at_level=5"
|
|
gdb_test "maint flush register-cache" \
|
|
"Register cache flushed\\."
|
|
gdb_test_lines "bt" "backtrace when the unwind is broken at frame 5" \
|
|
[multi_line \
|
|
"#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
|
|
"#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
|
|
"#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
|
|
"#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
|
|
"#4 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
|
|
"#5 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
|
|
"Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
|
|
}
|
|
|
|
with_test_prefix "cycle at level 3" {
|
|
# Arrange to introduce a stack cycle at frame 3.
|
|
gdb_test_no_output "python stop_at_level=3"
|
|
gdb_test "maint flush register-cache" \
|
|
"Register cache flushed\\."
|
|
gdb_test_lines "bt" "backtrace when the unwind is broken at frame 3" \
|
|
[multi_line \
|
|
"#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
|
|
"#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
|
|
"#2 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
|
|
"#3 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
|
|
"Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
|
|
}
|
|
|
|
with_test_prefix "cycle at level 1" {
|
|
# Arrange to introduce a stack cycle at frame 1.
|
|
gdb_test_no_output "python stop_at_level=1"
|
|
gdb_test "maint flush register-cache" \
|
|
"Register cache flushed\\."
|
|
gdb_test_lines "bt" "backtrace when the unwind is broken at frame 1" \
|
|
[multi_line \
|
|
"#0 \[^\r\n\]* inline_func \\(\\) at \[^\r\n\]+" \
|
|
"#1 \[^\r\n\]* normal_func \\(\\) at \[^\r\n\]+" \
|
|
"Backtrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)"]
|
|
}
|
|
|
|
# Flush the register cache (which also flushes the frame cache) so we
|
|
# get a full backtrace again, then switch on frame debugging and try
|
|
# to back trace. At one point this triggered an assertion.
|
|
gdb_test "maint flush register-cache" \
|
|
"Register cache flushed\\." ""
|
|
gdb_test_no_output "set debug frame 1"
|
|
gdb_test_multiple "bt" "backtrace with debugging on" {
|
|
-re "^$gdb_prompt $" {
|
|
pass $gdb_test_name
|
|
}
|
|
-re "\[^\r\n\]+\r\n" {
|
|
exp_continue
|
|
}
|
|
}
|
|
gdb_test "p 1 + 2 + 3" " = 6" \
|
|
"ensure GDB is still alive"
|