为什么当tracee收到SIGCONT时会出现SIGTRAP PTRACE_EVENT_STOP?
Why does a SIGTRAP PTRACE_EVENT_STOP occur when the tracee receives SIGCONT?
我正在使用 PTRACE_SEIZE
来跟踪子进程的执行,但我 运行 遇到了一个问题,其中非组停止 PTRACE_EVENT_STOP
(信号== SIGTRAP
) 当被跟踪者接收到 SIGCONT
时被发射。我似乎找不到任何可能表明发生这种情况的文档。根据我在 ptrace(2)
联机帮助页中收集到的内容,PTRACE_EVENT_STOP
仅在满足以下条件之一时才会出现:
- 跟踪器名为
ptrace(PTRACE_INTERRUPT, ...)
- 被跟踪者入群停止(信号为
SIGSTOP
、SIGTSTP
、SIGTTIN
或SIGTTOU
)
- tracee调用
fork
/vfork
/clone
并且tracer自动附加到新的process/thread
在下面的示例程序中,我得到一个带有信号 SIGTRAP
的 PTRACE_EVENT_STOP
,但它不符合这 3 个条件中的任何一个。当我 运行 程序时,我得到以下输出:
[Child] Raising SIGSTOP
Event for pid 29236: Tracee entered group-stop PTRACE_EVENT_STOP (signal: 19)
Event for pid 29236: Tracee entered non-group-stop PTRACE_EVENT_STOP (signal: 5)
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Tracee received signal (signal: 18)
Event for pid 29236: Tracee entered/exited syscall
[Child] Resumed from SIGSTOP
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Process exited
关于这个特定的 PTRACE_EVENT_STOP
是什么意思有什么想法吗?
示例程序:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
static void handle_events(pid_t pid_spec)
{
while (1) {
int status;
pid_t pid = waitpid(pid_spec, &status, __WALL);
printf("Event for pid %d: ", pid);
if (WIFEXITED(status)) {
printf("Process exited\n");
break;
} else if (WIFSIGNALED(status)) {
printf("Process killed by signal\n");
break;
} else if (WIFSTOPPED(status)) {
int ptrace_event = status >> 16;
int signal = WSTOPSIG(status);
switch (ptrace_event) {
case PTRACE_EVENT_STOP:
if (signal == SIGSTOP || signal == SIGTSTP
|| signal == SIGTTIN || signal == SIGTTOU) {
printf("Tracee entered group-stop PTRACE_EVENT_STOP (signal: %d)\n", signal);
ptrace(PTRACE_LISTEN, pid, NULL, NULL);
} else {
printf("Tracee entered non-group-stop PTRACE_EVENT_STOP (signal: %d)\n", signal);
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
}
break;
default:
if (signal == (SIGTRAP | 0x80)) {
printf("Tracee entered/exited syscall\n");
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
} else {
printf("Tracee received signal (signal: %d)\n", signal);
ptrace(PTRACE_SYSCALL, pid, NULL, signal);
}
break;
}
}
}
}
int main()
{
pid_t pid = fork();
if (pid == 0) {
printf("[Child] Raising SIGSTOP\n");
// Allow parent to PTRACE_SEIZE
if (raise(SIGSTOP) != 0) {
_exit(255);
}
printf("[Child] Resumed from SIGSTOP\n");
_exit(0);
}
// Wait for stop
int status;
waitpid(pid, &status, WSTOPPED);
ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACESYSGOOD);
// Allow child to continue
kill(pid, SIGCONT);
handle_events(pid);
return EXIT_SUCCESS;
}
strace
似乎在看到非组停止时调用 PTRACE_SYSCALL
PTRACE_EVENT_STOP
:
我设法找出事件发生的原因。
当一个进程被PTRACE_SEIZE
跟踪时,ptrace_trap_notify()
将被调用到set JOBCTL_TRAP_NOTIFY
when SIGCONT
is received or JOBCTL_TRAP_STOP
will be set when a stopping signal is received. get_signal()
will check for JOBCTL_TRAP_MASK
(ie. JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY
) and call do_jobctl_trap()
. do_jobctl_trap()
然后如果进程进入组停止将发送<stopping signal> | (PTRACE_EVENT_STOP << 8)
或者否则它将发送 SIGTRAP | (PTRACE_EVENT_STOP << 8)
.
因此,当使用 PTRACE_SEIZE
时:
- 停止信号将导致
<stopping signal> | (PTRACE_EVENT_STOP << 8)
事件
SIGCONT
信号将导致 SIGTRAP | (PTRACE_EVENT_STOP << 8)
事件
此行为似乎已在 commit fb1d910c178ba0c5bc32d3e5a9e82e05b7aad3cd
中引入。
我正在使用 PTRACE_SEIZE
来跟踪子进程的执行,但我 运行 遇到了一个问题,其中非组停止 PTRACE_EVENT_STOP
(信号== SIGTRAP
) 当被跟踪者接收到 SIGCONT
时被发射。我似乎找不到任何可能表明发生这种情况的文档。根据我在 ptrace(2)
联机帮助页中收集到的内容,PTRACE_EVENT_STOP
仅在满足以下条件之一时才会出现:
- 跟踪器名为
ptrace(PTRACE_INTERRUPT, ...)
- 被跟踪者入群停止(信号为
SIGSTOP
、SIGTSTP
、SIGTTIN
或SIGTTOU
) - tracee调用
fork
/vfork
/clone
并且tracer自动附加到新的process/thread
在下面的示例程序中,我得到一个带有信号 SIGTRAP
的 PTRACE_EVENT_STOP
,但它不符合这 3 个条件中的任何一个。当我 运行 程序时,我得到以下输出:
[Child] Raising SIGSTOP
Event for pid 29236: Tracee entered group-stop PTRACE_EVENT_STOP (signal: 19)
Event for pid 29236: Tracee entered non-group-stop PTRACE_EVENT_STOP (signal: 5)
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Tracee received signal (signal: 18)
Event for pid 29236: Tracee entered/exited syscall
[Child] Resumed from SIGSTOP
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Tracee entered/exited syscall
Event for pid 29236: Process exited
关于这个特定的 PTRACE_EVENT_STOP
是什么意思有什么想法吗?
示例程序:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
static void handle_events(pid_t pid_spec)
{
while (1) {
int status;
pid_t pid = waitpid(pid_spec, &status, __WALL);
printf("Event for pid %d: ", pid);
if (WIFEXITED(status)) {
printf("Process exited\n");
break;
} else if (WIFSIGNALED(status)) {
printf("Process killed by signal\n");
break;
} else if (WIFSTOPPED(status)) {
int ptrace_event = status >> 16;
int signal = WSTOPSIG(status);
switch (ptrace_event) {
case PTRACE_EVENT_STOP:
if (signal == SIGSTOP || signal == SIGTSTP
|| signal == SIGTTIN || signal == SIGTTOU) {
printf("Tracee entered group-stop PTRACE_EVENT_STOP (signal: %d)\n", signal);
ptrace(PTRACE_LISTEN, pid, NULL, NULL);
} else {
printf("Tracee entered non-group-stop PTRACE_EVENT_STOP (signal: %d)\n", signal);
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
}
break;
default:
if (signal == (SIGTRAP | 0x80)) {
printf("Tracee entered/exited syscall\n");
ptrace(PTRACE_SYSCALL, pid, NULL, 0);
} else {
printf("Tracee received signal (signal: %d)\n", signal);
ptrace(PTRACE_SYSCALL, pid, NULL, signal);
}
break;
}
}
}
}
int main()
{
pid_t pid = fork();
if (pid == 0) {
printf("[Child] Raising SIGSTOP\n");
// Allow parent to PTRACE_SEIZE
if (raise(SIGSTOP) != 0) {
_exit(255);
}
printf("[Child] Resumed from SIGSTOP\n");
_exit(0);
}
// Wait for stop
int status;
waitpid(pid, &status, WSTOPPED);
ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACESYSGOOD);
// Allow child to continue
kill(pid, SIGCONT);
handle_events(pid);
return EXIT_SUCCESS;
}
strace
似乎在看到非组停止时调用 PTRACE_SYSCALL
PTRACE_EVENT_STOP
:
我设法找出事件发生的原因。
当一个进程被PTRACE_SEIZE
跟踪时,ptrace_trap_notify()
将被调用到set JOBCTL_TRAP_NOTIFY
when SIGCONT
is received or JOBCTL_TRAP_STOP
will be set when a stopping signal is received. get_signal()
will check for JOBCTL_TRAP_MASK
(ie. JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY
) and call do_jobctl_trap()
. do_jobctl_trap()
然后如果进程进入组停止将发送<stopping signal> | (PTRACE_EVENT_STOP << 8)
或者否则它将发送 SIGTRAP | (PTRACE_EVENT_STOP << 8)
.
因此,当使用 PTRACE_SEIZE
时:
- 停止信号将导致
<stopping signal> | (PTRACE_EVENT_STOP << 8)
事件 SIGCONT
信号将导致SIGTRAP | (PTRACE_EVENT_STOP << 8)
事件
此行为似乎已在 commit fb1d910c178ba0c5bc32d3e5a9e82e05b7aad3cd
中引入。