GNU/Linux: Interrupt/Ctrl-C with SIGSTOP instead of SIGINT [PR gdb/9425, PR gdb/14559]

After the "Always put inferiors in their own terminal/session
[gdb/9425, gdb/14559]" change, when a user types "Ctrl-C" while the
inferior is running, GDB is the one who gets the SIGINT, not the
inferior process.  GDB then forwards the SIGINT to the inferior with
target_pass_ctrlc.

That was necessary but not not sufficient to fix PRs gdb/9425,
gdb/14559, because if a program blocks SIGINT with e.g. sigprocmask,
then if GDB sends it a SIGINT, the signal isn't ever delivered to the
process, so ptrace does not intercept it.  You type Ctrl-C, but
nothing happens.  Similarly, if a program uses sigwait to wait for
SIGINT, and the program receives a SIGINT, the SIGINT is _not_
intercepted by ptrace, it goes straight to the inferior.

Now that the Ctrl-C results in a SIGINT sent to GDB instead of the
inferior, we can make GDB interrupt the program any other way we like.
This patch makes non-stop-capable ports interrupt the program with
stop_all_threads / target_stop (i.e., SIGSTOP) instead of
target_pass_ctrlc (i.e., SIGINT), which always works -- SIGSTOP can't
be blocked/ignored.  (In the future GDB may even switch to
PTRACE_INTERRUPT on Linux, though that's a project of its own.)

Another advantage here is with multi-target -- currently, because GDB
relies on Ctrl-C stopping one thread, and then stopping all other
threads in reaction to that stop, target_pass_ctrlc tries to find one
inferior with a thread that is running, in any target.  If the
selected target for some reason fails to process the Ctrl-C request,
then the Ctrl-C ends up lost.  The mechanism implemented in this patch
is different -- we never have to pick a thread, inferior or target --
we're going to stop everything, so we end up in stop_all_threads.

For non-stop, the patch preserves the current behavior of only
stopping one thread in reaction to Ctrl-C, so it can still happen that
the thread that GDB selects to stop disappears and the Ctrl-C ends up
being lost.  However, because now GDB always sees the SIGINT first, we
can change how Ctrl-C behaves there too.  We could even make it
configurable -- for example, it could be reasonable that Ctrl-C simply
drops the CLI back to the prompt, without stopping anything at all.
That might be interesting for "set observer-mode on", at least.

This commit has a user-visible behavior change in all-stop mode --
when you interrupt the program with Ctrl-C, instead of:

  Thread 1 "threads" received signal SIGINT, Interrupt.

You'll get:

  Thread 1 "threads" stopped.

Which is what you already got with the "interrupt" command in non-stop
mode.

If you really want to pass a SIGINT to the program, you can then issue:

  (gdb) signal SIGINT

This commit also adjusts the testsuite to cope with that output
alternative.

With this change, the gdb.base/sigint-sigwait.exp and
gdb.base/sigint-masked-out.exp testcases now pass cleanly on
GNU/Linux, on both native debugging and gdbserver + "maint set
target-non-stop on", so the kfails are adjusted accordingly.

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <pedro@palves.net>

	PR gdb/9425
	PR gdb/14559
	* event-top.c (default_quit_handler): Mark infrun event-loop
	handler with mark_infrun_async_event_handler_ctrl_c instead of
	passing the Ctrl-C to the target directly with target_pass_ctrlc.
	* infcmd.c (interrupt_target_1): On non-stop targets, Mark infrun
	event-loop handler with
	mark_infrun_async_event_handler_interrupt_all instead of using
	target_interrupt.
	* infrun.c (interrupt_all_requested, switch_to_stop_thread)
	(sync_interrupt_all)
	(mark_infrun_async_event_handler_interrupt_all)
	(mark_infrun_async_event_handler_ctrl_c): New.
	(infrun_async_inferior_event_handler): Handle Ctrl-C/interrupt
	requests.
	* infrun.h (mark_infrun_async_event_handler_interrupt_all)
	(mark_infrun_async_event_handler_ctrl_c): Declare.
	* linux-nat.c (wait_for_signal): Don't handle Ctrl-C here.
	(linux_nat_wait_1): Handle it here, by marking the infrun event
	handler, and returning TARGET_WAITKIND_IGNORE with the quit flag
	still set.
	* target.c (maybe_pass_ctrlc): New.
	(target_terminal::inferior, target_terminal::restore_inferior):
	Use it.
	(target_pass_ctrlc): Ass there's no non-stop target pushed.

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <pedro@palves.net>

	PR gdb/9425
	PR gdb/14559
	* gdb.base/bp-cmds-continue-ctrl-c.exp: Expect "stopped" in
	alternative to "signal SIGINT".
	* gdb.base/interrupt-daemon-attach.exp: Likewise.
	* gdb.base/interrupt-daemon.exp: Likewise.
	* gdb.base/interrupt-noterm.exp: Likewise.
	* gdb.base/interrupt.exp: Likewise.
	* gdb.base/random-signal.exp: Likewise.
	* gdb.base/range-stepping.exp: Likewise.
	* gdb.gdb/selftest.exp: Likewise.
	* gdb.mi/new-ui-mi-sync.exp: Likewise.
	* gdb.multi/multi-target-interrupt.exp: Likewise.
	* gdb.multi/multi-target-no-resumed.exp: Likewise.
	* gdb.multi/multi-term-settings.exp: Likewise.
	* gdb.server/reconnect-ctrl-c.exp: Likewise.
	* gdb.threads/async.exp: Likewise.
	* gdb.threads/continue-pending-status.exp: Likewise.
	* gdb.threads/leader-exit.exp: Likewise.
	* gdb.threads/manythreads.exp: Likewise.
	* gdb.threads/pthreads.exp: Likewise.
	* gdb.threads/schedlock.exp: Likewise.
	* gdb.threads/sigthread.exp: Likewise.

	* lib/gdb.exp (can_interrupt_blocked_sigint): New.
	* gdb.base/sigint-masked-out.exp (test_ctrl_c)
	(test_interrupt_cmd): Use can_interrupt_blocked_sigint, and don't
	kfail if true.
	* gdb.base/sigint-sigwait.exp (test_ctrl_c, test_interrupt_cmd):
	Likewise.

Change-Id: I83c1b6a20deea1f1909156adde1d60b8f6f2629b
This commit is contained in:
Pedro Alves 2021-06-03 19:39:19 +01:00
parent 86a5798736
commit 814fb49ba3
29 changed files with 315 additions and 57 deletions

View File

@ -1002,7 +1002,15 @@ default_quit_handler (void)
if (target_terminal::is_ours ())
quit ();
else
target_pass_ctrlc ();
{
/* Let the even loop handle the quit/interrupt. In some
modes (e.g., "set non-stop off" + "maint set
target-non-stop on"), it's not safe to request an
interrupt right now, as we may be in the middle of
handling some other event, and target_stop changes infrun
state. */
mark_infrun_async_event_handler_ctrl_c ();
}
}
}

