I'm trying to debug a program that often causes GDB to stop and display SIGTRAP when it is not at a breakpoint. It happens when loading dynamic libraries and other ordinary stuff. There are like 1,000 of these occurring before my breakpoint is finally hit, so it's non-feasible for me to manually "continue" all these irrelevant SIGTRAPs. But if I use the command handle SIGTRAP nostop noprint
, then GDB will not stop at my breakpoint.
It seems like there must be a way to educate GDB so that it understands which SIGTRAP is good for stopping, and which is no good for stopping. Clearly GDB knows whether it is at a breakpoint, because the output is very reliably different: at a breakpoint, it mentions "breakpoint" and shows the breakpoint number--but at any other SIGTRAP, it just says "SIGTRAP". So instead of printing the message about a SIGTRAP, I'd really like GDB to just say to itself, "wow, this is a SIGTRAP and there is no breakpoint here--look at me, I'm about to stop and print a useless SIGTRAP message that completely ruins the debug session! How about I just continue quietly?" Please let me know if someone has a way to do this.
You can set catchpoints to catch the SIGTRAP signal and add commands to decide whether to continue or to stop. In this handler, you can inspect convenience variables such as $_siginfo
for the reason for the signal.
Of particular interest is $_siginfo.si_code
, its value depends on the signal that is delivered. The sigaction(2) Linux manual page describes the exact relations. You can find the numeric values for those SI_USER
, SI_KERNEL
, etc. codes by compiling a program or looking in headers (on my system it uses the header /usr/include/bits/siginfo.h
). Some values I have encountered are:
SI_USER
SI_KERNEL
TRAP_TRACE
With this information in hand, here is an example that catches SIGTRAP and prints the reason, then continues:
catch signal SIGTRAP
commands
p $_siginfo.si_code
c
end
# Set another breakpoint for testing
break sleep
Now consider this test program that sleeps 5 seconds, then triggers a debug trap on x86(-64):
#include <unistd.h>
int main(void) {
for (;;) {
sleep(5);
asm("int3");
}
return 0;
}
This program keeps stopping gdb
at the int3
line because the signal is caught (si_code
happens to be 0x80, SI_KERNEL
), but then the instruction is repeated again. So to skip this instruction, the program counter ($pc
) must be incremented. After doing so, I learned this information about SIGTRAP
and si_code
:
SI_KERNEL
).TRAP_TRACE
) is received (because of the catchpoint for SIGTRAP
).int3
instruction triggers SIGTRAP with code 128. Thus you needs something to differentiate the instructions.Here are the final GDB commands that skip the int3
traps and still keep the breakpoints functional:
catch signal SIGTRAP
commands
silent # do not print catchpoint hits
# ignore the int3 instruction (this address was looked up at
# the tracepoint using print $pc)
if $pc == 0x400568
set $pc++ # skip int3
c
end
# Ignore TRAP_TRACE that is used for breakpoints
if $_siginfo.si_code == 2
c
end
end
A final note: SIGTRAP is used internally by the debugger, it is possible that the above catches too much. This was tested with GDB 7.10 on Arch Linux.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With