title: How to detach from process, so that it can be traced by another process?
body: <p>Program steps:</p>
  
  <ol>
  <li>Create child process by fork and call execv inside it</li>
  <li>Ptrace attach to child process</li>
  <li>Do something with ptrace</li>
  <li>Detach from child</li>
  <li>execute gdb -p child_pid</li>
  </ol>
  
  <p>But when gdb starts, it writes that child process is already tracked.
  How to detach from traced process, so that it can be traced by another process?</p>
  
  <p>Code that do things above</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/wait.h&gt;
  #include &lt;sys/signal.h&gt;
  #include &lt;sys/user.h&gt;
  #include &lt;sys/ptrace.h&gt;
  
  #define Error(msg) do { perror(msg); exit(0); } while(0)
  #define PTRACE_E(req, pid, addr, data) \
      do { \
          if(ptrace(req, pid, addr, data) &lt; 0) { \
              perror(#req); \
              exit(0); \
          } \
      } while(0)
  #define BUF_SIZE 16
  
  int main(int argc, char **argv) {
      pid_t pid;
      struct user_regs_struct regs;
      int status;
      char buf[BUF_SIZE];
  
      if (argc &lt; 2) {
          fprintf(stderr, "Usage: %s &lt;executable&gt; [ARGS]\n", argv[0]);
          exit(0);
      }
  
      pid = fork();
      if(pid &lt; 0) {
          Error("fork");
      } else if(pid == 0) {
          if(execv(argv[1], &amp;argv[1]) &lt; 0)
              Error("execv");
      }
  
      PTRACE_E(PTRACE_ATTACH, pid, NULL, NULL);
  
      while(wait(&amp;status) &amp;&amp; !WIFEXITED(status)) {
          PTRACE_E(PTRACE_GETREGS, pid, NULL, &amp;regs);
  
          if(regs.orig_eax == 26 &amp;&amp; regs.ebx == PTRACE_TRACEME) {
              regs.eax = 0;
  
              PTRACE_E(PTRACE_SETREGS, pid, NULL, &amp;regs);
              break;
          }
  
          PTRACE_E(PTRACE_SYSCALL, pid, NULL, NULL);
      }
  
      ptrace(PTRACE_DETACH, pid, NULL, NULL);
  
      snprintf(buf, BUF_SIZE, "%d", pid);
      execl("/usr/bin/gdb", "/usr/bin/gdb", "-p", buf, NULL);
  }
  </code></pre>