C 线程可以跟踪进程吗?
我有一个多线程进程,它必须控制另一个进程的执行。 为此,从我使用Ptrace的一个线程开始。 这就是tracee的创建和启动方式C 线程可以跟踪进程吗?,c,multithreading,pthreads,ptrace,C,Multithreading,Pthreads,Ptrace,我有一个多线程进程,它必须控制另一个进程的执行。 为此,从我使用Ptrace的一个线程开始。 这就是tracee的创建和启动方式 switch( childPID=fork() ){ case -1: perror("fork()"); return -1; case 0 : ptrace(PTRACE_TRACEME, 0, NULL, NULL); execve(execPath,NULL,NUL
switch( childPID=fork() ){
case -1:
perror("fork()");
return -1;
case 0 :
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execve(execPath,NULL,NULL);
return -1;
default:
break;
}
这就是流程的运行方式
while (1) {
ptrace(PTRACE_CONT, childPID, 0, 0);
waitpid( childPID, &status, 0);
// inspect status and break in some cases
...
...
}
我有一个类似的非多线程应用程序,它工作得很好,加载exec并检查堆栈和内存,没有问题。但是,当我在多线程上尝试这种配置时,我创建的进程根本不会运行
我的问题是。如何从线程跟踪进程?我是否必须更改附加流程的方式 在多线程应用程序中,为了跟踪程序,需要对父进程通过使用ptrace(ptrace_foo,pid,…)生成的每个特定线程使用ptrace,其中pid是进程的线程id。为了跟踪父级本身,请在父级代码中使用pid=0的ptrace。ptrace仅适用于特定的线程。 希望你能找到你所关心的 [编辑] 关于问题的解释,我犯了一个错误 回答下面的评论:根据手册PTRACE_TRACEME没有将tracee附加到主线程,而是附加到父线程 PTRACE_TRACEME——指示此进程由其父进程跟踪 [老掉牙的回答]
跟踪是每个线程的,您需要单独附加每个线程。您的代码只是附加到execve调用的进程的主线程 从自述linux ptrace: 附件和后续命令是每个线程的:在多线程进程中,每个线程都可以单独附加到(可能不同的)跟踪程序,或者不附加,因此不进行调试。因此,“tracee”总是指(一个)线程,而不是“一个(可能是多线程的)进程” 您可以捕捉信号陷阱信号(来自ptrace man): 如果PTRACE_O_TRACEEXEC选项无效,则被跟踪进程对execve(2)的所有成功调用都将导致向其发送SIGTRAP信号,使父进程有机会在新程序开始执行之前获得控制权 并使用PTRACE_GETEVENTMSG恢复pid: 检索关于刚刚发生的ptrace事件的消息(作为无符号长消息),将其放置在跟踪程序中的地址数据处。对于PTRACE_EVENT_EXIT,这是跟踪对象的退出状态。对于PTRACE_EVENT_FORK、PTRACE_EVENT_VFORK、PTRACE_EVENT_VFORK、PTRACE_EVENT_VFORK和PTRACE_EVENT_CLONE,这是新流程的PID。(地址被忽略。)
然后使用PTRACE_ATTACH来附加到恢复的新pid。文章末尾的代码是问题的一个答案。 您可以拥有跟踪进程的线程。
如果有人感兴趣,我正在试验的问题是,出于一些无法理解的原因,跟踪器线程并不是发送所有跟踪命令的线程。其中一个打电话给fork负责追踪另一个在发送
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义NUM_线程9
int-childPID;
内敛的父亲;
无效打印寄存器(结构用户寄存器){
printf(“\tReg ebx 0x%lx\n”,寄存器->ebx);
printf(“\tReg ecx 0x%lx\n”,寄存器->ecx);
printf(“\tReg edx 0x%lx\n”,寄存器->edx);
printf(“\tReg esi 0x%lx\n”,寄存器->esi);
printf(“\tReg edi 0x%lx\n”,寄存器->edi);
printf(“\tReg ebp 0x%lx\n”,寄存器->ebp);
printf(“\tReg eax 0x%lx\n”,寄存器->eax);
printf(“\tReg xds 0x%lx\n”,寄存器->xds);
printf(“\tReg xes 0x%lx\n”,寄存器->xes);
printf(“\tReg xfs 0x%lx\n”,寄存器->xfs);
printf(“\tReg xgs 0x%lx\n”,寄存器->xgs);
printf(“\tReg orig\u eax 0x%lx\n”,寄存器->orig\u eax);
printf(“\tReg eip 0x%lx\n”,寄存器->eip);
printf(“\tReg xcs 0x%lx\n”,寄存器->xcs);
printf(“\tReg eflags 0x%lx\n”,寄存器->eflags);
printf(“\tReg esp 0x%lx\n”,寄存器->esp);
printf(“\tReg xss 0x%lx\n”,寄存器->xss);
}
int load(char*execPath){
开关(childPID=fork()){
案例1:
perror(“fork()”);
返回-1;
案例0:
if(access(execPath,X_OK)==-1){
printf(“\tAcces拒绝\n”,execPath);
}
否则{
printf(“\t子进程pid:%d%d\n”,子进程pid,getpid());
如果(ptrace(ptrace_TRACEME,0,NULL,NULL)8==(SIGTRAP |)(ptrace_EVENT_EXEC8==(SIGTRAP |(PTRACE_EVENT_exit跟踪是针对每个线程的,您需要单独附加每个线程。您只需将代码附加到由execve调用的进程的主线程。谢谢您的纠正,我不是英语母语人士。您可以自己编辑。不是问的问题-是跟踪程序,不是多线程跟踪对象。我不需要ind线程的pid,因为我的tracee是单线程应用程序。问题是跟踪程序是多线程的,而不是相反的^^.ptrace(ptrace_TRACEME,0,NULL,NULL);在我看来,类似于:附加到父线程。这可能是或不可能是实际跟踪的线程。您认为更改附加方法可以克服我的问题吗?但是在ptrace(ptrace_attach,pid,…)pid应该是ThreadID?Olivecode抱歉,我的第一条评论是错误的,我是stackoverflow的新手,我不知道我只有5分钟的时间来修改一条评论!抱歉!问题不在这里-是跟踪器,而不是多线程的tracee。问题解决了吗?你可以在自己的帖子中发布答案。事实上,对于多线程跟踪器程序,y
#include <pthread.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/reg.h>
#include <sys/user.h>
#define NUM_THREADS 9
int childPID;
int fatherPID;
void print_registers(struct user_regs_struct *registers){
printf("\tReg ebx 0x%lx\n",registers->ebx);
printf("\tReg ecx 0x%lx\n",registers->ecx);
printf("\tReg edx 0x%lx\n",registers->edx);
printf("\tReg esi 0x%lx\n",registers->esi);
printf("\tReg edi 0x%lx\n",registers->edi);
printf("\tReg ebp 0x%lx\n",registers->ebp);
printf("\tReg eax 0x%lx\n",registers->eax);
printf("\tReg xds 0x%lx\n",registers->xds);
printf("\tReg xes 0x%lx\n",registers->xes);
printf("\tReg xfs 0x%lx\n",registers->xfs);
printf("\tReg xgs 0x%lx\n",registers->xgs);
printf("\tReg orig_eax 0x%lx\n",registers->orig_eax);
printf("\tReg eip 0x%lx\n",registers->eip);
printf("\tReg xcs 0x%lx\n",registers->xcs);
printf("\tReg eflags 0x%lx\n",registers->eflags);
printf("\tReg esp 0x%lx\n",registers->esp);
printf("\tReg xss 0x%lx\n",registers->xss);
}
int load(char * execPath){
switch( childPID=fork() ){
case -1:
perror("fork()");
return -1;
case 0 :
if( access(execPath, X_OK)==-1){
printf("\tAcces denied to\n",execPath);
}
else {
printf("\tChild Process pid :%d %d\n",childPID,getpid());
if(ptrace(PTRACE_TRACEME, 0, NULL, NULL)<0){
perror("ptrace(PTRACE_TRACEME)");
return -1;
}
execve(execPath,NULL,NULL);
perror("execve()");
}
return -1;
default:
wait(NULL);
fatherPID=getpid();
printf("\tParent Process pid :%d %d\n",fatherPID,childPID);
if (ptrace(PTRACE_SETOPTIONS, childPID, 0, PTRACE_O_TRACEEXIT)){
perror("stopper: ptrace(PTRACE_SETOPTIONS, ...)");
return -1;
}
break;
}
return -1;
}
void registers(){
printf("\t@@Command get_registers@\n");
struct user_regs_struct * registers = (struct user_regs_struct*)(calloc(1, sizeof(struct user_regs_struct)));
long ret = ptrace (PTRACE_GETREGS, childPID, 0, registers);
if (ret <0) perror("ptrace (PTRACE_GETREGS,..) Couldn't get registers");
print_registers(registers);
free(registers);
}
int continuE(){
int status = 0;
int signo;
long long_var=0;
// to continue the execution is needed to trigger the event
while (1) {
ptrace(PTRACE_CONT, childPID, 0, 0);
waitpid( childPID, &status, 0);
if (WIFEXITED(status))
printf("Child exited by %d\n",WEXITSTATUS(status));
if (WIFSIGNALED(status))
printf(" child process terminated by a signal %d \n",WTERMSIG(status) );
if (WIFSTOPPED(status)) {
signo = WSTOPSIG(status);
//printf("Child stopped by %d\n",signo);
}
// we had the sigtrap and we are at the exec
if (status>>8 == (SIGTRAP | (PTRACE_EVENT_EXEC<<8))){
printf("\t###Stopped the tracee at EXEC, with status %d###\n",WEXITSTATUS(status));
ptrace(PTRACE_GETEVENTMSG, childPID,0,&long_var);
printf("\t###PTRACE_GETEVENTMSG result %lu ,%d ###\n",long_var,WEXITSTATUS(long_var));
}
// we have a sigtrap and we are on the exit
// we could think to take out PTRACE_O_TRACEEXIT
if (status>>8 == (SIGTRAP | (PTRACE_EVENT_EXIT<<8))){
printf("\t###Stopped the tracee at EXIT###\n");
signo= SIGHUP;
}
// normal cases
if ((signo == SIGTRAP) || (signo == SIGTERM) ||(signo ==SIGINT) || (signo == SIGHUP)
|| ( signo == SIGSEGV) ){
break;
}
}
return signo;
}
void *work(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
load("/home/rtems/plibeagleeye/Plib/Tests/bin/stanford.o");
registers();
continuE();
registers();
pthread_exit(NULL);
}
void *work2(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
int rc;
long *taskids;
void *status;
taskids = (long *) malloc( NUM_THREADS * sizeof(long));
long t=0;
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
taskids[t] = 0;
rc = pthread_create(&threads[t], &attr, work, (void *)taskids[t]);
for(t=1; t<NUM_THREADS; t++){
taskids[t] = t;
printf("Creating thread %ld\n", t);
rc = pthread_create(&threads[t], &attr, work2, (void *)taskids[t]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_attr_destroy(&attr);
for(t=0; t<NUM_THREADS; t++){
rc = pthread_join(threads[t], &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
}
printf("Ciaoz all threads finished their jobs\n");
free(taskids);
/* Last thing that main() should do */
pthread_exit(NULL);
return 0;
}