2010-03-01 4 views
6

누군가가 Wikipedia "ptrace" article에 추가되었습니다. Linux에서는 ptraced 프로세스가 다른 프로세스를 ptrace 할 수 없다고 주장했습니다. 나는 그런 경우인지 (그리고 왜 그런지) 판단하려고한다. 다음은 이것을 테스트하기 위해 고안 한 간단한 프로그램입니다. 내 프로그램이 실패합니다 (하위 하위 프로세스가 제대로 실행되지 않음). 그러나 저는 이것이 내 오류이고 근본적인 것이 아니라고 확신합니다. 본질적ptraced Linux 프로세스 내에서 ptrace 호출

초기 프로세스 포크 B 턴 포크에 C 처리. 는 하위 B, 그 자식 C을 ptraces B ptraces. 설정이 끝나면 세 프로세스 모두가 A, B 또는 C을 매초마다 표준 출력으로 인쇄합니다. 무슨 실제로

B 잘 작동하지만, C 인쇄 한 번만 다음 내동댕이 것입니다. ps -eo pid,cmd,wchan으로 확인하면 커널 함수 ptrace_stop에 붙어있는 C이 표시되고, 나머지는 hrtimer_nanosleep에있는 반면, 나는이 세 가지 모두를 기대합니다.

매우 세 가지 모두가 작동하기 때문에 (프로그램이 C와 As 및 Bs를 인쇄하므로) 초기 설정에서 경쟁 조건이 있다고 생각하게 만듭니다.

추측 잘못 될 수도 무엇인지에은 다음과 같습니다

  • 뭔가 보고와 함께 할 수있는 SIGCHLD 관련 C에 신호와 함께 할 수있는 SIGCHLD을보고 B 에, B (두 pids에 대한 PTRACE_CONT의 해킹 호출은 문제를 해결하지 못함)에서 오는 것으로보고 (2) 기다립니다.
  • C는 B 의해 ptraced한다 - C가 (B의 통화의 ptrace 및 에 오류하지도 않고이를 덮어) 대신 의해 상속의 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; 
} 
+0

가 도움이되지만 알 수 없습니다'의 ptrace (PTRACE_CONT는 child_pid, SIG, NULL)'... 당신은 아마 의미 '의 ptrace (PTRACE_CONT, child_pid, NULL, 시그마)'(데이터 = SIG) – remram

답변

4

실제로 경쟁 조건이 나타납니다. 두 번째fork() 호 바로 앞에 sleep(1);을 입력하여 반복적으로 발생할 수 있습니다.

프로세스 A가 프로세스 B에 신호를 올바르게 전달하지 못하기 때문에 경쟁 조건이 발생합니다. 즉, 프로세스 A가 프로세스 B를 추적하기 시작한 후에 프로세스 B가 프로세스 C를 추적하기 시작하면 프로세스 B는이를 나타내지 않는 신호 프로세스 C가 중지되어 계속 진행할 수 없습니다.

이 문제를 해결하려면, 당신은 당신의 SIGCHLD 핸들러를 해결해야합니다

static void sigchld_handler(int sig){ 
    int result, status; 
    pid_t child_pid = wait(&status); // find who send us this SIGCHLD 

    printf("%d received SIGCHLD on %d\n", getpid(), child_pid); 
    if (WIFSTOPPED(status)) 
    { 
     result=ptrace(PTRACE_CONT, child_pid, 0, WSTOPSIG(status)); 
     if(result) { 
      perror("continuing after SIGCHLD"); 
     } 
    } 
} 
+0

예, 그게 정확히 . 당신의 아름다운 명확한 설명을 대단히 고맙습니다. –

+0

@caf 가능한가요? –

0

그것은 "수"있다가의 ptrace 자체를 호출하는 자식 프로세스에 대한 몇 가지의 ptrace 기능을 수행 할 수 있습니다. 진정한 어려움은 트레이서 프로세스가 트레이스 프로세스에 첨부 될 때 트레이스 프로세스의 부모가된다는 것입니다. 트레이서 프로세스가 모든 (직접 및 간접적 인) 하위 프로세스 (예 : 디버거 프로그램이 멀티 스레드 프로그램을 디버깅해야하는 경우)에서 모든 동작을 추적하려고하면 자연스럽게 원래 프로세스 계층 구조가 중단되고 모든 프로세스 간/모든 자식 프로세스 들간의 스레드 간 통신 (즉, 스레드 동기화, 신호 송수신, ...)은 추적자 프로세스에 의해 에뮬레이션/다중화 될 필요가있다. 그것은 여전히 ​​"가능"하지만 훨씬 어렵고 비효율적입니다.

관련 문제