View File

@ -2846,7 +2846,39 @@ interrupt_target_1 (bool all_threads)
stop_current_target_threads_ns (inferior_ptid);
}
else
target_interrupt ();
{
if (exists_non_stop_target ())
{
/* Ignore the interrupt request if everything is already
stopped. */
auto any_resumed = [] ()
{
for (thread_info *thr : all_non_exited_threads ())
{
if (thr->executing)
return true;
if (thr->suspend.waitstatus_pending_p)
return true;
}
return false;
};
if (any_resumed ())
{
/* Stop all threads, and report one single stop for all
threads. Since the "interrupt" command works
asynchronously on all other modes (non-stop or true
all-stop + stopping with SIGINT), i.e., the command
finishes and GDB prints the prompt before the target
actually stops, make this mode work the same, by
deferring the actual synchronous stopping work to the
event loop. */
mark_infrun_async_event_handler_interrupt_all ();
}
}
else
target_interrupt ();
}
disable_commit_resumed.reset_and_commit ();
}

View File

@ -9440,13 +9440,158 @@ static const struct internalvar_funcs siginfo_funcs =
NULL
};
/* Callback for infrun's target events source. This is marked when a
thread has a pending status to process. */
/* True if the user used the "interrupt" command and we want to handle
the interruption via the event loop instead of immediately. This
is so that "interrupt" always stops the program asynchronously in
all the different execution modes. In particular, in "set non-stop
off" + "maint set target-non-stop on" mode, we want to
synchronously stop all threads with stop_all_threads, so we delay
doing that to the event loop, so that "interrupt" presents a prompt
immediately, and then presents the stop afterwards, just like what
happens in non-stop mode, or if the target is in true all-stop mode
and the interrupting is done by sending a SIGINT to the inferior
process. */
static bool interrupt_all_requested = false;
/* Pick the thread to report the stop on and to switch to it. */
static void
switch_to_stop_thread ()
{
thread_info *stop_thr = nullptr;
if (previous_thread != nullptr && previous_thread->state == THREAD_RUNNING)
stop_thr = previous_thread.get ();
else
{
for (thread_info *thr : all_non_exited_threads ())
if (thr->state == THREAD_RUNNING)
{
stop_thr = thr;
break;
}
}
gdb_assert (stop_thr != nullptr);
switch_to_thread (stop_thr);
}
/* Synchronously stop all threads, saving interesting events as
pending events, and present a normal stop on one of the threads.
Preference is given to the "previous thread", which was the thread
that the user last resumed. This is used in "set non-stop off" +
"maint set target-non-stop on" mode to stop the target in response
to Ctrl-C or the "interrupt" command. */
static void
sync_interrupt_all ()
{
/* Events are always processed with the main UI as current UI. This
way, warnings, debug output, etc. are always consistently sent to
the main console. */
scoped_restore save_ui = make_scoped_restore (&current_ui, main_ui);
/* Exposed by gdb.base/paginate-after-ctrl-c-running.exp. */
/* Temporarily disable pagination. Otherwise, the user would be
given an option to press 'q' to quit, which would cause an early
exit and could leave GDB in a half-baked state. */
scoped_restore save_pagination
= make_scoped_restore (&pagination_enabled, false);
scoped_disable_commit_resumed disable_commit_resumed ("stopping for ctrl-c");
gdb_assert (!non_stop);
/* Stop all threads before picking which one to present the stop on
-- this is safer than the other way around because otherwise the
thread we pick could exit just while we try to stop it. */
stop_all_threads ();
switch_to_stop_thread ();
target_waitstatus ws;
ws.kind = TARGET_WAITKIND_STOPPED;
ws.value.sig = GDB_SIGNAL_0;
set_last_target_status (current_inferior ()->process_target (),
inferior_ptid, ws);
stopped_by_random_signal = true;
stop_print_frame = true;
normal_stop ();
inferior_event_handler (INF_EXEC_COMPLETE);
/* If a UI was in sync execution mode, and now isn't, restore its
prompt (a synchronous execution command has finished, and we're
ready for input). */
all_uis_check_sync_execution_done ();
}
/* See infrun.h. */
void
mark_infrun_async_event_handler_interrupt_all ()
{
mark_infrun_async_event_handler ();
interrupt_all_requested = true;
}
/* See infrun.h. */
void
mark_infrun_async_event_handler_ctrl_c ()
{
mark_infrun_async_event_handler ();
set_quit_flag ();
}
/* Callback for infrun's target events source. This is marked either
when a thread has a pending status to process, or a target
interrupt was requested, either with Ctrl-C or the "interrupt"
command and target is in non-stop mode. */
static void
infrun_async_inferior_event_handler (gdb_client_data data)
{
/* Handle a Ctrl-C while the inferior has the terminal, or an
"interrupt" cmd request. */
if ((!target_terminal::is_ours () && check_quit_flag ())
|| interrupt_all_requested)
{
interrupt_all_requested = false;
if (exists_non_stop_target ())
{
if (non_stop)
{
/* Stop one thread, like it would happen if we were
stopping with SIGINT sent to the foreground
process. */
switch_to_stop_thread ();
interrupt_target_1 (false);
}
else
{
/* Stop all threads, and report one single stop for all
threads. */
sync_interrupt_all ();
}
}
else
{
/* Pass a Ctrl-C request to the target. Usually this means
sending a SIGINT to the inferior process. */
target_pass_ctrlc ();
}
/* Don't clear the event handler yet -- there may be pending
events to process. */
return;
}
clear_async_event_handler (infrun_async_inferior_event_token);
inferior_event_handler (INF_REG_EVENT);
}

