Bug 18772 - gdb does not respond to CTRL-C
Summary: gdb does not respond to CTRL-C
Status: REOPENED
Alias: None
Product: gdb
Classification: Unclassified
Component: remote (show other bugs)
Version: 7.9
: P2 critical
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-08-05 11:32 UTC by Lee Moore
Modified: 2023-03-21 14:58 UTC (History)
15 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
A reproducer for this issue (332 bytes, text/x-csrc)
2022-04-26 14:59 UTC, Andrew Burgess
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Lee Moore 2015-08-05 11:32:39 UTC
Hi Support,

it looks like a bug has been introduced, somewhere between 7.5 & 7.9.
I do not have all the intermediate builds available to narrow this down.

I have a very simple testcase, running on Fedora Linux, but appears to be a general issue I even reproduced on an ARM target.

1: #include <stdio.h>
2: int main() {
3:     int cond = 0;
4:     while(cond == 0) { /* do nothing  */ } // BREAK at this line
5:     return 0;
6: }

compile for debug
$ gcc -g -o app.exe app.c

run the application in gdbserver
$ gdbserver localhost:9999 app.exe

in gdb do the following
$ gdb app.exe
(gdb) target remote localhost:9999
(gdb) b app.c:4
(gdb) continue
(gdb) next

so now gdb is trying to run to the 'next' line, which it cannot reach because the condition in the while loop is always true, so interrupt by sending CTRL-C
(gdb) ^C

nothing happens

The session is now locked up, if you issue another CTRL-C, the gdb client will Quit
(gdb)^CQuit

The gdbserver is still running, but I have failed to interrupt

Try the same with gdb version 7.5 and it works

Thx
Lee
Comment 1 Massimo B. 2017-02-23 10:41:05 UTC
This is 7.12.1 server and client.
Having no breakpoints it is not possible to pause execution by CTRL+c at all, as it is done using the native gdb:


server $ gdbserver --multi --attach localhost:8888 $(pgrep -f my_app)

client $ gdb
target extended-remote localhost:8888
Remote debugging using localhost:8888
Reading /lib64/libdl.so.2 from remote target...
Reading /lib64/libSegFault.so from remote target...
...
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
0x00007f6b26857923 in __select_nocancel () from target:/lib64/libc.so.6
(gdb) where
#0  0x00007f6b26857923 in __select_nocancel () from target:/lib64/libc.so.6
...
#9  0x00000000004497ee in main (argc=14, argv=0x7ffe8e4b0af8) at main.cpp:245

(gdb) c
Continuing.

^C^CThe target is not responding to interrupt requests.
Stop debugging it? (y or n) y
Disconnected from target.
Comment 2 jon 2019-02-07 10:56:06 UTC
This appears to still be a problem in gdb 8. It also seems to be a problem for sim targets. (Sometimes CTRL-C can break a windows sim target, but never on Linux).

Note that CTRL-C only seems to be ignored for the 'next' or 'step' commands. If you 'continue' instead of 'next', then CTRL-C seems to work for me:

(gdb) run
Starting program: test.exe 
^C
Program received signal SIGINT, Interrupt.
0x000000bc in main () at test.c:6
6	  while(!x)
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x000000bc in main () at test.c:6
6	  while(!x)
(gdb) n
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
Comment 3 Eugene 2019-04-10 13:33:25 UTC
Looks like this is triggered by https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commit;h=78708b7c8ccc2138880217de9bd60eceff683f10

