19

I frequently work with PostgreSQL for debugging, and it uses SIGINT internally for some of its inter-backend signalling.

As a result when running certain backends under gdb execution tends to get interrupted a lot. One can use the signal command to make sure SIGINT is passed to the program and that it is not captured by gdb... but then gdb doesn't respond to control-C on the command line, since that sends SIGINT.

If you run:

handle SIGINT noprint nostop pass

gdb will complain

SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) y

Is there any way to get gdb to use a different interrupt signal? Or any alternative method that'd let me have gdb ignore SIGINT?

(This isn't an issue for most PostgreSQL backend debugging, but it's a pain with background workers and autovacuum).

Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
  • _Is there any way to get gdb to use a different interrupt signal?_ - The SIGINT is delivered from the system when the input driver sees control C in the buffer. In theory it would be possible to tell a program to treat some other signal the way it would treat SIGINT, but in practice I doubt gdb or anything else would do this because the value is not flexible from the operating system. – mah May 03 '16 at 01:15
  • Could you workaround it by configuring gdb to handle another signal with `stop nopass` (or `stop pass` if the program needs the signal) and send that signal to the program instead of using ctrl-c? – kaylum May 03 '16 at 01:55
  • Use e.g. `kill -USR1` from another terminal? – user253751 May 03 '16 at 02:32
  • @kaylum I could, but the problem is the stops. It sends a lot of SIGINTs, so debugging is constantly interrupted. – Craig Ringer May 03 '16 at 02:56
  • @immibis Yeah, good point. gdb will stop on any signal configured for `stop` handling. Pg also uses `SIGUSR1` heavily (sigh) but I could abuse `SIGSTOP` or similar. – Craig Ringer May 03 '16 at 02:57
  • @CraigRinger I meant the same thing as immibis. Just leave SIGINT as `nostop` and instead pick a different signal that the application either doesn't use or doesn't use as frequently for the purposes of interrupting gdb. – kaylum May 03 '16 at 03:10
  • Post an answer and I'll accept. Basically boils down to that there's no easy way to change the signal used for control-C interrupts, but you can just mask sigint and if you need a manual interrupt reconfigure a different signal and send with `kill`. – Craig Ringer May 03 '16 at 04:45

4 Answers4

32

Readers who end up on this page (as I did) with a slightly different variation of this problem, would perhaps be more interested in this question:

Debugging a segmentation fault when I do ctrl c

... and its answer, which is:

  • send SIGINT from inside gdb itself:

    (gdb) signal 2

(Normally I would post the link as a simple comment under the OP's question on this page, but since there are already 7 comments, comments are being hidden/buried.)

If you read all the details of the OP's question here, then it is obvious that my answer is not correct for OP.

However, my answer is correct for many situations that could be described by the same title: "Debugging a program that uses SIGINT with gdb"

pestophagous
  • 4,069
  • 3
  • 33
  • 42
11

On UNIX-like systems, you can distinguish a tty-initiated SIGINT from one sent by kill by looking at the si_pid element in the siginfo struct. If the pid is 0, it came from a tty.

So you could do something like this:

catch signal SIGINT
commands
  if $_siginfo._sifields._kill.si_pid == 0
    print "Received SIGINT from tty"
  else
    printf "Received SIGINT from %d; continuing\n", $_siginfo._sifields._kill.si_pid
    signal SIGINT
  end
end
Mark Plotnick
  • 9,598
  • 1
  • 24
  • 40
5

This part of gdb is a bit tricky, both due to its history and also due to the various modes of operation it supports.

One might think that running gdb in a separate terminal and only using attach would help it do the right thing, but I don't think it is that easy.

One way forward might be to only use async execution when debugging, and then use a command to interrupt the inferior. Something like:

(gdb) attach 5555
... attaches
(gdb) continue &
... lots of stuff happens
(gdb) interrupt -a

Depending on your version of gdb you might need to set target-async for this to work.

Tom Tromey
  • 21,507
  • 2
  • 45
  • 63
1

HOW TO MAKE GDB STOP ON ANOTHER SIGNAL THAN SIGINT: ===========================================

So if your problem is: You attach to the process with gdb -p and then gdb stops the process execution by itself and you can press bt, etc. Then you press continue and the execution is continued. Then you press Ctrl+C, but SIGINT comes to your process instead of breaking gdb.

Here it is explained why it is so: it turns out, that your program first "gets" the SIGINT actually, but then ptrace catches it and passes to gdb and it already decides what to do according to your info signal SIGINT. So if your program makes sigwaitinfo() on SIGINT or blocks SIGINT, you are in trouble.

So the solution is to use another signal to break gdb. Run handle SIGUSR1 nopass inside gdb after it breaks by itself at the first time. Then after you press continue, you should send SIGUSR1=10 to the debugged program (not to gdb process) by running kill -10 <debugged process> in another shell. And then gdb will catch it and breaks. This works of course only if your program does not do anything with SIGUSR1 obviously.

JenyaKh
  • 2,040
  • 17
  • 25