C 线程可以跟踪进程吗?

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

我有一个多线程进程,它必须控制另一个进程的执行。 为此,从我使用Ptrace的一个线程开始。 这就是tracee的创建和启动方式

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负责追踪另一个在发送

  • ptrace(ptrace_CONT,childPID,0,0)
  • ptrace(ptrace_GETREGS,childPID,0,寄存器) 产生的错误是:ptrace(ptrace_GETREGS,…)无法获取寄存器:没有这样的进程


    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义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;
    
    }