View File

@ -255,6 +255,18 @@ extern void infrun_async (int enable);
loop. */
extern void mark_infrun_async_event_handler (void);
/* Like mark_infrun_async_event_handler, and ask the event loop to
stop all threads, in response to an "interrupt" command. */
extern void mark_infrun_async_event_handler_interrupt_all ();
/* Like mark_infrun_async_event_handler, and ask the event loop to
handle a "Ctrl-C" interruption request. In some modes (e.g., "set
non-stop off" + "maint set target-non-stop on"), we interrupt the
target with target_stop, and it's not safe to use that right away,
as we may be in the middle of handling some other event, and
target_stop changes infrun state. */
extern void mark_infrun_async_event_handler_ctrl_c ();
/* The global chain of threads that need to do a step-over operation
to get past e.g., a breakpoint. */
extern struct thread_info *global_thread_step_over_chain_head;

View File

@ -2142,19 +2142,6 @@ wait_for_signal ()
{
linux_nat_debug_printf ("about to sigsuspend");
sigsuspend (&suspend_mask);
/* If the quit flag is set, it means that the user pressed Ctrl-C
and we're debugging a process that is running on a separate
terminal, so we must forward the Ctrl-C to the inferior. (If the
inferior is sharing GDB's terminal, then the Ctrl-C reaches the
inferior directly.) We must do this here because functions that
need to block waiting for a signal loop forever until there's an
event to report before returning back to the event loop. */
if (!target_terminal::is_ours ())
{
if (check_quit_flag ())
target_pass_ctrlc ();
}
}
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
@ -3317,8 +3304,32 @@ linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
/* We shouldn't end up here unless we want to try again. */
gdb_assert (lp == NULL);
/* Block until we get an event reported with SIGCHLD. */
/* Block until we get an event reported with SIGCHLD or a SIGINT
interrupt. */
wait_for_signal ();
/* If the quit flag is set, it means that the user pressed
Ctrl-C and we're debugging a process that is running on a
separate terminal, so we must forward the Ctrl-C to the
inferior. (If the inferior is sharing GDB's terminal, then
the Ctrl-C reaches the inferior directly.) If we were
interrupted by Ctrl-C, return back to the event loop and let
it handle interrupting the target (or targets). */
if (!target_terminal::is_ours () && check_quit_flag ())
{
mark_infrun_async_event_handler_ctrl_c ();
linux_nat_debug_printf ("exit (quit flag)");
/* If we got a SIGCHLD, need to end up here again. */
async_file_mark ();
ourstatus->kind = TARGET_WAITKIND_IGNORE;
restore_child_signals_mask (&prev_mask);
return minus_one_ptid;
}
}
gdb_assert (lp);

