mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-05 15:15:42 +00:00
Fix bug in DAP handling of 'pause' requests
While working on cancellation, I noticed that a DAP 'pause' request would set the "do not emit the continue" flag. This meant that a subsequent request that should provoke a 'continue' event would instead suppress the event. I then tried writing a more obvious test case for this, involving an inferior call -- and discovered that gdb.events.cont does not fire for an inferior call. This patch installs a new event listener for gdb.events.inferior_call and arranges for this to emit continue and stop events when appropriate. It also fixes the original bug, by adding a check to exec_and_expect_stop.
This commit is contained in:
@@ -128,8 +128,9 @@ def exec_and_expect_stop(cmd, reason):
|
|||||||
"""Indicate that a stop is expected, then execute CMD"""
|
"""Indicate that a stop is expected, then execute CMD"""
|
||||||
global _expected_stop
|
global _expected_stop
|
||||||
_expected_stop = reason
|
_expected_stop = reason
|
||||||
global _suppress_cont
|
if reason != StopKinds.PAUSE:
|
||||||
_suppress_cont = True
|
global _suppress_cont
|
||||||
|
_suppress_cont = True
|
||||||
# FIXME if the call fails should we clear _suppress_cont?
|
# FIXME if the call fails should we clear _suppress_cont?
|
||||||
exec_and_log(cmd)
|
exec_and_log(cmd)
|
||||||
|
|
||||||
@@ -156,6 +157,26 @@ def _on_stop(event):
|
|||||||
send_event("stopped", obj)
|
send_event("stopped", obj)
|
||||||
|
|
||||||
|
|
||||||
|
# This keeps a bit of state between the start of an inferior call and
|
||||||
|
# the end. If the inferior was already running when the call started
|
||||||
|
# (as can happen if a breakpoint condition calls a function), then we
|
||||||
|
# do not want to emit 'continued' or 'stop' events for the call. Note
|
||||||
|
# that, for some reason, gdb.events.cont does not fire for an infcall.
|
||||||
|
_infcall_was_running = False
|
||||||
|
|
||||||
|
|
||||||
|
@in_gdb_thread
|
||||||
|
def _on_inferior_call(event):
|
||||||
|
global _infcall_was_running
|
||||||
|
if isinstance(event, gdb.InferiorCallPreEvent):
|
||||||
|
_infcall_was_running = inferior_running
|
||||||
|
if not _infcall_was_running:
|
||||||
|
_cont(None)
|
||||||
|
else:
|
||||||
|
if not _infcall_was_running:
|
||||||
|
_on_stop(None)
|
||||||
|
|
||||||
|
|
||||||
gdb.events.stop.connect(_on_stop)
|
gdb.events.stop.connect(_on_stop)
|
||||||
gdb.events.exited.connect(_on_exit)
|
gdb.events.exited.connect(_on_exit)
|
||||||
gdb.events.new_thread.connect(_new_thread)
|
gdb.events.new_thread.connect(_new_thread)
|
||||||
@@ -163,3 +184,4 @@ gdb.events.thread_exited.connect(_thread_exited)
|
|||||||
gdb.events.cont.connect(_cont)
|
gdb.events.cont.connect(_cont)
|
||||||
gdb.events.new_objfile.connect(_new_objfile)
|
gdb.events.new_objfile.connect(_new_objfile)
|
||||||
gdb.events.free_objfile.connect(_objfile_removed)
|
gdb.events.free_objfile.connect(_objfile_removed)
|
||||||
|
gdb.events.inferior_call.connect(_on_inferior_call)
|
||||||
|
|||||||
44
gdb/testsuite/gdb.dap/pause.c
Normal file
44
gdb/testsuite/gdb.dap/pause.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/* This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright 2011-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/>. */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
do_nothing ()
|
||||||
|
{
|
||||||
|
return 91;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
return_false ()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sleep_a_bit ()
|
||||||
|
{
|
||||||
|
sleep (1); /* STOP */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
sleep_a_bit ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ require allow_dap_tests
|
|||||||
|
|
||||||
load_lib dap-support.exp
|
load_lib dap-support.exp
|
||||||
|
|
||||||
standard_testfile attach.c
|
standard_testfile
|
||||||
|
|
||||||
if {[build_executable ${testfile}.exp $testfile $srcfile] == -1} {
|
if {[build_executable ${testfile}.exp $testfile $srcfile] == -1} {
|
||||||
return
|
return
|
||||||
@@ -29,6 +29,18 @@ if {[dap_launch $testfile] == ""} {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Set a conditional breakpoint that will never fire. This is done to
|
||||||
|
# test the state-tracking in events -- an inferior call from a
|
||||||
|
# breakpoint condition should not cause any sort of stop or continue
|
||||||
|
# events.
|
||||||
|
set line [gdb_get_line_number "STOP"]
|
||||||
|
dap_check_request_and_response "set conditional breakpoint" \
|
||||||
|
setBreakpoints \
|
||||||
|
[format {o source [o path [%s]] \
|
||||||
|
breakpoints [a [o line [i %d] \
|
||||||
|
condition [s "return_false()"]]]} \
|
||||||
|
[list s $srcfile] $line]
|
||||||
|
|
||||||
dap_check_request_and_response "start inferior" configurationDone
|
dap_check_request_and_response "start inferior" configurationDone
|
||||||
dap_wait_for_event_and_check "inferior started" thread "body reason" started
|
dap_wait_for_event_and_check "inferior started" thread "body reason" started
|
||||||
|
|
||||||
@@ -45,4 +57,20 @@ dap_check_request_and_response pause pause \
|
|||||||
dap_wait_for_event_and_check "stopped by pause" stopped \
|
dap_wait_for_event_and_check "stopped by pause" stopped \
|
||||||
"body reason" pause
|
"body reason" pause
|
||||||
|
|
||||||
|
set result [dap_request_and_response evaluate {o expression [s do_nothing()]}]
|
||||||
|
gdb_assert {[dict get [lindex $result 0] body result] == 91} \
|
||||||
|
"check result of evaluation"
|
||||||
|
|
||||||
|
set seen fail
|
||||||
|
foreach event [lindex $result 1] {
|
||||||
|
if {[dict get $event type] != "event"} {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if {[dict get $event event] == "continued"} {
|
||||||
|
set seen pass
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gdb_assert {$seen == "pass"} "continue event from inferior call"
|
||||||
|
|
||||||
dap_shutdown
|
dap_shutdown
|
||||||
|
|||||||
Reference in New Issue
Block a user