How gdb generally works
In a debugging session, when the debugger wants to set a breakpoint, it replaces an instruction by int3
When the trap instruction (
0xCC on x86) is executed, the processor notifies the OS.
On UNIX, the OS checks to see whether the process is being
ptraced by somebody.
- If no, the
SIGTRAPsignal is delivered to the application, which usually results in process being killed (but you can catch and handle the signal in the application).
- If there is a
ptraceer (usually a debugger), then the signal is not delivered to the application. Instead, debugger’s
waitis unblocked to notify the debugger that the inferior has changed state. The debugger then looks at where the inferior process stopped, discovers that it did so because of a breakpoints, and handles the situation as appropriate (let’s you examine the inferior, or resumes it if the breakpoint is conditional and current conditions don’t match, etc.)
When the target process is stopped, it could interrupt the system_call where target process/thread is waiting/running.
There is an unfortunate side effect when using GDB to debug multi-threaded programs.
If one thread stops for a breakpoint, or for some other reason, and another thread is blocked in a system call,
then the system call may return prematurely.
This is a consequence of the interaction between multiple threads and the signals that GDB uses to implement breakpoints and other events that stop execution.
To handle this problem, your program should check the return value of each system call and react appropriately. This is good programming style anyways.
For example, do not write code like this:
The call to
sleep will return early if a different thread stops at a breakpoint or for some other reason.
Instead, write this:
int unslept = 10; while (unslept > 0) unslept = sleep (unslept);
A system call is allowed to return early, so the system is still conforming to its specification. But GDB does cause your multi-threaded program to behave differently than it would without GDB.
Also, GDB uses internal breakpoints in the thread library to monitor certain events such as thread creation and thread destruction. When such an event happens, a system call in another thread may return prematurely, even though your program does not appear to stop.
GDB and sigwaitinfo
if we use sigwaitinfo to handle the signal in a thread, sigwaitinfo maybe interrupted ( return -1 ) when gdb ran step/next in another thread etc.
so we need to check sigwaitinfo() the while loop: