【发布时间】:2011-01-22 12:11:11
【问题描述】:
有人添加到Wikipedia "ptrace" article 声称,在 Linux 上,ptraced 进程本身不能 ptrace 另一个进程。我正在尝试确定是否(如果是,为什么)是这种情况。下面是我设计的一个简单程序来测试它。我的程序失败了(子子进程无法正常运行),但我确信这是我的错误,而不是根本问题。
本质上,初始进程 A 派生出进程 B,而后者又派生出 C。 A ptrace 其子 B,B ptrace 其子 C。设置完成后,所有三个进程都将被写入以每秒一次将A、B 或C 打印到标准输出。
实际上,A 和 B 工作正常,但 C 只打印一次然后卡住。检查ps -eo pid,cmd,wchan 显示C 卡在内核函数ptrace_stop 中,而其余的都在hrtimer_nanosleep 中,我希望这三个都在。
偶尔所有三个都可以工作(因此程序会打印 Cs 以及 As 和 Bs),这让我相信在初始设置中存在一些竞争条件。
我的猜测可能是错误的:
- 与 A 看到与 B 相关的
SIGCHLD相关,看到SIGCHLD与向 C 发出信号有关,并 wait(2) 报告两者都来自 B(但是对两个 pid 的 PTRACE_CONT 的 hacky 调用并不能解决问题)? - C 应该由 B 跟踪 - C 继承了 A 的 ptrace(以及 B 对 ptrace 的调用既没有出错也没有覆盖它)?
谁能弄清楚我做错了什么?谢谢。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
static void a(){
while(1){
printf ("A\n");
fflush(stdout);
sleep(1);
}
}
static void b(){
while(1){
printf ("B\n");
fflush(stdout);
sleep(1);
}
}
static void c(){
while(1){
printf ("C\n");
fflush(stdout);
sleep(1);
}
}
static void sigchld_handler(int sig){
int result;
pid_t child_pid = wait(NULL); // find who send us this SIGCHLD
printf("SIGCHLD on %d\n", child_pid);
result=ptrace(PTRACE_CONT, child_pid, sig, NULL);
if(result) {
perror("continuing after SIGCHLD");
}
}
int main(int argc,
char **argv){
pid_t mychild_pid;
int result;
printf("pidA = %d\n", getpid());
signal(SIGCHLD, sigchld_handler);
mychild_pid = fork();
if (mychild_pid) {
printf("pidB = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("outer ptrace");
}
a();
}
else {
mychild_pid = fork();
if (mychild_pid) {
printf("pidC = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("inner ptrace");
}
b();
}
else {
c();
}
}
return 0;
}
【问题讨论】:
-
不禁注意到
ptrace(PTRACE_CONT, child_pid, sig, NULL)...你的意思可能是ptrace(PTRACE_CONT, child_pid, NULL, sig)(data=sig)