following change worked for me:

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 94af240..2e5776f 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5936,7 +5936,9 @@ linux_request_interrupt (void)
 {
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  */
-  kill (-signal_pid, SIGINT);
+  int r = kill (-signal_pid, SIGINT);
+  if (r != 0)
+      kill (signal_pid, SIGINT);
 }
 
 /* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
Comment 4 Massimo B. 2020-04-20 08:55:51 UTC
Any progress here? Is the proposed patch a reasonable solution and will be integrated?
Comment 5 rarul 2020-10-10 15:49:42 UTC
I don't think the proposed patch is good,
for it is wrong to send SIGINT to the pocess group.
See this ticket. Josh suggested the right approach.
https://sourceware.org/bugzilla/show_bug.cgi?id=18945

I'm not sure why this bug is not fixed yet.
In Yocto project case, they decided to apply the patch.
https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/recipes-devtools/gdb/gdb/0011-gdbserver-ctrl-c-handling.patch
There're no active gdbserver maintainers?
Comment 6 Matic Kres 2020-10-12 06:15:09 UTC
Agree with rarul, sending interrupt to group process is not a good choice.
My post about it:
https://sourceware.org/bugzilla/show_bug.cgi?id=26575
Comment 7 Andrew Burgess 2022-04-16 14:02:12 UTC
I tried to reproduce this issue with GDB 8.2 and 11.2 on x86-64 GNU/Linux using Fedora 31, using the test program from the original comment.

I can't see any problems interrupting GDB using Ctrl-C.  I tested this using 'continue', 'next', and 'step' commands, and in all cases GDB interrupts as expected (i.e. comes to a stop).

If any of the original bug reporters are still seeing this issue with a recent version of GDB, then please do follow up and we can reopen this bug, but for no I propose that we close this issue.
Comment 8 Lee Moore 2022-04-19 10:26:01 UTC
wow I logged this 7 years ago!
I tried this with gdbserver/gdb 8.1, the problem no longer occurs

no idea at what point it got fixed
Comment 9 Rich Surgenor 2022-04-24 22:08:22 UTC
(In reply to Lee Moore from comment #8)
> wow I logged this 7 years ago!
> I tried this with gdbserver/gdb 8.1, the problem no longer occurs
> 
> no idea at what point it got fixed

This issue still happened to me on an ARMv7 target from a x86_64 host. Adding the patch that sends kill to just the process when sending to the process group fails worked instantly fixed the problem.

This is with gdbserver 10.2 and gdb 9.2
Comment 10 Rich Surgenor 2022-04-24 22:27:39 UTC
(In reply to Andrew Burgess from comment #7)
> I tried to reproduce this issue with GDB 8.2 and 11.2 on x86-64 GNU/Linux
> using Fedora 31, using the test program from the original comment.
> 
> I can't see any problems interrupting GDB using Ctrl-C.  I tested this using
> 'continue', 'next', and 'step' commands, and in all cases GDB interrupts as
> expected (i.e. comes to a stop).
> 
> If any of the original bug reporters are still seeing this issue with a
> recent version of GDB, then please do follow up and we can reopen this bug,
> but for no I propose that we close this issue.

Did you confirm that the pgid was != to the pid in your testing? In my case, the pgid did not match the pgid or pid of any processes, resulting in the signal not getting sent anywhere.
Comment 11 Andrew Burgess 2022-04-25 13:22:31 UTC
(In reply to Rich Surgenor from comment #10)

> Did you confirm that the pgid was != to the pid in your testing? In my case,
> the pgid did not match the pgid or pid of any processes, resulting in the
> signal not getting sent anywhere.

OK, that's pretty interesting.  So I guess you started debugging some process that forks, you follow the fork, then you place the child into a different process group?

Or am I overthinking this?

I'll try to craft a test that matches your description above later this week, but any further hints you have about the nature of the failing situation would be great.  

I'm reopening this issue for now.
Comment 12 Andrew Burgess 2022-04-26 14:59:19 UTC
Created attachment 14082 [details]
A reproducer for this issue

The attached file sig-c-bug.c is a reproducer for this issue.  The bug impacts not just remote targets, but also native Linux targets too as of commit 2b718529b99.

Compile up the attached file as:

  gcc -g3 -O0 -Wall -Wextra -Werror  -o sig-c-bug.x sig-c-bug.c

Then run the test as:

  ./gdb/gdb --data-directory ./gdb/data-directory/ \
     ~/tmp/sig-c-bug.x \
     -q \
     -ex 'set detach-on-fork off' \
     -ex 'set follow-fork-mode parent' \
     -ex 'run' \
     -ex 'info inferiors' \
     -ex 'inferior 2' \
     -ex 'continue'

You should end up with inferior 2 running, every second you'll see a new line of this output:

  Tick: 0
  Tick: 1
  Tick: 2
  Tick: 3
  Tick: 4
  ... and so on ...

try to interrupt gdb using ctrl-c ... it doesn't work for me.

Inferior 2 will automatically exit after 'Tick: 9', at which point you need to restart the test.

The same behaviour can be seen when using a remote target, just start gdbserver something like:

  gdbserver --multi :54321 sig-c-bug.x

and then:

  ./gdb/gdb --data-directory ./gdb/data-directory/ \
     ~/tmp/sig-c-bug.x \
     -q \
     -ex 'set sysroot /' \
     -ex 'set detach-on-fork off' \
     -ex 'set follow-fork-mode parent' \
     -ex 'target extended-remote :54321' \
     -ex 'continue' \
     -ex 'info inferiors' \
     -ex 'inferior 2' \
     -ex 'continue'

and the remote target will be ticking in inferior 2, and can't be interrupted.
Comment 13 Pedro Alves 2022-06-22 16:42:33 UTC
Once I'm done with my current priorities, my next project will be going back to this:

 [PATCH v2 00/16] Interrupting programs that block/ignore SIGINT
 https://pi.simark.ca/gdb-patches/20210614212410.1612666-1-pedro@palves.net/

That redesigns how SIGINT is handled when native debugging, such that GDB _always_ gets the SIGINT first instead of relying on the inferior getting it, so I suspect it will fix Andrew's testcase when native debugging (though I haven't tried it).  As for remote debugging with gdbserver, I will take a look at it too, once I resume work on that series.
Comment 14 Disconnect3d 2022-08-14 21:25:58 UTC
(In reply to Pedro Alves from comment #13)
> Once I'm done with my current priorities, my next project will be going back
> to this:
> 
>  [PATCH v2 00/16] Interrupting programs that block/ignore SIGINT
>  https://pi.simark.ca/gdb-patches/20210614212410.1612666-1-pedro@palves.net/
> 
> That redesigns how SIGINT is handled when native debugging, such that GDB
> _always_ gets the SIGINT first instead of relying on the inferior getting
> it, so I suspect it will fix Andrew's testcase when native debugging (though
> I haven't tried it).  As for remote debugging with gdbserver, I will take a
> look at it too, once I resume work on that series.

Hey,

Any progress on it?

I just stumbled on it when debugging an AARCH64 target [0] run via QEMU user emulation [1]. I wonder if that it is a bug in the QEMU user emulation layer here or if comes from GDB?

[0] https://github.com/perfectblue/ctf-writeups/tree/master/2019/insomnihack-teaser-2019/nyanc/challenge
[1] Via command `qemu-aarch64 -g 1234 ./nyanc`, but I first used patchelf to set interpreter and libc:
```
patchelf --set-interpreter ./ld-linux-aarch64.so.1 ./nyanc 
patchelf --replace-needed libc.so.6 ./libc.so.6 ./nyanc 
```
Comment 15 Filip Bascarevic 2022-08-30 08:40:34 UTC
(In reply to Pedro Alves from comment #13)
> Once I'm done with my current priorities, my next project will be going back
> to this:
> 
>  [PATCH v2 00/16] Interrupting programs that block/ignore SIGINT
>  https://pi.simark.ca/gdb-patches/20210614212410.1612666-1-pedro@palves.net/
> 
> That redesigns how SIGINT is handled when native debugging, such that GDB
> _always_ gets the SIGINT first instead of relying on the inferior getting
> it, so I suspect it will fix Andrew's testcase when native debugging (though
> I haven't tried it).  As for remote debugging with gdbserver, I will take a
> look at it too, once I resume work on that series.

Hello community,

it seems this patch also broke Eclipse Suspend functionality during debugging. I think the Eclipse also sends CTRL-C when the user presses Suspend button. I noticed it from the GDB release 11.1 (10.2 works). 
Used remote debugging of the Qemu target Aarch64 with Eclipse in Windows. 
Feel free to contact me for any support or additional information

Best regards, 
Filip Bascarevic
Comment 16 Sourceware Commits 2022-11-27 09:31:56 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4c35c4c6a779c79e456b7a5311f74aafc9026bd5

commit 4c35c4c6a779c79e456b7a5311f74aafc9026bd5
Author: Tom de Vries <tdevries@suse.de>
Date:   Sun Nov 27 10:31:50 2022 +0100

    [gdb/server] Emit warning for SIGINT failure
    
    Consider the executable from test-case gdb.base/interrupt-daemon.exp.
    
    When starting it using gdbserver:
    ...
    $ ./build/gdbserver/gdbserver localhost:2345 \
      ./outputs/gdb.base/interrupt-daemon/interrupt-daemon
    ...
    and connecting to it using gdb:
    ...
    $ gdb -q -ex "target remote localhost:2345" \
        -ex "set follow-fork-mode child" \
        -ex "break daemon_main" -ex cont
    ...
    we are setup to do the same as in the test-case: interrupt a running inferior
    using ^C.
    
    So let's try:
    ...
    (gdb) continue
    Continuing.
    ^C
    ...
    After pressing ^C, nothing happens.  This a known problem, filed as
    PR remote/18772.
    
    The problem is that in linux_process_target::request_interrupt, a kill is used
    to send a SIGINT, but it fails.  And it fails silently.
    
    Make the failure verbose by adding a warning, such that the gdbserver output
    becomes more helpful:
    ...
    Process interrupt-daemon created; pid = 15068
    Listening on port 2345
    Remote debugging from host ::1, port 35148
    Detaching from process 15068
    Detaching from process 15085
    gdbserver: Sending SIGINT to process group of pid 15068 failed: \
      No such process
    ...
    
    Note that the failure can easily be reproduced using the test-case and target
    board native-gdbserver:
    ...
    (gdb) continue^M
    Continuing.^M
    PASS: gdb.base/interrupt-daemon.exp: fg: continue
    ^CFAIL: gdb.base/interrupt-daemon.exp: fg: ctrl-c stops process (timeout)
    ...
    as reported in PR server/23382.
    
    Tested on x86_64-linux.
    Approved-By: Simon Marchi <simon.marchi@efficios.com>
Comment 17 Eldar Abusalimov 2023-03-20 15:53:22 UTC
There's one more thing why the naive `kill (-signal_pid, SIGINT);` is wrong.

In case the target PID is 1, it calls `kill` passing -1 to it, which has a special meaning (quoting https://man7.org/linux/man-pages/man2/kill.2.html#DESCRIPTION):

       If pid equals -1, then sig is sent to every process for which the
       calling process has permission to send signals, except for
       process 1 (init), but see below.

That is, it attempts to interrupt any process other than the one it is supposed to!

Debugging PID 1 may sound an edge case, but it is actually perfectly fine to do so in case of a sole process running inside a Docker container. In other words, it's not necessarily even the init process, like systemd or upstart, it's often a legit regular program that you develop yourself.
Comment 18 Tom Tromey 2023-03-21 14:58:56 UTC
On Linux at least we could use PTRACE_INTERRUPT, see bug #15250.