tech-misc archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Problem with using PT_SYSCALL.



Hi!

  I've been experimenting with ptrace() and found out that simply following 
man (2) ptrace is not enough.

  The attached problem is supposed to run "/bin/ls /" and stop at every system 
call it makes. The problem is that ptrace(PT_SYSCALL,...) at the end of the 
main loop seems simply to resume the child and make it run until it exits, but 
not until it makes a system call.

  Attached program works as expected under FreeBSD and Linux, so I believe 
there is some detail that needs to be taken into account for NetBSD and that I 
have missed.

  Can you please give a hint how to correct this program?

-------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <errno.h>

#if defined(BSD)
        #define REQ_TRACE_ME    PT_TRACE_ME
        #define REQ_SYSCALL             PT_SYSCALL
        #define REQ_KILL                PT_KILL
        #define CONT_ADDR               (caddr_t)1
#elif defined(LINUX)
        #define REQ_TRACE_ME    PTRACE_TRACEME
        #define REQ_SYSCALL             PTRACE_SYSCALL
        #define REQ_KILL                PTRACE_KILL
        #define CONT_ADDR               NULL
#else
        #error "Define BSD or LINUX."
#endif

static void die(const char *msg)
{
        printf("%s, errno=%d\n",msg,errno);
        _exit(1);
}

static void child()
{
const char      *args[] =       {"/bin/ls","/",NULL};
const char      *env[]  =       {NULL};

        if(0>ptrace(REQ_TRACE_ME,0,NULL,0))
                die("failed to trace myself");
        
        execve(args[0],(char * const *)args,(char * const *)env);
        die("failed to start the child");
}

int main()
{
pid_t   p;
int             status;
int             sig;

        p=fork();
        if(p<0)
                die("failed to fork");
        
        if(!p)
                child();
        
        for(;;)
        {
                if(0>waitpid(p,&status,0))
                        die("failed to wait for child");
                if(WIFSTOPPED(status))
                {
                        sig=WSTOPSIG(status);
                        printf("child stopped by signal %d 
(%s)\n",sig,strsignal(sig));
                        if(sig!=SIGTRAP)
                        {
                                printf("signal is not SIGTRAP; killing 
child\n");
                                if(0>ptrace(REQ_KILL,p,NULL,0))
                                        die("failed to kill the child");
                                break;
                        }
                }
                else if(WIFSIGNALED(status))
                {
                        sig=WTERMSIG(status);
                        printf("child was signaled by signal %d (%d)\n",
                                sig,strsignal(sig));
                        if(0>ptrace(REQ_KILL,p,NULL,0))
                                die("failed to kill the child");
                        break;
                }
                else if(WIFEXITED(status))
                {
                        printf("child exited with status 
%d\n",WEXITSTATUS(status));
                        break;
                }
                else
                {
                        printf("neither stopped, nor signaled, nor killed?\n");
                        if(0>ptrace(PT_KILL,p,NULL,0))
                                die("failed to kill the child");
                        break;
                }
                
                printf("resuming the child\n");
                if(0>ptrace(REQ_SYSCALL,p,CONT_ADDR,0))
                        die("failed to resume the child");
        }
        
        return 0;
}


Home | Main Index | Thread Index | Old Index