有人在维基百科的“ptrace”文章中添加了声称,在 Linux 上,ptraced 进程本身不能 ptrace 另一个进程。我正在尝试确定是否(如果是,为什么)是这种情况。下面是我设计的一个简单程序来测试它。我的程序失败(子子进程无法正常运行),但我非常确信这是我的错误,而不是根本问题。
本质上,初始进程A分叉了进程B,而 B 又分叉了C。A ptrace 其子B,B ptrace 其子C。设置完成后,所有三个进程都会每秒 写入一次 print A
、B
或stdout 。C
在实践中,A和B工作正常,但C只打印一次然后卡住。检查ps -eo pid,cmd,wchan
显示C卡在内核函数ptrace_stop
中,而其余的都在hrtimer_nanosleep
我希望所有三个都出现的位置。
偶尔这三个都可以工作(所以程序会打印 Cs 以及 As 和 Bs),这让我相信在初始设置中存在一些竞争条件。
我对可能出错的猜测是:
- 与A看到 a
SIGCHLD
相关的 a 与B看到 aSIGCHLD
与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;
}