From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id WEnqMgzKx2DNUQAAWB0awg (envelope-from ) for ; Mon, 14 Jun 2021 17:28:44 -0400 Received: by simark.ca (Postfix, from userid 112) id CDBFB1F163; Mon, 14 Jun 2021 17:28:44 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=MAILING_LIST_MULTI, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 555C91E54D for ; Mon, 14 Jun 2021 17:28:41 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 22D70397302B for ; Mon, 14 Jun 2021 21:28:41 +0000 (GMT) Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) by sourceware.org (Postfix) with ESMTPS id 7D748397304C for ; Mon, 14 Jun 2021 21:24:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7D748397304C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=palves.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wm1-f54.google.com with SMTP id n35-20020a05600c3ba3b02901cdecb6bda8so306177wms.5 for ; Mon, 14 Jun 2021 14:24:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zPVx0v1zi2Mw4BokAOrF8W4V+wg3rqTE80Umd14F9G4=; b=VPpWdjPY0MGtyjuBHfr3EhErBeBJwuduj/ZvQGro+Xtp/HWp0NnxF66Q5A5eR6bq7O IMdZriajDXGM5ILKXhMNEftDZWeD9dsb4j9xYUg5F0hLyvTaAMpOFWbR11rQBzA/sWGW 6RiKIAYGkMahyhh06U5sQMod+SqoFzR5CCxAjtqmq5cIC1HIkuBqdvq74Ty4bBGgWMHO Dbwj754gyQaRcmpRE4XJYGgL0cgTXTZ/ah3h8Het2i9PX0CH1vXWdflHtUH9w8oFgunb TYgnfGsPd+9YmrpxS2o/sPtUHB047I7uzRMabWjnn3bY0FNH7NqEBMrjQNuGCS761wPQ POFA== X-Gm-Message-State: AOAM533skbByLgqYCLFs66HeZtaUeXxV7toBdd+go68OzSWYYnJTl/DV +uzTV32qIcVmt+sY7ShmLECuduRWFuWh5w== X-Google-Smtp-Source: ABdhPJyPVdKvcnODq2QTK6x61mLKeGIg/91qSNySqLDySc1hC2cWAILU0dIISsTDjc/q5/Xkd+hdGw== X-Received: by 2002:a05:600c:a07:: with SMTP id z7mr18403524wmp.83.1623705883713; Mon, 14 Jun 2021 14:24:43 -0700 (PDT) Received: from localhost ([2001:8a0:f932:6a00:6b6e:c7b6:c5a7:aac3]) by smtp.gmail.com with ESMTPSA id r1sm3475686wmh.32.2021.06.14.14.24.42 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 14 Jun 2021 14:24:42 -0700 (PDT) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH v2 15/16] GNU/Linux: Interrupt/Ctrl-C with SIGSTOP instead of SIGINT [PR gdb/9425, PR gdb/14559] Date: Mon, 14 Jun 2021 22:24:09 +0100 Message-Id: <20210614212410.1612666-16-pedro@palves.net> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210614212410.1612666-1-pedro@palves.net> References: <20210614212410.1612666-1-pedro@palves.net> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+public-inbox=simark.ca@sourceware.org Sender: "Gdb-patches" 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 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 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 --- gdb/event-top.c | 10 +- gdb/infcmd.c | 34 +++- gdb/infrun.c | 149 +++++++++++++++++- gdb/infrun.h | 12 ++ gdb/linux-nat.c | 39 +++-- gdb/target.c | 24 ++- .../gdb.base/bp-cmds-continue-ctrl-c.exp | 3 + .../gdb.base/interrupt-daemon-attach.exp | 2 +- gdb/testsuite/gdb.base/interrupt-daemon.exp | 4 +- gdb/testsuite/gdb.base/interrupt-noterm.exp | 2 +- gdb/testsuite/gdb.base/interrupt.exp | 4 +- gdb/testsuite/gdb.base/random-signal.exp | 3 +- gdb/testsuite/gdb.base/range-stepping.exp | 2 +- gdb/testsuite/gdb.base/sigint-masked-out.exp | 12 +- gdb/testsuite/gdb.base/sigint-sigwait.exp | 12 +- gdb/testsuite/gdb.gdb/selftest.exp | 4 +- gdb/testsuite/gdb.mi/new-ui-mi-sync.exp | 2 +- .../gdb.multi/multi-target-interrupt.exp | 2 +- .../gdb.multi/multi-target-no-resumed.exp | 2 +- .../gdb.multi/multi-term-settings.exp | 2 +- gdb/testsuite/gdb.server/reconnect-ctrl-c.exp | 4 +- gdb/testsuite/gdb.threads/async.exp | 2 +- .../gdb.threads/continue-pending-status.exp | 2 +- gdb/testsuite/gdb.threads/leader-exit.exp | 2 +- gdb/testsuite/gdb.threads/manythreads.exp | 4 +- gdb/testsuite/gdb.threads/pthreads.exp | 2 +- gdb/testsuite/gdb.threads/schedlock.exp | 11 +- gdb/testsuite/gdb.threads/sigthread.exp | 2 +- gdb/testsuite/lib/gdb.exp | 19 +++ 29 files changed, 315 insertions(+), 57 deletions(-) diff --git a/gdb/event-top.c b/gdb/event-top.c index 002a7dc95e0..9741b23576a 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -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 (); + } } } diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 99ce0ec78fa..72051bdc095 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -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 (); } diff --git a/gdb/infrun.c b/gdb/infrun.c index 3f40fa39b5a..f3f24839f32 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -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 (¤t_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); } diff --git a/gdb/infrun.h b/gdb/infrun.h index 5d791bdc5b4..64fdfc7ab60 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -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; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index d31bcd98e84..a40b3c30012 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -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); diff --git a/gdb/target.c b/gdb/target.c index 68d7e7c12d7..ab4dc7bd5dd 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -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 ()) diff --git a/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp b/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp index d21f580af87..e7e7a4c43a6 100644 --- a/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp +++ b/gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp @@ -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" diff --git a/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp b/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp index e43bfe4f4ad..840bbec2dc1 100644 --- a/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp +++ b/gdb/testsuite/gdb.base/interrupt-daemon-attach.exp @@ -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" diff --git a/gdb/testsuite/gdb.base/interrupt-daemon.exp b/gdb/testsuite/gdb.base/interrupt-daemon.exp index 2270ab0cbc2..0b0b6dc3e80 100644 --- a/gdb/testsuite/gdb.base/interrupt-daemon.exp +++ b/gdb/testsuite/gdb.base/interrupt-daemon.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.base/interrupt-noterm.exp b/gdb/testsuite/gdb.base/interrupt-noterm.exp index 5cfc6171dd4..089b43305fe 100644 --- a/gdb/testsuite/gdb.base/interrupt-noterm.exp +++ b/gdb/testsuite/gdb.base/interrupt-noterm.exp @@ -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 diff --git a/gdb/testsuite/gdb.base/interrupt.exp b/gdb/testsuite/gdb.base/interrupt.exp index 41788ccade2..30ca6d44285 100644 --- a/gdb/testsuite/gdb.base/interrupt.exp +++ b/gdb/testsuite/gdb.base/interrupt.exp @@ -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" } } diff --git a/gdb/testsuite/gdb.base/random-signal.exp b/gdb/testsuite/gdb.base/random-signal.exp index 8511e83fce5..4c8806ce367 100644 --- a/gdb/testsuite/gdb.base/random-signal.exp +++ b/gdb/testsuite/gdb.base/random-signal.exp @@ -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 diff --git a/gdb/testsuite/gdb.base/range-stepping.exp b/gdb/testsuite/gdb.base/range-stepping.exp index c1ba8ef71cb..21bd7326370 100644 --- a/gdb/testsuite/gdb.base/range-stepping.exp +++ b/gdb/testsuite/gdb.base/range-stepping.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.base/sigint-masked-out.exp b/gdb/testsuite/gdb.base/sigint-masked-out.exp index 0391152e93a..77a599d12ef 100644 --- a/gdb/testsuite/gdb.base/sigint-masked-out.exp +++ b/gdb/testsuite/gdb.base/sigint-masked-out.exp @@ -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)" } } diff --git a/gdb/testsuite/gdb.base/sigint-sigwait.exp b/gdb/testsuite/gdb.base/sigint-sigwait.exp index 1dd706fc1a4..e37a2d2cbef 100644 --- a/gdb/testsuite/gdb.base/sigint-sigwait.exp +++ b/gdb/testsuite/gdb.base/sigint-sigwait.exp @@ -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)" } } diff --git a/gdb/testsuite/gdb.gdb/selftest.exp b/gdb/testsuite/gdb.gdb/selftest.exp index bee3010bca1..7679131b8e7 100644 --- a/gdb/testsuite/gdb.gdb/selftest.exp +++ b/gdb/testsuite/gdb.gdb/selftest.exp @@ -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 $" { diff --git a/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp b/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp index 887bd60abcd..8eadc2f6f22 100644 --- a/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp +++ b/gdb/testsuite/gdb.mi/new-ui-mi-sync.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.multi/multi-target-interrupt.exp b/gdb/testsuite/gdb.multi/multi-target-interrupt.exp index cafd60d31b1..36b47a40c1a 100644 --- a/gdb/testsuite/gdb.multi/multi-target-interrupt.exp +++ b/gdb/testsuite/gdb.multi/multi-target-interrupt.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp b/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp index 6e84d9a6949..0ce26f28199 100644 --- a/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp +++ b/gdb/testsuite/gdb.multi/multi-target-no-resumed.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.multi/multi-term-settings.exp b/gdb/testsuite/gdb.multi/multi-term-settings.exp index 5275391a73c..7796d508083 100644 --- a/gdb/testsuite/gdb.multi/multi-term-settings.exp +++ b/gdb/testsuite/gdb.multi/multi-term-settings.exp @@ -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. diff --git a/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp b/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp index 11aa5147c78..2121c47e873 100644 --- a/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp +++ b/gdb/testsuite/gdb.server/reconnect-ctrl-c.exp @@ -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" { diff --git a/gdb/testsuite/gdb.threads/async.exp b/gdb/testsuite/gdb.threads/async.exp index c49deb1f8b5..f7be1271b7b 100644 --- a/gdb/testsuite/gdb.threads/async.exp +++ b/gdb/testsuite/gdb.threads/async.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.threads/continue-pending-status.exp b/gdb/testsuite/gdb.threads/continue-pending-status.exp index c0321c39d11..ca82290e260 100644 --- a/gdb/testsuite/gdb.threads/continue-pending-status.exp +++ b/gdb/testsuite/gdb.threads/continue-pending-status.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.threads/leader-exit.exp b/gdb/testsuite/gdb.threads/leader-exit.exp index fe06e6d4f29..fb76bba3e3b 100644 --- a/gdb/testsuite/gdb.threads/leader-exit.exp +++ b/gdb/testsuite/gdb.threads/leader-exit.exp @@ -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 } } diff --git a/gdb/testsuite/gdb.threads/manythreads.exp b/gdb/testsuite/gdb.threads/manythreads.exp index b0004b912b7..992c46a3874 100644 --- a/gdb/testsuite/gdb.threads/manythreads.exp +++ b/gdb/testsuite/gdb.threads/manythreads.exp @@ -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 $" { diff --git a/gdb/testsuite/gdb.threads/pthreads.exp b/gdb/testsuite/gdb.threads/pthreads.exp index 86258b1d874..4bf8544db52 100644 --- a/gdb/testsuite/gdb.threads/pthreads.exp +++ b/gdb/testsuite/gdb.threads/pthreads.exp @@ -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 $" { diff --git a/gdb/testsuite/gdb.threads/schedlock.exp b/gdb/testsuite/gdb.threads/schedlock.exp index 90c70587220..ab25c3d0388 100644 --- a/gdb/testsuite/gdb.threads/schedlock.exp +++ b/gdb/testsuite/gdb.threads/schedlock.exp @@ -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 } } } diff --git a/gdb/testsuite/gdb.threads/sigthread.exp b/gdb/testsuite/gdb.threads/sigthread.exp index 867aef9a710..43f39406380 100644 --- a/gdb/testsuite/gdb.threads/sigthread.exp +++ b/gdb/testsuite/gdb.threads/sigthread.exp @@ -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" diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index d8c684c7238..5aeebb3704b 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -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 {} { -- 2.26.2