forked from Imagelibrary/binutils-gdb
This fixes yet another bug exposed by ASAN + multi-target.exp Running an Asan-enabled GDB against gdb.multi/multi-target.exp exposed yet another latent GDB bug. See here for the full log: https://sourceware.org/pipermail/gdb-patches/2020-July/170761.html As Simon described, the problem is: - We create a new frame_info object in restore_selected_frame (by calling find_relative_frame) - The frame is allocated on the frame_cache_obstack - In frame_unwind_try_unwinder, we try to find an unwinder for that frame - While trying unwinders, memory read fails because the remote target closes, because of "monitor exit" - That calls reinit_frame_cache (as shown above), which resets frame_cache_obstack - When handling the exception in frame_unwind_try_unwinder, we try to set some things on the frame_info object (like *this_cache, which in fact tries to write into frame_info::prologue_cache), but the frame_info object is no more, it went away with the obstack. Fix this by maintaining a frame cache generation counter. Then in exception handling code paths, don't touch frame objects if the generation is not the same as it was on entry. This commit generalizes the gdb.server/server-kill.exp testcase and reuses it to test the scenario in question. The new tests fail without the GDB fix. gdb/ChangeLog: * frame-unwind.c (frame_unwind_try_unwinder): On exception, don't touch THIS_CACHE/THIS_FRAME if the frame cache was cleared meanwhile. * frame.c (frame_cache_generation, get_frame_cache_generation): New. (reinit_frame_cache): Increment FRAME_CACHE_GENERATION. (get_prev_frame_if_no_cycle): On exception, don't touch PREV_FRAME/THIS_FRAME if the frame cache was cleared meanwhile. * frame.h (get_frame_cache_generation): Declare. gdb/testsuite/ChangeLog: * gdb.server/server-kill.exp (prepare): New, factored out from the top level. (kill_server): New. (test_tstatus, test_unwind_nosyms, test_unwind_syms): New. (top level) : Call test_tstatus, test_unwind_nosyms, test_unwind_syms.
129 lines
3.3 KiB
Plaintext
129 lines
3.3 KiB
Plaintext
# This testcase is part of GDB, the GNU debugger.
|
|
#
|
|
# Copyright 2013-2020 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/>.
|
|
|
|
# Check that GDB handles GDBserver disconnecting abruptly, in several
|
|
# scenarios.
|
|
|
|
load_lib gdbserver-support.exp
|
|
|
|
standard_testfile
|
|
|
|
if {[skip_gdbserver_tests]} {
|
|
return 0
|
|
}
|
|
|
|
if { [build_executable "failed to prepare" ${testfile}] } {
|
|
return -1
|
|
}
|
|
|
|
# Spawn GDBserver, run to main, extract GDBserver's PID and save it in
|
|
# the SERVER_PID global.
|
|
|
|
proc prepare {} {
|
|
global binfile gdb_prompt srcfile decimal
|
|
global server_pid
|
|
|
|
clean_restart $binfile
|
|
|
|
# Make sure we're disconnected, in case we're testing with an
|
|
# extended-remote board, therefore already connected.
|
|
gdb_test "disconnect" ".*"
|
|
|
|
gdbserver_run ""
|
|
|
|
# Continue past server_pid assignment.
|
|
gdb_breakpoint ${srcfile}:[gdb_get_line_number "i = 0;"]
|
|
gdb_continue_to_breakpoint "after server_pid assignment"
|
|
|
|
# Get the pid of GDBServer.
|
|
set test "p server_pid"
|
|
set server_pid 0
|
|
gdb_test_multiple $test $test {
|
|
-re " = ($decimal)\r\n$gdb_prompt $" {
|
|
set server_pid $expect_out(1,string)
|
|
pass $test
|
|
}
|
|
}
|
|
|
|
if {$server_pid == 0} {
|
|
return 0
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
# Kill GDBserver using the PID saved by prepare.
|
|
|
|
proc kill_server {} {
|
|
global server_pid
|
|
|
|
remote_exec target "kill -9 $server_pid"
|
|
}
|
|
|
|
# Test issuing "tstatus" right after the connection is dropped.
|
|
|
|
proc_with_prefix test_tstatus {} {
|
|
if ![prepare] {
|
|
return
|
|
}
|
|
|
|
kill_server
|
|
|
|
# Enable trace status packet which is disabled after the
|
|
# connection if the remote target doesn't support tracepoint at
|
|
# all. Otherwise, no RSP packet is sent out.
|
|
gdb_test_no_output "set remote trace-status-packet on"
|
|
|
|
# Force GDB to talk with GDBserver, so that we can get the
|
|
# "connection closed" error.
|
|
gdb_test "tstatus" {Remote connection closed|Remote communication error\. Target disconnected\.: Connection reset by peer\.}
|
|
}
|
|
|
|
# Test unwinding with no debug/unwind info, right after the connection
|
|
# is dropped.
|
|
|
|
proc_with_prefix test_unwind_nosyms {} {
|
|
if ![prepare] {
|
|
return
|
|
}
|
|
|
|
# Remove symbols, so that we try to unwind with one of the
|
|
# heuristic unwinders, and read memory from within its sniffer.
|
|
gdb_unload
|
|
|
|
kill_server
|
|
|
|
gdb_test "bt" "(Target disconnected|Remote connection closed|Remote communication error).*"
|
|
}
|
|
|
|
# Test unwinding with debug/unwind info, right after the connection is
|
|
# dropped.
|
|
|
|
proc_with_prefix test_unwind_syms {} {
|
|
if ![prepare] {
|
|
return
|
|
}
|
|
|
|
kill_server
|
|
|
|
gdb_test "bt" "(Target disconnected|Remote connection closed|Remote communication error).*"
|
|
}
|
|
|
|
test_tstatus
|
|
test_unwind_nosyms
|
|
test_unwind_syms
|