当tracee收到SIGCONT时,为什么会发生SIGTRAP PTRACE_EVENT_STOP?

时间:2018-03-19 01:00:10

标签: c linux ptrace

我使用PTRACE_SEIZE来跟踪子流程的执行情况,但我遇到了一个非群组停靠问题PTRACE_EVENT_STOP(signal == {当tracee收到SIGTRAP时,会发出{1}})。我似乎无法找到任何可能表明这种情况发生的文档。根据我在SIGCONT联机帮助页中收集的内容,ptrace(2)仅在满足以下条件之一时才会出现:

  • 该追踪器名为PTRACE_EVENT_STOP
  • tracee进入组停止(信号为ptrace(PTRACE_INTERRUPT, ...)SIGSTOPSIGTSTPSIGTTIN
  • tracee名为SIGTTOU / fork / vfork,跟踪器自动附加到新进程/线程

在下面的示例程序中,我收到信号为clone的{​​{1}},但它与这3个条件中的任何一个都不匹配。当我运行程序时,我得到以下输出:

PTRACE_EVENT_STOP

关于这个特定SIGTRAP意味着什么的任何想法?

示例程序:

[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

1 个答案:

答案 0 :(得分:1)

我设法找出事件发生的原因。

当某个流程与PTRACE_SEIZE进行匹配时,ptrace_trap_notify()会在set JOBCTL_TRAP_NOTIFYJOBCTL_TRAP_STOP被设置时调用get_signal()一个SIGCONT is receivedJOBCTL_TRAP_MASK会检查JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY(即<stopping signal> | (PTRACE_EVENT_STOP << 8))和stopping signal is received。如果进程进入群组停止,call do_jobctl_trap()会发送SIGTRAP | (PTRACE_EVENT_STOP << 8),否则会发送PTRACE_SEIZE

因此,在使用<stopping signal> | (PTRACE_EVENT_STOP << 8)

  • 停止信号将导致SIGCONT事件
  • SIGTRAP | (PTRACE_EVENT_STOP << 8)信号将导致class PgSplash(Screen): def skip(self, dt): screen.switch_to(pages[1]) def on_enter(self, *args): Clock.schedule_once(self.skip, 5) class PgBrowser(Screen): def on_pre_enter(self, *args): user_path = os.path.join(browser_base.get_home_directory(), 'Documents') browser = browser_base.FileBrowser(select_string='Select', favorites=[(user_path, 'Documents')]) browser.bind(on_success=self._fbrowser_success, on_canceled=self._fbrowser_canceled, on_submit=self._fbrowser_submit) self.add_widget(browser) def _fbrowser_canceled(self, instance): print('cancelled, Close self.') self.root_window.hide() sys.exit(0) def _fbrowser_success(self, instance): # select pressed global file print(instance.selection) file = instance.selection[0] def _fbrowser_submit(self, instance): # clicked on the file global file print(instance.selection) file = instance.selection[0] pages = [PgSplash(name="PgSplash"), PgBrowser(name="PgBrowser")] screen = ScreenManager() screen.add_widget(pages[0]) class myApp(App): def build(self): screen.current = "PgSplash" return screen myApp().run() 事件

此行为似乎已在do_jobctl_trap()中引入。