If a process is currently stopped due to a SIGTRAP signal and it is sent a SIGSTOP signal via kill(), what would be the default behavior? Would the SIGSTOP be a pending signal that is delivered after the process continues again? Or will it just be discarded/ignored?
If the SIGSTOP is queued up, is there any way to remove it from the queue from outside of that process, such as in a tracing process?
From the signal(7) man page:
The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
A simple test with an app stopped on a breakpoint and sending it a SIGSTOP shows gdb displaying some information when I hit 'next'. The signal was obviously delivered to the app. It cannot continue to be debugged until I send it a SIGCONT.
(gdb) next
Program received signal SIGSTOP, Stopped (signal).
fill (arr=0x7fffffffdff0, size=5) at tmp.cpp:28
(gdb) next
Program received signal SIGCONT, Continued.
fill (arr=0x7fffffffdff0, size=5) at tmp.cpp:28
(gdb) next
(gdb)
What do you mean 'stopped due to a SIGTRAP signal'? A SIGTRAP will not stop a process; by default it will terminate with a core dump, or you can change it to ignore the signal or call a signal handler, but in no case will the SIGTRAP stop the process by itself. You might have the process being traced by some other process (such as a debugger) with ptrace(2), in which case it will stop just before delivering the SIGTRAP, but in that case its under the control of the ptrace and won't continue until there's a PTRACE_CONT or other ptrace action to continue the process.
Related
I'm reading about signals and I read that a signal that has been sent but not received is considered pending. Additionally, control jumps to a handler whenever a OS does a context switch to some process and discovers a pending and unblocked signal.
When is the bit for a signal in the pending bitmask cleared? Is it only when the handler finishes processing the signal? Or is it cleared the moment control jumps to the beginning of the handler?
I'm curious because I'm not sure what happens if for example, a SIGINT signal arrived while a SIGINT handler was already processing the signal and chose not to block further SIGINT signals. (I read that by default, signal handlers for signal K will block signal K by default but I'm wondering what happens if it is unblocked)
I'm currently learning how signals really works in POSIX-systems. Signals such as SIGTERM can be caught and handled with custom handlers, this means that the kernel propagates the signal to the process itself. On the other hand SIGKILL is not catchable and cannot be handled firstly because it is its main purpose - kill the process. But I'm wondering does this means that the SIGKILL is not even propagated to the process ? I mean if the users will send kill -9 to some process using terminal the kernel will immediately purge that process without even forwarding the signal to it, or the signal will still be forwarded to the process but with the exception that we cannot add a custom handler to it? Sorry, if you consider this question dummy! I'm just starting with POSIX systems
some signals can catch and we name those catchable signals and some are uncatchable. The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
You can see a complete list of signals and appropriate action here.
When I want to inspect tracee syscall I use PTRACE_ATTACH , then PTRACE_SYSCALL in loop , and finally PTRACE_DETACH .
The problem is that if the tracee registered to SIGTRAP or SIGCONT it can change his behaviour while I use PTRACE_SYSCALL or PTRACE_DETACH and I don't want to do it.
When I attach to tracee with PTRACE_ATTACH tracee got SIGSTOP but it can't register/reaction to this signal, so that it fine.
What is the solution that the tracee could not catch SIGTRAP when I use PTRACE_SYSCALL or SIGCONT when I used PTRACE_CONT
The tracer always gets first dibs at signal handling, and it can choose to suppress the signal so that the tracee's handler doesn't run. The only thing you have to worry about is if the tracee blocks the signal with something like sigprocmask or a blocking call to pselect and uses something like sigpending or signalfd to look for it, which you could fix by modifying or emulating the relevant syscalls.
To suppress a signal, just pass 0 for sig when resuming after signal-delivery-stop. From man 2 ptrace:
Signal injection and suppression
After signal-delivery-stop is observed by the tracer, the tracer should restart the tracee with the call
ptrace(PTRACE_restart, pid, 0, sig)
where PTRACE_restart is one of the restarting ptrace requests. If sig is 0, then a signal is not delivered. Otherwise, the signal sig is delivered. This operation is called signal injection in this manual page, to distinguish it from signal-delivery-stop.
Come to think of it, I guess the signal is sent to the OS and the program will proceed, even if the signal is still pending on the OS side. Can someone confirm?
kill(this_process, signum);
printf("will line this run in any reality of the multi-verse?");
printf("or should I go to sleep?");
sleep(10);
From the POSIX specification of kill()
If the value of pid causes sig to be generated for the sending process, and if sig is not blocked for the calling thread and if no other thread has sig unblocked or is waiting in a sigwait() function for sig, either sig or at least one pending unblocked signal shall be delivered to the sending thread before kill() returns.
So if there are no other signals pending for the process when you call kill(), the signal you send has to be delivered immediately. But if there are other signals pending, this signal could be queued and an earlier signal delivered immediately.
When I was googling my gdb and sigwait issue, I found this kernel bug thread
GDB is not trapping SIGINT. Ctrl+C terminates program when should break gdb.
Quote:
gdb puts the debugged process in its own pgrp and sets the terminal to that pgrp.
When you hit C-c, the signal goes to the current pgrp, i.e. to the debugged process and not to gdb. When a signal is delivered, ptrace will intercept it and let gdb decide what to do before it actually reaches the debugged process.
However, your program uses sigwait and so the signal is never actually delivered. Instead, you dequeue it via sigwait without going through actual signal delivery. ptrace only reports a signal that is about to be delivered. When you use sigwait, technically the signal is blocked the whole time and never delivered as such.
This comment got me more curious about how signal and GDB actually works,
1) What is the difference between "signal delivered" and "signal queued"?
2) How does GDB trap signals while the signal is sent to the debugged process?
Thanks,