5

他の 1 つのプロセスの実行を制御する必要があるマルチスレッド プロセスがあります。そのために、スレッドの 1 つから Ptrace を使用します。これは、トレースが作成されて起動される方法です。

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をロードし、スタックとメモリを検査する同様の非マルチスレッドアプリケーションを持っています。しかし、マルチスレッドでこの構成を試してみると、作成したプロセスがまったく実行されません。

私の質問はです。スレッドからプロセスをトレースするにはどうすればよいですか? プロセスのアタッチ方法を変更する必要がありますか?

4

3 に答える 3

2

投稿の最後のコードは、質問に対する 1 つの回答です。 プロセスをトレースするスレッドを持つことができます。


誰かが興味を持っている場合は、私が実験していた問題は、いくつかの理解できない理由により、トレーサー スレッドがすべてのトレース コマンドを送信するスレッドではなかったことです。そのうちの 1 人は fork を呼び出してトレースの責任を負い、もう 1 人は送信していました。

  1. ptrace(PTRACE_CONT, childPID, 0, 0);
  2. ptrace (PTRACE_GETREGS、childPID、0、登録);

結果のエラーは次のとおりでした: ptrace (PTRACE_GETREGS,..) 登録を取得できませんでした: そのようなプロセスはありません


#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;

}

本当に驚いたのは、どのスレッドがトレーサーであるかの兆候がないことです。ptrace(PTRACE_TRACEME, 0, NULL, NULL) 0 は完全に機能しているようです。

于 2013-09-12T08:33:23.243 に答える
1

マルチスレッド アプリケーションでは、プログラムをトレースするために、ptrace(PTRACE_foo, pid, ...) を使用して、親プロセスが生成する特定のスレッドごとに ptrace を使用する必要があります。ここで、pid はプロセスのスレッド ID です。親自体をトレースするには、親コードで pid = 0 の ptrace を使用します。ptrace は厳密に特定のスレッドのみに適用されます。あなたが探していたものが見つかったことを願っています...

于 2013-09-11T11:31:32.527 に答える
0

[編集]

質問の解釈を間違えました。

以下のコメントへの回答: マニュアルによると、PTRACE_TRACEME はトレースをメイン スレッドではなく、親スレッドにアタッチします。

PTRACE_TRACEME -- このプロセスがその親によってトレースされることを示します。

[古い不適切な回答]

トレースはスレッドごとです。各スレッドを個別にアタッチする必要があります。コードは、execve によって呼び出されるプロセスのメイン スレッドに接続するだけです。

README-linux-ptrace から:

アタッチメントと後続のコマンドはスレッドごとです。マルチスレッド プロセスでは、すべてのスレッドを (潜在的に異なる) トレーサに個別にアタッチするか、アタッチせずにそのままにしてデバッグを行わないことができます。したがって、「tracee」は常に「(1 つの) スレッド」を意味し、「(おそらくマルチスレッド化された) プロセス」を意味することはありません。

SIGTRAP シグナルをキャッチすることで実行できます (ptrace man から):

PTRACE_O_TRACEEXEC オプションが有効でない場合、トレースされたプロセスによる execve(2) へのすべての呼び出しが成功すると、そのプロセスに SIGTRAP シグナルが送信され、新しいプログラムが実行を開始する前に親に制御を取得する機会が与えられます。

PTRACE_GETEVENTMSG を使用して pid を回復します。

発生した ptrace イベントに関するメッセージを (unsigned long として) 取得し、それをトレーサーのアドレス データに配置します。PTRACE_EVENT_EXIT の場合、これは tracee の終了ステータスです。PTRACE_EVENT_FORK、PTRACE_EVENT_VFORK、PTRACE_EVENT_VFORK_DONE、および PTRACE_EVENT_CLONE の場合、これは新しいプロセスの PID です。(addr は無視されます。)

次に、PTRACE_ATTACH を使用して、回復した新しい pid にアタッチします。

于 2013-09-11T11:49:49.507 に答える