]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
GNU/Linux: Interrupt/Ctrl-C with SIGSTOP instead of SIGINT [PR gdb/9425, PR gdb/14559]
authorPedro Alves <pedro@palves.net>
Thu, 3 Jun 2021 18:39:19 +0000 (19:39 +0100)
committerPedro Alves <pedro@palves.net>
Mon, 14 Jun 2021 21:20:45 +0000 (22:20 +0100)
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

29 files changed:
gdb/event-top.c
gdb/infcmd.c
gdb/infrun.c
gdb/infrun.h
gdb/linux-nat.c
gdb/target.c
gdb/testsuite/gdb.base/bp-cmds-continue-ctrl-c.exp
gdb/testsuite/gdb.base/interrupt-daemon-attach.exp
gdb/testsuite/gdb.base/interrupt-daemon.exp
gdb/testsuite/gdb.base/interrupt-noterm.exp
gdb/testsuite/gdb.base/interrupt.exp
gdb/testsuite/gdb.base/random-signal.exp
gdb/testsuite/gdb.base/range-stepping.exp
gdb/testsuite/gdb.base/sigint-masked-out.exp
gdb/testsuite/gdb.base/sigint-sigwait.exp
gdb/testsuite/gdb.gdb/selftest.exp
gdb/testsuite/gdb.mi/new-ui-mi-sync.exp
gdb/testsuite/gdb.multi/multi-target-interrupt.exp
gdb/testsuite/gdb.multi/multi-target-no-resumed.exp
gdb/testsuite/gdb.multi/multi-term-settings.exp
gdb/testsuite/gdb.server/reconnect-ctrl-c.exp
gdb/testsuite/gdb.threads/async.exp
gdb/testsuite/gdb.threads/continue-pending-status.exp
gdb/testsuite/gdb.threads/leader-exit.exp
gdb/testsuite/gdb.threads/manythreads.exp
gdb/testsuite/gdb.threads/pthreads.exp
gdb/testsuite/gdb.threads/schedlock.exp
gdb/testsuite/gdb.threads/sigthread.exp
gdb/testsuite/lib/gdb.exp

index 002a7dc95e065c7425134b15507e76b45d193d85..9741b23576a94b6c1f0a5e80aef9cf80f0759c87 100644 (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 ();
+       }
     }
 }
 
index 99ce0ec78fafa19b5819d0a725163fedbc0bed49..72051bdc0957d3d723fc2d5d1f72d3e7a76b3d3c 100644 (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 ();
 }
index 3f40fa39b5a56e033b0a8140c5a2e994d29b0e17..f3f24839f326b4ed8259a11820d30614b9588600 100644 (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);
 }
 
index 5d791bdc5b4934006be6c6a667197fb65792d9cb..64fdfc7ab606ffa62e88e2c3cb2a143b5ca681d9 100644 (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;
index d31bcd98e845dbf76eee6be8cfe4ee58931d8078..a40b3c30012c01cd1bdfa48f392a316a8354a7e8 100644 (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);
index 68d7e7c12d75b4d3895decfdd190e6c0aed31baa..ab4dc7bd5dd4a4ebe11ac4e3418e569d044e0ee9 100644 (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 ())
index d21f580af8791b63535531d6e1bf1bef8ec97db7..e7e7a4c43a6b65475e0c385ec72fc1a0c5410e51 100644 (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"
 
index e43bfe4f4ad7529d10c8adbdee972ca0daff2846..840bbec2dc1def6381566cef0a17bce6ad25d736 100644 (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"
index 2270ab0cbc251d6de101eb6101385b1916c67e9e..0b0b6dc3e80d10a5886e29a66f81e789bf8250e1 100644 (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
            }
        }
index 5cfc6171dd40cd97a836a08074aedc1ff9db6e76..089b43305fe06a0fa90c77e9aada24184b9ea4e7 100644 (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
index 41788ccade2245719ddcfa7a38b785d10baaee6f..30ca6d442859d6d3d9baee5eeb5afdce0488b875 100644 (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"
                }
            }
index 8511e83fce5d82c6abf134a432b119e37e16fa9f..4c8806ce367dfac4a543e5643bb4500b4399aecd 100644 (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
index c1ba8ef71cb6ab9dd5e3349c2d8eebcd8fee5316..21bd7326370e3e83c74c0037364a09500281393a 100644 (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
            }
        }
index 0391152e93a69801a206cffd09dc8d539404d175..77a599d12ef71f222ba10df73e6e058cba3e27ac 100644 (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)"
        }
     }
index 1dd706fc1a465cc4e23cce9df85349b8b3fe6cc5..e37a2d2cbefff78d9b7faf5294aceae49d202d94 100644 (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)"
        }
     }
index bee3010bca1175dd8a8f79a883c7a0a5ca1d81c6..7679131b8e74ef3e1ad1a5f77b83adf54c5fb7a5 100644 (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 $" {
index 887bd60abcd170ae216218f8b4de9e59cbd409bd..8eadc2f6f228bbb42752374604deb04c863958f2 100644 (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
                    }
                }
index cafd60d31b14ea0ae1138e8aa16314cb5084171b..36b47a40c1a39bbdc3c30e82090e2116e252907c 100644 (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
            }
        }
index 6e84d9a69492bff867e93d9db705e1082d2ed059..0ce26f28199fd4c69918329279405efe6856610e 100644 (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
        }
     }
index 5275391a73c8d7d869abd5ee54f168d94378f8d0..7796d5080834ffa9f6f5b515e6230f805869cfc6 100644 (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.
index 11aa5147c78af41e62b5ca722d524b8a3346a8a9..2121c47e8738488cc944e90960197d60a6fb2930 100644 (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" {
index c49deb1f8b54ada2cca394807b375b1fae9aabcb..f7be1271b7b018fb0412690fd11867889286b9a4 100644 (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
                }
            }
index c0321c39d11c8ca7d1e5858a652a0c0be2e06b79..ca82290e2602be310a3f9aee8c8f606515575ff8 100644 (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
            }
        }
index fe06e6d4f295b8c84754e91973ebae5eb0895167..fb76bba3e3bf4705530d669d45bfce5ce2816404 100644 (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
     }
 }
index b0004b912b7b7bfdb1d6154acf853910246bcaee..992c46a38745c81d77a8724b0ded7f8606bbaa8b 100644 (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 $" {
index 86258b1d874f3c1f6bd8c487bbfa076a7b3a0041..4bf8544db529e2a14f19cf7e1180b0d45a49e60a 100644 (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 $" {
index 90c7058722022150a47515d2310da5585ffc60ba..ab25c3d038891ff9409e036ea9744e55e89ad073 100644 (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
       }
   }
 }
index 867aef9a7105f315be62e574117d434474edd263..43f394063807c4c188b3fd20718dc83546057bbf 100644 (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"
index d8c684c72389ca63e0adc198426c607acdff3e42..5aeebb3704bdce402b080828c92cb1888a8dff05 100644 (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 {} {