Search code examples
cunixptrace

ptrace_detach, SIGINT and trace/breakpoint trap (core dumped)


I'm trying to trace a program while it is running: with ptrace(PTRACE_ATTACH, ...), ptrace(PTRACE_SINGLESTEP, ...), etc..

Everything seems to be fine, but when I quit my tracing program with CTRL-C, I want to detach it (with PTRACE_DETACH) from the traced program and when I'm performing this action, the traced program crashes with the error Trace/BPT trap (core dumped).

My question is: how can I detach properly without making the traced program crash?

Here is the function that is catching the SIGINT signal:

void sig_int()
{
    if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1)
        my_perror("ptrace / DETACH", strerror(errno));
}

EDIT:

Here is some other code:

if ((ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) == -1))                                                                                                 
   my_perror("ptrace / SINGLESTEP", strerror(errno));
if (wait4(pid, &(l->status), 0, 0) == -1)
   my_perror("wait4", strerror(errno));
if (ptrace(PTRACE_GETREGS, pid, 0, &(l->reg)) == -1)
   my_perror("ptrace / GETREGS", strerror(errno));
if ((l->opcode = ptrace(PTRACE_PEEKTEXT, pid, l->reg.rip, NULL)) == -1)
   my_perror("ptrace / PEEKTEXT", strerror(errno));

This is the part of my loop where i do the first part of my tracing


Solution

  • OK my problem has been resolved here is the new function catching SIGINT:

    void            int_sig()
     {
      if (stop == 0)
        {
          printf("Interrupting!\n");
          ptrace(PTRACE_CONT, pid, NULL, NULL);
          exit(0);
        }
     }
    

    What is this new variable named 'stop' ?

    Well let's go backward in my code when i'm singlesteppin' and getregs the second time in a row just after knowing if my next singlestep was a syscall. I was doing that in order to get the return value of the syscall :

    void            do_step(t_list *l)                                                                                                                        
    {
      if ((ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) == -1))
       my_perror("ptrace / SINGLESTEP", strerror(errno));
      if (wait4(pid, &(l->status), 0, 0) == -1)
        my_perror("wait4", strerror(errno));
     if (ptrace(PTRACE_GETREGS, pid, 0, &(l->reg)) == -1)
      my_perror("ptrace / GETREGS", strerror(errno));
     if ((l->opcode = ptrace(PTRACE_PEEKTEXT, pid, l->reg.rip, NULL)) == -1)
       my_perror("ptrace / PEEKTEXT", strerror(errno));
    }
    
    void            do_next_step(t_list *l, t_strace *t)
     {
      stop = 1;
      if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) == -1 ||
          (wait4(pid, &(l->status), 0, 0) == -1))
         my_perror("ERROR", strerror(errno));
      if (!WIFSTOPPED(l->status) || WIFEXITED(l->status))
         {
           printf("?\n");
          exit(0);
        }
     if (ptrace(PTRACE_GETREGS, pid, 0, &(l->reg)) == -1)
       my_perror("ptrace / GETREGS", strerror(errno));
     if (t->ret == 1)
      printf("%d\n", (int)l->reg.rax);
       else
        printf("%#lx\n", l->reg.rax);
       stop = 0;
     }
    

    I have found out that if i was trying to interrupt my tracing program while i was in the do_next_step founction, this would crash the traced program!

    So i put a flag to skip the action in int_sig() if i was in the 'do_next_step' function!

    Hope that will be helpfull and / or interesting in the future !

    Thanks a lot for those who helped me all along this issue ! Cheers !!!