aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/breakpoint.c12
-rw-r--r--gdb/infcall.c41
-rw-r--r--gdb/infrun.c16
-rw-r--r--gdb/testsuite/gdb.mi/mi-condbreak-fail.c39
-rw-r--r--gdb/testsuite/gdb.mi/mi-condbreak-fail.exp67
5 files changed, 152 insertions, 23 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index d898167..93634bd 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5535,7 +5535,6 @@ bpstat_check_breakpoint_conditions (bpstat *bs, thread_info *thread)
else
within_current_scope = false;
}
- CORE_ADDR pc_before_check = get_frame_pc (get_selected_frame (nullptr));
if (within_current_scope)
{
try
@@ -5555,17 +5554,6 @@ bpstat_check_breakpoint_conditions (bpstat *bs, thread_info *thread)
(gdb_stderr, ex,
"Error in testing condition for breakpoint %d:\n",
b->number);
-
- /* If the pc value changed as a result of evaluating the
- condition then we probably stopped within an inferior
- function call due to some unexpected stop, e.g. the thread
- hit another breakpoint, or the thread received an
- unexpected signal. In this case we don't want to also
- print the information about this breakpoint. */
- CORE_ADDR pc_after_check
- = get_frame_pc (get_selected_frame (nullptr));
- if (pc_before_check != pc_after_check)
- bs->print = 0;
}
}
else
diff --git a/gdb/infcall.c b/gdb/infcall.c
index ddf325a..bea5b18 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -564,10 +564,13 @@ call_thread_fsm::should_stop (struct thread_info *thread)
call.. */
return_value = get_call_return_value (&return_meta_info);
- /* Break out of wait_sync_command_done. */
+ /* Break out of wait_sync_command_done. This is similar to the
+ async_enable_stdin call in normal_stop (which we don't call),
+ however, in this case we only change the WAITING_UI. This is
+ enough for wait_sync_command_done. */
scoped_restore save_ui = make_scoped_restore (&current_ui, waiting_ui);
- target_terminal::ours ();
- waiting_ui->prompt_state = PROMPT_NEEDED;
+ gdb_assert (current_ui->prompt_state == PROMPT_BLOCKED);
+ async_enable_stdin ();
}
return true;
@@ -661,14 +664,32 @@ run_inferior_call (std::unique_ptr<call_thread_fsm> sm,
infcall_debug_printf ("thread is now: %s",
inferior_ptid.to_string ().c_str ());
- /* If GDB has the prompt blocked before, then ensure that it remains
- so. normal_stop calls async_enable_stdin, so reset the prompt
- state again here. In other cases, stdin will be re-enabled by
- inferior_event_handler, when an exception is thrown. */
+ /* After the inferior call finished, async_enable_stdin has been
+ called, either from normal_stop or from
+ call_thread_fsm::should_stop, and the prompt state has been
+ restored by the scoped_restore in the try block above.
+
+ If the inferior call finished successfully, then we should
+ disable stdin as we don't know yet whether the inferior will be
+ stopping. Calling async_disable_stdin restores things to how
+ they were when this function was called.
+
+ If the inferior call didn't complete successfully, then
+ normal_stop has already been called, and we know for sure that we
+ are going to present this stop to the user. In this case, we
+ call async_enable_stdin. This changes the prompt state to
+ PROMPT_NEEDED.
+
+ If the previous prompt state was PROMPT_NEEDED, then as
+ async_enable_stdin has already been called, nothing additional
+ needs to be done here. */
if (current_ui->prompt_state == PROMPT_BLOCKED)
- current_ui->unregister_file_handler ();
- else
- current_ui->register_file_handler ();
+ {
+ if (call_thread->thread_fsm ()->finished_p ())
+ async_disable_stdin ();
+ else
+ async_enable_stdin ();
+ }
/* If the infcall does NOT succeed, normal_stop will have already
finished the thread states. However, on success, normal_stop
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 7efa061..8286026 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4458,6 +4458,8 @@ fetch_inferior_event ()
auto defer_delete_threads
= make_scope_exit (delete_just_stopped_threads_infrun_breakpoints);
+ int stop_id = get_stop_id ();
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (&ecs);
@@ -4485,7 +4487,19 @@ fetch_inferior_event ()
clean_up_just_stopped_threads_fsms (&ecs);
- if (thr != nullptr && thr->thread_fsm () != nullptr)
+ if (stop_id != get_stop_id ())
+ {
+ /* If the stop-id has changed then a stop has already been
+ presented to the user in handle_inferior_event, this is
+ likely a failed inferior call. As the stop has already
+ been announced then we should not notify again.
+
+ Also, if the prompt state is not PROMPT_NEEDED then GDB
+ will not be ready for user input after this function. */
+ should_notify_stop = false;
+ gdb_assert (current_ui->prompt_state == PROMPT_NEEDED);
+ }
+ else if (thr != nullptr && thr->thread_fsm () != nullptr)
should_notify_stop
= thr->thread_fsm ()->should_notify_stop ();
diff --git a/gdb/testsuite/gdb.mi/mi-condbreak-fail.c b/gdb/testsuite/gdb.mi/mi-condbreak-fail.c
new file mode 100644
index 0000000..94bd248
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-condbreak-fail.c
@@ -0,0 +1,39 @@
+/* Copyright 2023 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+volatile int global_counter = 0;
+
+int
+cond_fail ()
+{
+ volatile int *p = 0;
+ return *p; /* Crash here. */
+}
+
+int
+foo ()
+{
+ global_counter += 1; /* Set breakpoint here. */
+ return 0;
+}
+
+int
+main ()
+{
+ int res = foo ();
+ return res;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-condbreak-fail.exp b/gdb/testsuite/gdb.mi/mi-condbreak-fail.exp
new file mode 100644
index 0000000..34be4b9
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-condbreak-fail.exp
@@ -0,0 +1,67 @@
+# Copyright (C) 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/>.
+
+# Check that when GDB fails to evaluate the condition of a conditional
+# breakpoint we only get one *stopped notification.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile
+
+if [build_executable ${testfile}.exp ${binfile} ${srcfile}] {
+ return -1
+}
+
+if {[mi_clean_restart $binfile]} {
+ return
+}
+
+if {[mi_runto_main] == -1} {
+ return
+}
+
+# Create the conditional breakpoint.
+set bp_location [gdb_get_line_number "Set breakpoint here"]
+mi_create_breakpoint "-c \"cond_fail ()\" $srcfile:$bp_location" \
+ "insert conditional breakpoint" \
+ -func foo -file ".*$srcfile" -line "$bp_location" \
+ -cond "cond_fail \\(\\)"
+
+# Number of the previous breakpoint.
+set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID" \
+ "get number for breakpoint"]
+
+# The line where we expect the inferior to crash.
+set crash_linenum [gdb_get_line_number "Crash here"]
+
+# Run the inferior and wait for it to stop.
+mi_send_resuming_command "exec-continue" "continue the inferior"
+mi_gdb_test "" \
+ [multi_line \
+ "~\"\\\\nProgram\"" \
+ "~\" received signal SIGSEGV, Segmentation fault\\.\\\\n\"" \
+ "~\"$hex in cond_fail \\(\\) at \[^\r\n\]+\"" \
+ "~\"${crash_linenum}\\\\t\\s+return \\*p;\[^\r\n\]+\\\\n\"" \
+ "\\*stopped,reason=\"signal-received\",signal-name=\"SIGSEGV\"\[^\r\n\]+" \
+ "&\"Error in testing condition for breakpoint $bpnum:\\\\n\"" \
+ "&\"The program being debugged was signaled while in a function called from GDB\\.\\\\n\"" \
+ "&\"GDB remains in the frame where the signal was received\\.\\\\n\"" \
+ "&\"To change this behavior use \\\\\"set unwindonsignal on\\\\\"\\.\\\\n\"" \
+ "&\"Evaluation of the expression containing the function\\\\n\"" \
+ "&\"\\(cond_fail\\) will be abandoned\\.\\\\n\"" \
+ "&\"When the function is done executing, GDB will silently stop\\.\\\\n\"" \
+ "=breakpoint-modified,bkpt={number=\"$bpnum\",type=\"breakpoint\",\[^\r\n\]+times=\"1\",\[^\r\n\]+}"] \
+ "wait for stop"