View File

@ -927,6 +927,21 @@ target_terminal::init (void)
m_terminal_state = target_terminal_state::is_ours;
}
/* Called after switching the terminal to the inferior. If the user
hit C-c before, pretend that it was hit right here. Non-stop
targets however are more complicated though, as interruption with
"set non-stop off" + "maint set target-non-stop on" wants to stop
all threads individually with target_stop (and synchronously wait
for the stops), so we let the event loop handle it, when it's
recursion-safe to do so. */
static void
maybe_pass_ctrlc ()
{
if (!exists_non_stop_target () && check_quit_flag ())
target_pass_ctrlc ();
}
/* See target/target.h. */
void
@ -961,8 +976,7 @@ target_terminal::inferior (void)
/* If the user hit C-c before, pretend that it was hit right
here. */
if (check_quit_flag ())
target_pass_ctrlc ();
maybe_pass_ctrlc ();
}
/* See target/target.h. */
@ -998,8 +1012,7 @@ target_terminal::restore_inferior (void)
/* If the user hit C-c before, pretend that it was hit right
here. */
if (check_quit_flag ())
target_pass_ctrlc ();
maybe_pass_ctrlc ();
}
/* Switch terminal state to DESIRED_STATE, either is_ours, or
@ -3797,6 +3810,9 @@ target_interrupt ()
void
target_pass_ctrlc (void)
{
/* Non-stop targets interrupt programs with target_stop instead. */
gdb_assert (!exists_non_stop_target ());
/* Pass the Ctrl-C to the first target that has a thread
running. */
for (inferior *inf : all_inferiors ())

