【问题标题】:Why does a SIGTRAP PTRACE_EVENT_STOP occur when the tracee receives SIGCONT?为什么当被跟踪者收到 SIGCONT 时会发生 SIGTRAP PTRACE_EVENT_STOP?
【发布时间】:2018-03-19 01:00:09
【问题描述】:

我正在使用 PTRACE_SEIZE 来跟踪子进程的执行,但我遇到了一个问题,即当tracee 收到SIGCONT。我似乎找不到任何可能表明为什么会发生这种情况的文档。根据我在 ptrace(2) 手册页中收集到的信息,PTRACE_EVENT_STOP 仅在以下条件之一为真时才会出现:

  • 追踪器名为ptrace(PTRACE_INTERRUPT, ...)
  • 被跟踪者进入组停止(信号为SIGSTOPSIGTSTPSIGTTINSIGTTOU
  • 被称为fork/vfork/clone 的跟踪器和跟踪器自动附加到新进程/线程

在下面的示例程序中,我得到一个带有信号SIGTRAPPTRACE_EVENT_STOP,但它与这三个条件中的任何一个都不匹配。当我运行程序时,我得到以下输出:

[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_EVENT_STOP 时调用PTRACE_SYSCALL

【问题讨论】:

    标签: c linux ptrace


    【解决方案1】:

    我设法弄清楚事件发生的原因。

    当使用PTRACE_SEIZE 跟踪进程时,当SIGCONT is receivedJOBCTL_TRAP_STOP 设置为stopping signal is received 时,ptrace_trap_notify() 将被调用到set JOBCTL_TRAP_NOTIFYget_signal() 将检查JOBCTL_TRAP_MASK(即JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY)和call do_jobctl_trap()。如果进程进入组停止,do_jobctl_trap() 将发送&lt;stopping signal&gt; | (PTRACE_EVENT_STOP &lt;&lt; 8),否则它将发送SIGTRAP | (PTRACE_EVENT_STOP &lt;&lt; 8)

    因此,当使用PTRACE_SEIZE:

    • 停止信号将导致&lt;stopping signal&gt; | (PTRACE_EVENT_STOP &lt;&lt; 8) 事件
    • SIGCONT 信号将导致SIGTRAP | (PTRACE_EVENT_STOP &lt;&lt; 8) 事件

    此行为似乎已在 commit fb1d910c178ba0c5bc32d3e5a9e82e05b7aad3cd 中引入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 2016-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多