Does int 3 interrupt execute the whole process on Linux or only the current thread?

Assume x86 architecture. And the OS is based on Linux. Given a multi-threaded process in which one thread executes an int 3 instruction, does the interrupt handler stop executing the entire process, or only a thread executing an int 3 instruction?

+6
source share
4 answers

Since the question is specific to Linux, let me dive into the kernel source! We know that int 3 will generate SIGTRAP, as we can see in do_int3 . The default behavior of SIGTRAP is to terminate the process and core dump.

do_int3 calls do_trap , which, after a multi-sided call, calls complete_signal , where most of the magic happens. Following the comments, it’s very clear to see what happens without much explanation:

  • A stream was found to signal. The main thread receives the first crack, but any thread can receive it, unless it is clearly indicated that it does not want to.
  • SIGTRAP is fatal (and we assumed that we wanted to establish what this default behavior was) and should reset the kernel, so it is fatal for the whole group.
  • The loop on line 1003 wakes up all the streams and transmits a signal.

EDIT . To reply to a comment:

When a process has a ptrace d value, the behavior is pretty well described on the page (see Signal-Delivery-Stop). In principle, after the kernel selects an arbitrary thread that processes the signal, if the selected thread is monitored, it enters a signal transmission-stop - this means that the signal is not yet delivered to the process and can be suppressed by the trace process. This applies to the debugger : we don’t need a dead process when debugging (this is not entirely true, but consider the live-debugging script, which is the only thing that makes sense in this context), so by default we block SIGTRAP, unless the user specifies otherwise. In this case, it does not matter how the monitored process processes SIGTRAP (SIG_IGN or SIG_DFL or the user-defined handler) because it will never know that this happened.

Please note that in the case of SIGTRAP, the trace process must take into account different scenarios other than the stopped process, as well as on the manual page under each ptrace action.

+9
source

Easy enough to check:

 #include <thread> #include <vector> void f(int v) { std::this_thread::sleep_for(std::chrono::seconds(2)); if (v == 2) asm("int $3"); std::this_thread::sleep_for(std::chrono::seconds(1)); printf("%d\n", v); // no sync here to keep it simple } int main() { std::vector<std::thread> threads; for (int i = 0; i < 4; i++) threads.emplace_back(f, i); for (auto& thread : threads) thread.join(); return 0; } 

If only the thread was stopped, it should still print the message from threads other than 2, but this is not the case, and the whole process stops before printing anything (or starts a breakpoint when debugging). On Ubuntu you will get a message:

Trace / interrupt trap (flushing kernel)

+7
source

The answer is actually not so. Int 3 is used to start a breakpoint. The interrupt handler is tiny, and neither the interrupt nor its handler stops any threads.

If the debugger is not loaded, the handler will either ignore it or call the operating system to take some action with an error, for example, raising a signal (possibly SIGTRAP). Not a single thread is damaged.

If there is a debugger in the process, the ISR breakpoint transfers control to it. A breakpoint does not stop a thread except one that breaks. The debugger may try to pause others.

If there is a debugger outside the process, the handler will call it, but it must be mediated through the OS to make a suitable context switch. As part of this switch, the OS suspends debuggee, which means that all its threads will stop.

+1
source

int 3 is a privileged instruction to prevent user space code from starting.

The kernel will then send the SIGTRAP signal to your process, and the default action for the SIGTRAP signal is to terminate the entire process.

+1
source

All Articles