首先,启动流程B(参见下面的mt.cpp
),它将创建一个pthread_create()
的线程。将为进程A输出主线程的ppid
,pid
和tid
以及新线程,然后它们都启动for循环并引发SIGTRAP
,这应该是在流程A中被waitpid()
抓住。
其次,使用进程B的attach.cpp
启动进程A(请参阅下面的pid
)。进程A将通过ptrace(PTRACE_ATTACH, ...)
附加到进程B,然后使用{{1}等待信号事件在waitpid()
中,如果获得while(true)
,请致电ptrace(PTRACE_CONT, ...)
,如果获得SIGTRAP
,请致电循环。
现在是问题所在:
进程A可以捕获进程B的主线程引发的SIGSTOP
并成功调用SIGTRAP
,然后进程B将继续按预期执行。
BUT !!!
当流程B的新主题提出ptrace(PTRACE_CONT, ...)
时,流程A未能SIGTRAP
ptrace(PTRACE_CONT, ...)
"没有此类流程" ,因为进程B的核心转储了errmsg
"跟踪/断点陷阱(核心转储)" 。
此外,errmsg
变为假,WIFSTOPPED(status)
变为真。
我知道WIFSIGNALED(status)
的默认操作是终止进程,似乎SIGTRAP
在终止操作之后转移到进程A,而不是之前,因此进程A没有机会继续进程乙
我尝试过SIGTRAP
代替进程A,gdb
都可以被捕获并继续成功。因此,进程A的代码中肯定存在问题。
以下SIGTRAP
作为流程A执行:
attach.cpp
以下#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
pid_t pid = 0;
int ret = 0;
int status = 0;
if (argc > 1) {
pid = atoi(argv[1]);
printf("pid=%d\n", pid);
}
ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
printf("attach ret=%d\n", ret);
waitpid(pid, &status, 0);
ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
printf("cont ret=%d\n", ret);
while (true) {
ret = waitpid(pid, &status, WUNTRACED);
printf("\nwaitpid ret=%d.\n", ret);
int sig = 0;
if (WIFSIGNALED(status)) {
printf("WIFSIGNALED\n");
sig = WTERMSIG(status);
} else if (WIFSTOPPED(status)) {
printf("WIFSTOPPED\n");
sig = WSTOPSIG(status);
} else {
printf("other status %d\n", status);
}
if (SIGTRAP == sig) {
ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
printf("SIGTRAP cont ret=%d err=%s\n", ret, strerror(errno));
} else if (SIGSTOP == sig) {
ret = ptrace(PTRACE_DETACH, pid, NULL, NULL);
printf("SIGSTOP detach ret=%d\n", ret);
break;
} else {
printf("other signal %d\n", sig);
}
sleep(2);
}
return 0;
}
作为流程B执行:
mt.cpp
结果如下:
流程B:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
void *func(void * arg)
{
printf("child ppid=%d pid=%d tid=%d\n", getppid(), getpid(), gettid());
int i = 0;
for (; i < 5; i++) {
printf("child loop i=%d\n", i);
sleep(2);
}
printf("\nchild before SIGTRAP\n", gettid());
raise(SIGTRAP);
printf("child after SIGTRAP\n\n", gettid());
for (; i < 8; i++) {
printf("child loop i=%d\n", i);
sleep(2);
}
return NULL;
}
int main(void)
{
printf("parent ppid=%d pid=%d tid=%d\n", getppid(), getpid(), gettid());
pthread_t tid;
pthread_create(&tid, NULL, func, NULL);
int i = 0;
for (; i < 3; i++) {
printf("parent loop i=%d\n", i);
sleep(2);
}
printf("\nparent before SIGTRAP\n", gettid());
raise(SIGTRAP);
printf("parent after SIGTRAP\n\n", gettid());
for (; i < 10; i++) {
printf("parent loop i=%d\n", i);
sleep(2);
}
pthread_join(tid, NULL);
return 0;
}
流程A:
$ ./mt
parent ppid=12238 pid=30389 tid=30389
parent loop i=0
child ppid=12238 pid=30389 tid=30390
child loop i=0
parent loop i=1
child loop i=1
parent loop i=2
child loop i=2
parent before SIGTRAP
child loop i=3
parent after SIGTRAP
parent loop i=3
child loop i=4
parent loop i=4
child before SIGTRAP
Trace/breakpoint trap (core dumped)
答案 0 :(得分:1)
Linux PTRACE_ATTACH
请求,尽管其参数名为 pid ,但只会跟踪该线程。
您可以通过将此函数添加到程序并在两个线程中调用它来验证这一点:
#define trprefix "TracerPid:"
int tracerpid()
{
char stfile[100], buf[512];
sprintf(stfile, "/proc/self/task/%d/status", (int)gettid());
int trpid = -1;
FILE *st = fopen(stfile, "r");
if (st != NULL) {
while (fgets(buf, sizeof buf, st) != NULL) {
if (strncmp(buf, trprefix, strlen(trprefix)) == 0)
trpid = atoi(buf+strlen(trprefix));
}
fclose(st);
}
return trpid;
}
你会看到父线程的Tracer PID是你的“attach”进程,而子线程的Tracer PID是0。
当子线程引发SIGTRAP
时,线程没有跟踪器,因此将采用SIGTRAP
的默认操作 - 整个过程将被终止。这就是为什么你的追踪者说waitpid返回WIFSIGNALED
。
解决此问题:
在“mt”程序中,将调用移至pthread_create
,使其位于第一个延迟循环之后,这将为您提供足够的时间在创建新线程之前附加到进程。
在ptrace(PTRACE_ATTACH, ...); waitpid(...);
:
errno = 0;
ret = ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACECLONE);
printf("setoptions ret=%d err=%s\n", ret, strerror(errno));
PTRACE_O_TRACECLONE
选项将让您的程序跟踪目标使用clone
创建的每个线程。
将您的所有waitpid(pid, ...)
转换为waitpid(-1, ...)
,以便您的程序等待任何主题。