2

I am trying to implement strace -f. Please look at the main loop of my program:

static void trace_syscalls(pid_t pid)
{
  int status;
  wait(&status);

  unsigned int options = PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE
    | PTRACE_O_TRACEVFORK | PTRACE_O_EXITKILL;
  ptrace(PTRACE_SETOPTIONS, pid, 0, options);

  std::list<pid_t> pids = { pid };
  pid_t new_pid = 0;
  struct user_regs_struct regs;
  ptrace(PTRACE_SYSCALL, pid, 0, 0);

  while (!pids.empty())
  {
    for (auto it_pid = pids.begin(); it_pid != pids.end(); it_pid++)
    {
      waitpid(*it_pid, &status, 0);
      if (WIFEXITED(status))
      {
        std::cerr << "program exited with code " << WEXITSTATUS(status)
          << std::endl;
        pids.erase(it_pid);
        break;
      }

      // Entry of the sycall
      ptrace(PTRACE_GETREGS, *it_pid, 0, &regs);
      std::cerr << "[pid " << *it_pid << "] ";


      switch_syscall(regs.orig_rax);

      ptrace(PTRACE_SYSCALL, *it_pid, 0, 0);  // Restart child
      waitpid(*it_pid, &status, 0);           // Waiting the syscall to end

      // Exit of the syscall
      ptrace(PTRACE_GETREGS, *it_pid, 0, &regs);

      // Printing the return value
      std::cerr << " = ";
      if (regs.rax == (unsigned long long)-2)
        std::cerr << -1 << "\n";
      else
        std::cerr << regs.rax << "\n";

      if (regs.orig_rax == __NR_fork || regs.orig_rax == __NR_vfork
          || regs.orig_rax == __NR_clone)
      {
        ptrace(PTRACE_GETEVENTMSG, *it_pid, 0, &new_pid);
        if (new_pid != 0 && !exists(pids, new_pid))
        {
          printf("NEW = %u\n", new_pid);
          pids.push_front(new_pid);
          ptrace(PTRACE_SYSCALL, new_pid, 0, 0);
        }
      }
      ptrace(PTRACE_SYSCALL, *it_pid, 0, 0);
    }
  }
}

I am currently tracing the following testing code:

int main()
{
  pid_t pid = 0;

  pid = fork();

  if (pid == 0)
  {
    printf("child\n");
    exit(42);
  }

  sleep(1);
  printf("parent\n");
  return 0;
}

With that test, I get an output showing that both the child and the father exit with 0. I don't understand that, since the child uses exit(42). Also, some system calls of the father are detected in the son's dead process. Everything makes me think that WIFEXITED returns 0 with the status of the child, even after the child calls exit().

Here is a sample output:

[...]
[pid 14229] mprotect()  = 0
[pid 14229] mprotect()  = 0
[pid 14229] munmap()  = 0
[pid 14229] clone()  = 18446744073709551578
NEW = 14230
[pid 14230] Syscall number: 5 = 0
[pid 14229] clone()  = 18446744073709551578
[pid 14230] mmap()  = 140012527452160
[pid 14229] Syscall number: 14 = 18446744073709551578
[pid 14230] Syscall number: 1child
 = 6
[pid 14229] Syscall number: 13 = 18446744073709551578
[pid 14230] exit_group()  = 18446744073709551578
[pid 14229] Syscall number: 14 = 0
[pid 14230] Syscall number: 14 = 0
[pid 14229] Syscall number: 35 = 0
[pid 14230] Syscall number: 35 = 0
[pid 14229] Syscall number: 5 = 0
[pid 14230] Syscall number: 5 = 0
[pid 14229] mmap()  = 140012527452160
[pid 14230] mmap()  = 140012527452160
[pid 14229] Syscall number: 1parent
 = 7
[pid 14230] Syscall number: 1 = 7
[pid 14229] exit_group()  = 18446744073709551578
program exited with code 0
program exited with code 0

Why do the exit of the child does not take effect ?

kst
  • 21
  • 3
  • Every time you call waitpid, you should check returnval / status pair. Second thing that comes to my mind (not tested your code), is that it might be that you cancel the syscalls, since after exit_group, you still get syscalls from that process. – Stian Skjelstad Apr 18 '16 at 10:46

0 Answers0