вызов ptrace в ptraced процессе Linux

Кто-то добавил к Википедии "ptrace" статью, утверждая, что на Linux процесс ptraced не мог самостоятельно ptrace другой процесс. Я пытаюсь определить, имеет ли (и раз так почему) это место. Ниже простая программа, я умудрился тестировать это. Мои сбои программы (sub подпроцесс не работает правильно), но я довольно убежден, что это - моя ошибка и не что-то фундаментальное.

В сущности начальная буква обрабатывает, ветвления обрабатывают B который в свою очередь ветвления C. ptraces его ребенок B, B ptraces его ребенок C. После того как они настраиваются, все три процесса записаны, чтобы просто распечатать A,B, или C к stdout один раз во второй.

На практике то, что происходит, - то, что A и B хорошо работают, но C печатает только однажды и затем застревает. Сверение ps -eo pid,cmd,wchan шоу C всунутая функция ядра ptrace_stop в то время как остальные находятся в hrtimer_nanosleep где я ожидал бы, что все три будут.

Достаточно редко все три действительно работают (таким образом, программа печатает Cs, а также As и бакалавра наук), который приводит меня полагать, что в начальной настройке существует некоторое состояние состязания.

Мои предположения относительно того, что могло бы быть неправильным:

  • что-то, чтобы сделать с наблюдением a SIGCHLD связанный с B, видящим a SIGCHLD сделать с сигналом к C и ожидать (2) создание отчетов об обоих как прибывающий из B (но hacky вызов PTRACE_CONT обоим pids не чинит вещи)?
  • C должен быть ptraced B - C, наследовал ptrace вместо этого (и B звонят в ptrace ни с ошибками, ни перезаписали это)?

Кто-либо может выяснить то, что я делаю неправильно?Спасибо.

#include 
#include 
#include 
#include 
#include 
#include 

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

6
задан Finlay McWalter 1 March 2010 в 22:27
поделиться

1 ответ

Вы действительно наблюдаете состояние гонки. Вы можете вызвать его повторяемость, поставив sleep(1); непосредственно перед вторым вызовом fork().

Состояние гонки вызвано тем, что процесс A неправильно передает сигналы процессу B. Это означает, что если процесс B начинает отслеживать процесс C после того, как процесс A начал отслеживать процесс B, процесс B никогда не получит сигнал SIGCHLD, указывающий на то, что процесс 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");
        }
    }
}
5
ответ дан 17 December 2019 в 04:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: