diff options
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/event-top.c | 3 | ||||
-rw-r--r-- | gdb/python/python.c | 29 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-cmd-exception.c | 22 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-cmd-exception.exp | 43 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-cmd-exception.py | 33 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-cmd-prompt.c | 22 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-cmd-prompt.exp | 55 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-cmd-prompt.py | 36 | ||||
-rw-r--r-- | gdb/ui.h | 5 |
9 files changed, 247 insertions, 1 deletions
diff --git a/gdb/event-top.c b/gdb/event-top.c index 33aef7d..ef4ceed 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -522,7 +522,8 @@ async_enable_stdin (void) { struct ui *ui = current_ui; - if (ui->prompt_state == PROMPT_BLOCKED) + if (ui->prompt_state == PROMPT_BLOCKED + && !ui->keep_prompt_blocked) { target_terminal::ours (); ui->register_file_handler (); diff --git a/gdb/python/python.c b/gdb/python/python.c index 845abb3..7b0997c 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -641,6 +641,35 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw) scoped_restore preventer = prevent_dont_repeat (); + /* If the executed command raises an exception, we may have to + enable stdin and recover the GDB prompt. + + Stdin should not be re-enabled if it is already blocked because, + for example, we are running a command in the context of a + synchronous execution command ("run", "continue", etc.). Like + this: + + User runs "continue" + --> command blocks the prompt + --> Python API is invoked, e.g. via events + --> gdb.execute(C) invoked inside Python + --> command C raises an exception + + In this case case, GDB would go back to the top "continue" command + and move on with its normal course of execution. That is, it + would enable stdin in the way it normally does. + + Similarly, if the command we are about to execute enables the + stdin while we are still in the context of a synchronous + execution command, we would be displaying the prompt too early, + before the surrounding command completes. + + For these reasons, we keep the prompt blocked, if it already is. */ + bool prompt_was_blocked = (current_ui->prompt_state == PROMPT_BLOCKED); + scoped_restore save_prompt_state + = make_scoped_restore (¤t_ui->keep_prompt_blocked, + prompt_was_blocked); + try { gdbpy_allow_threads allow_threads; diff --git a/gdb/testsuite/gdb.python/py-cmd-exception.c b/gdb/testsuite/gdb.python/py-cmd-exception.c new file mode 100644 index 0000000..6cb2c2c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd-exception.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2023-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/>. */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.python/py-cmd-exception.exp b/gdb/testsuite/gdb.python/py-cmd-exception.exp new file mode 100644 index 0000000..0bfa13e --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd-exception.exp @@ -0,0 +1,43 @@ +# Copyright (C) 2023-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 is part of the GDB testsuite. It tests a corner case where +# the executed GDB command gives an exception and enabling the stdin would +# cause the GDB prompt to be displayed prematurely. + +load_lib gdb-python.exp + +require !use_gdb_stub allow_python_tests + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 +} + +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] +gdb_test_no_output "source $pyfile" "source the script" + +gdb_start_cmd + +gdb_test_multiple "" "check the prompt" { + -re "breakpoint $decimal, main .*\r\n$gdb_prompt $" { + # The prompt is positioned correctly. + pass $gdb_test_name + } + -re "No symbol \"a\" in current context.\r\n$gdb_prompt " { + fail $gdb_test_name + } +} diff --git a/gdb/testsuite/gdb.python/py-cmd-exception.py b/gdb/testsuite/gdb.python/py-cmd-exception.py new file mode 100644 index 0000000..e44b184 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd-exception.py @@ -0,0 +1,33 @@ +# Copyright (C) 2023-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/>. + +import gdb + +class MyListener: + def __init__(self): + gdb.events.new_objfile.connect(self.handle_new_objfile_event) + self.processed_objfile = False + + def handle_new_objfile_event(self, event): + if self.processed_objfile: + return + + print('loading ' + event.new_objfile.filename) + self.processed_objfile = True + + # There is no variable 'a'. The command raises an exception. + gdb.execute('print a') + +the_listener = MyListener() diff --git a/gdb/testsuite/gdb.python/py-cmd-prompt.c b/gdb/testsuite/gdb.python/py-cmd-prompt.c new file mode 100644 index 0000000..304503c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd-prompt.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2023-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/>. */ + +int +main () +{ + return 0; /* break-here */ +} diff --git a/gdb/testsuite/gdb.python/py-cmd-prompt.exp b/gdb/testsuite/gdb.python/py-cmd-prompt.exp new file mode 100644 index 0000000..a69211c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd-prompt.exp @@ -0,0 +1,55 @@ +# Copyright (C) 2023-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 is part of the GDB testsuite. It tests a corner case +# where the executed GDB command enables the stdin while running +# inside a synchronous command, causing the GDB prompt to be displayed +# prematurely. + +load_lib gdb-python.exp +load_lib gdbserver-support.exp + +# We use the start command. +require !use_gdb_stub +require allow_python_tests allow_gdbserver_tests + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 +} + +set bp_line [gdb_get_line_number "break-here"] +gdb_breakpoint $bp_line + +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] +gdb_test_no_output "source $pyfile" "source the script" + +set gdbserver [gdbserver_start "" [standard_output_file $binfile]] +set gdbserver_gdbport [lindex $gdbserver 1] +gdb_test_no_output "python the_listener.port = '${gdbserver_gdbport}'" + +gdb_run_cmd + +gdb_test_multiple "" "prompt is positioned correctly" { + -re -wrap "break-here \[^\r\n\]+" { + pass $gdb_test_name + } +} + +# Clean up the gdbserver. +gdb_test "inferior 2" "Switching to inferior 2.*" \ + "switch to gdbserver for clean up" +gdbserver_exit 0 diff --git a/gdb/testsuite/gdb.python/py-cmd-prompt.py b/gdb/testsuite/gdb.python/py-cmd-prompt.py new file mode 100644 index 0000000..ac1fdec --- /dev/null +++ b/gdb/testsuite/gdb.python/py-cmd-prompt.py @@ -0,0 +1,36 @@ +# Copyright (C) 2023-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/>. + +import gdb + +class MyListener: + def __init__(self): + gdb.events.new_objfile.connect(self.handle_new_objfile_event) + self.processed_objfile = False + self.port = "uninitialized" + + def handle_new_objfile_event(self, event): + if self.processed_objfile: + return + + print('loading ' + event.new_objfile.filename) + self.processed_objfile = True + + gdb.execute('add-inferior -no-connection') + gdb.execute('inferior 2') + gdb.execute('target remote ' + self.port) + gdb.execute('inferior 1') + +the_listener = MyListener() @@ -135,6 +135,11 @@ struct ui /* See enum prompt_state's description. */ enum prompt_state prompt_state = PROMPT_NEEDED; + /* Whether the prompt should be kept blocked. This is useful to not + unblock the prompt too early in the context of nested command + execution. */ + bool keep_prompt_blocked = false; + /* The fields below that start with "m_" are "private". They're meant to be accessed through wrapper macros that make them look like globals. */ |