View File

@ -87,6 +87,9 @@ proc do_test {} {
-re "Program received signal SIGINT.*\r\n$gdb_prompt $" {
send_log "$internal_pass (SIGINT)\n"
}
-re "Program stopped.*\r\n$gdb_prompt $" {
send_log "$internal_pass (stopped)\n"
}
-re "Quit\r\n$gdb_prompt $" {
send_log "$internal_pass (Quit)\n"

View File

@ -81,7 +81,7 @@ proc do_test {} {
}
after 500 {send_gdb "\003"}
gdb_test "" "(Program|Thread .*) received signal SIGINT.*" \
gdb_test "" "(Program|Thread .*) (received signal SIGINT|stopped).*" \
"stop with control-c"
remote_exec host "kill -9 $child_pid"

View File

@ -53,7 +53,7 @@ proc do_test {} {
set test "ctrl-c stops process"
gdb_test_multiple "" $test {
-re "received signal SIGINT.*\r\n$gdb_prompt $" {
-re "(received signal SIGINT|stopped).*\r\n$gdb_prompt $" {
pass $test
}
}
@ -79,7 +79,7 @@ proc do_test {} {
set test "interrupt cmd stops process"
gdb_test_multiple "" $test {
-re "received signal SIGINT" {
-re "(received signal SIGINT|stopped)" {
pass $test
}
}

View File

@ -67,7 +67,7 @@ gdb_test_multiple $test $test {
set test "inferior received SIGINT"
gdb_test_multiple "" $test {
-re "\r\nProgram received signal SIGINT.*" {
-re "\r\nProgram (received signal SIGINT|stopped).*" {
# This appears after the prompt, which was already consumed
# above.
pass $test

View File

@ -82,7 +82,7 @@ if ![file exists $binfile] then {
send_gdb "\003"
set msg "send_gdb control C"
gdb_test_multiple "" $msg {
-re "Program received signal SIGINT.*$gdb_prompt $" {
-re "Program (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $msg
}
}
@ -166,7 +166,7 @@ if ![file exists $binfile] then {
set msg "Send Control-C, second time"
send_gdb "\003"
gdb_test_multiple "" "$msg" {
-re "Program received signal SIGINT.*$gdb_prompt $" {
-re "Program (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$msg"
}
}

View File

@ -47,7 +47,8 @@ proc do_test {} {
# For this to work we must be sure to consume the "Continuing."
# message first, or GDB's signal handler may not be in place.
after 500 {send_gdb "\003"}
gdb_test "" "Program received signal SIGINT.*" "stop with control-c"
gdb_test "" "Program (received signal SIGINT|stopped).*" \
"stop with control-c"
}
# With native debugging and "run" (with job control), the ctrl-c

View File

@ -193,7 +193,7 @@ if ![target_info exists gdb,nointerrupts] {
incr vcont_r_counter
exp_continue
}
-re "Program received signal SIGINT.*$gdb_prompt $" {
-re "Program (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $test
}
}

View File

@ -36,6 +36,8 @@ proc_with_prefix test_ctrl_c {} {
return
}
set can_interrupt [can_interrupt_blocked_sigint]
gdb_test_multiple "continue" "" {
-re "Continuing" {
pass $gdb_test_name
@ -52,7 +54,9 @@ proc_with_prefix test_ctrl_c {} {
pass $gdb_test_name
}
timeout {
setup_kfail "gdb/9425" *-*-*
if {!$can_interrupt} {
setup_kfail "gdb/9425" *-*-*
}
fail "$gdb_test_name (timeout)"
}
}
@ -71,6 +75,8 @@ proc_with_prefix test_interrupt_cmd {} {
return
}
set can_interrupt [can_interrupt_blocked_sigint]
gdb_test_multiple "continue&" "" {
-re "Continuing\\.\r\n$gdb_prompt " {
pass $gdb_test_name
@ -91,7 +97,9 @@ proc_with_prefix test_interrupt_cmd {} {
pass $gdb_test_name
}
timeout {
setup_kfail "gdb/14559" *-*-*
if {!$can_interrupt} {
setup_kfail "gdb/14559" *-*-*
}
fail "$gdb_test_name (timeout)"
}
}

View File

@ -37,6 +37,8 @@ proc_with_prefix test_ctrl_c {} {
return
}
set can_interrupt [can_interrupt_blocked_sigint]
gdb_test_multiple "continue" "" {
-re "Continuing" {
pass $gdb_test_name
@ -54,7 +56,9 @@ proc_with_prefix test_ctrl_c {} {
pass $gdb_test_name
}
-re -wrap "Inferior.*exited normally.*" {
setup_kfail "gdb/9425" *-*-*
if {!$can_interrupt} {
setup_kfail "gdb/9425" *-*-*
}
fail "$gdb_test_name (the program exited)"
}
}
@ -73,6 +77,8 @@ proc_with_prefix test_interrupt_cmd {} {
return
}
set can_interrupt [can_interrupt_blocked_sigint]
gdb_test_multiple "continue&" "" {
-re "Continuing\\.\r\n$gdb_prompt " {
pass $gdb_test_name
@ -95,7 +101,9 @@ proc_with_prefix test_interrupt_cmd {} {
pass $gdb_test_name
}
-re "Inferior.*exited normally" {
setup_kfail "gdb/14559" *-*-*
if {!$can_interrupt} {
setup_kfail "gdb/14559" *-*-*
}
fail "$gdb_test_name (the program exited)"
}
}

View File

@ -97,7 +97,7 @@ proc test_with_self { } {
send_gdb "\003"
# "Thread 1" is displayed iff Guile support is linked in.
gdb_expect {
-re "(Thread .*|Program) received signal SIGINT.*$gdb_prompt $" {
-re "(Thread .*|Program) (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$description"
}
-re ".*$gdb_prompt $" {
@ -119,7 +119,7 @@ proc test_with_self { } {
set description "send ^C to child process again"
send_gdb "\003"
gdb_expect {
-re "(Thread .*|Program) received signal SIGINT.*$gdb_prompt $" {
-re "(Thread .*|Program) (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$description"
}
-re ".*$gdb_prompt $" {

View File

@ -92,7 +92,7 @@ proc do_test {sync_command} {
gdb_test_multiple "interrupt" "$message" {
-re "$gdb_prompt " {
gdb_test_multiple "" "$message" {
-re "received signal SIGINT" {
-re "(received signal SIGINT|stopped)" {
pass $message
}
}

View File

@ -46,7 +46,7 @@ proc test_ctrlc {} {
set msg "send_gdb control C"
gdb_test_multiple "" $msg {
-re "received signal SIGINT.*$gdb_prompt $" {
-re "(received signal SIGINT|stopped).*$gdb_prompt $" {
pass $msg
}
}

View File

@ -59,7 +59,7 @@ proc test_no_resumed_infs {inf_A inf_B} {
# Now stop the program (all targets).
send_gdb "\003"
gdb_test_multiple "" "send_gdb control C" {
-re "received signal SIGINT.*$gdb_prompt $" {
-re "(received signal SIGINT|stopped).*$gdb_prompt $" {
pass $gdb_test_name
}
}

View File

@ -278,7 +278,7 @@ proc coretest {inf1_how inf2_how} {
if {$expect_ttou} {
gdb_test "" "Quit" "stop with control-c (Quit)"
} else {
gdb_test "" "received signal SIGINT.*" "stop with control-c (SIGINT)"
gdb_test "" "(received signal SIGINT|stopped).*" "stop with control-c (SIGINT)"
}
# Useful for debugging in case the Ctrl-C above fails.

View File

@ -49,7 +49,7 @@ with_test_prefix "preparation" {
gdb_test "disconnect" ".*"
}
# Connect, continue, send Ctrl-C and expect a SIGINT stop.
# Connect, continue, send Ctrl-C and expect a stop.
proc connect_continue_ctrl_c {} {
global gdbserver_protocol gdbserver_gdbport
@ -67,7 +67,7 @@ proc connect_continue_ctrl_c {} {
}
after 1000 {send_gdb "\003"}
gdb_test "" "Program received signal SIGINT.*" "stop with control-c"
gdb_test "" "Program (received signal SIGINT|stopped).*" "stop with control-c"
}
with_test_prefix "first" {

View File

@ -80,7 +80,7 @@ proc test_current_thread {expected_thr} {
gdb_test_multiple $test $test {
-re "^interrupt\r\n$gdb_prompt " {
gdb_test_multiple "" $test {
-re "Thread .* received signal SIGINT, Interrupt\\." {
-re "Thread .* (received signal SIGINT, Interrupt|stopped)\\." {
pass $test
}
}

View File

@ -116,7 +116,7 @@ for {set i 0} {$i < $attempts} {incr i} {
set msg "caught interrupt"
gdb_test_multiple "" $msg {
-re "Thread .* received signal SIGINT.*$gdb_prompt $" {
-re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $msg
}
}

View File

@ -55,7 +55,7 @@ send_gdb "\003"
set test "caught interrupt"
gdb_test_multiple "" $test {
-re "Thread .* received signal SIGINT.*$gdb_prompt $" {
-re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $test
}
}

View File

@ -56,7 +56,7 @@ gdb_test_multiple "continue" "first continue" {
# we don't lose GDB's output while we do it.
remote_expect host 1 { timeout { } }
# Send a Ctrl-C and wait for the SIGINT.
# Send a Ctrl-C and wait for the stop.
proc interrupt_and_wait { message } {
global gdb_prompt
@ -70,7 +70,7 @@ proc interrupt_and_wait { message } {
-re "\\\[\[^\]\]* exited\\\]\r\n" {
exp_continue
}
-re " received signal SIGINT.*$gdb_prompt $" {
-re " (received signal SIGINT|stopped).*$gdb_prompt $" {
pass "$message"
}
-re "$gdb_prompt $" {

View File

@ -204,7 +204,7 @@ proc check_control_c {} {
send_gdb "\003"
set description "Stopped with a ^C"
gdb_expect {
-re "Thread .* received signal SIGINT.*$gdb_prompt $" {
-re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $description
}
-re "Quit.*$gdb_prompt $" {

View File

@ -68,14 +68,9 @@ proc stop_process { description } {
# For this to work we must be sure to consume the "Continuing."
# message first, or GDB's signal handler may not be in place.
after 1000 {send_gdb "\003"}
gdb_expect {
-re "Thread .* received signal SIGINT.*$gdb_prompt $"
{
pass $description
}
timeout
{
fail "$description (timeout)"
gdb_test_multiple "" $description {
-re "Thread .* (received signal SIGINT|stopped).*$gdb_prompt $" {
pass $description
}
}
}

View File

@ -49,4 +49,4 @@ after 500 {send_gdb "\003"}
# Make sure we do not get an internal error from hitting Control-C
# while many signals are flying back and forth.
gdb_test "" "Thread .* received signal SIGINT.*" "stop with control-c"
gdb_test "" "Thread .* (received signal SIGINT|stopped).*" "stop with control-c"

View File

@ -2870,6 +2870,25 @@ gdb_caching_proc supports_memtag {
return 0
}
# Return true if the target is able to interrupt a program that blocks
# SIGINT.
proc can_interrupt_blocked_sigint {} {
if {[istarget *-*-linux*]} {
gdb_test_multiple "maint show target-non-stop" "" {
-re "(is|currently) on.*$::gdb_prompt $" {
}
-re "(is|currently) off.*$::gdb_prompt $" {
# GDBserver still tries to interrupt programs with
# SIGINT.
return 0
}
}
}
# Assume possible.
return 1
}
# Return 1 if the target supports hardware single stepping.
proc can_hardware_single_step {} {