Search code examples
gdbsignalsbreakpoints

How to step without passing signal to application?


Suppose a process run under GDB stops due to receiving a signal, e.g. SIGSEGV due to access to an invalid location. I then fix the location (by writing to a register or in any other way) and want to single-step, retrying the faulting instruction.

There is a command stepi, which would work if the signal were ignored or hadn't been received in the first place. But since there's a signal pending, I can't use it, at least directly. If I use signal 0 command, it will ignore the signal, but then it works as continue. Thus, if I use signal 0, I have to find out where the next instruction starts, add a tb on it etc.. This is unhandy.

Another way would be like handle SIGSEGV ignore followed by stepi followed by another handle command to restore its original state. Also unhandy: can't even define a "black box" function for this, since original state of signal handling may be non-default, and it'll have trouble restoring it after si.

So, is there any simple way to remove pending signal without continuing execution?


Solution

  • In gdb version 7.9 and later, there is a queue-signal command that will let you send a signal (or no signal at all, if you give it 0 as an argument) the next time the target is resumed. Here's some of the documentation:

    Queue signal to be delivered immediately to the current thread when execution of the thread resumes. The signal can be the name or the number of a signal. The handling of the signal must be set to pass the signal to the program, otherwise GDB will report an error. You can control the handling of signals from GDB with the handle command.

    Alternatively, if signal is zero, any currently queued signal for the current thread is discarded and when execution resumes no signal will be delivered.

    This command differs from the signal command in that the signal is just queued, execution is not resumed. And queue-signal cannot be used to pass a signal whose handling state has been set to nopass.