I am experiencing problems with ptrace() under FreeBSD. I made a simple
example program to demonstrate. All it does is fork a child process to
execl() a simple "hello world" program and ptrace() it with PT_CONTINUE.

 The first time around, everything is as it should be - the program is
executed and traced perfectly. However, when I attempt to repeat the whole
process, first by forking a completely new child to execute the helloworld
program again, I start getting ptrace() errors such as "Operation not
permitted" and "Device busy".

 Now the weird thing is, after the first trace, the program terminates
normally, and I print out the pid of the child process which should no
longer be running at this point. ptrace(PT_KILL) verifies this by
returning "No such process". However, during the pause between the first
and second ptrace, if I do a ps and search for the pid, it shows up in
memory as running in the background, although ptrace(PT_KILL) claims it
does not exist. Then my sample program attempts to trace the same
helloworld program again, and gets "Operation not permitted" - even though
an entirely new child is fork()'d with an entirely new pid - so it should
have absolutely no connection at all to the first trace. Does anyone know
why I can't ptrace() the same helloworld program a second time?

 I have attached my sample ptrace() program to this message. Thanks in
advance for any help

Patrick Alken
/*
 * To run this, make a prog.c which contains:
 * int main() { printf("hello world\n"); }
 * and compile it into the file "prog".
 *
 * Then, simply: gcc -o myptrace myptrace.c
 * and ./myptrace
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <sys/wait.h>
#include <machine/reg.h>
#include <unistd.h>
#include <string.h>

/*
DoTrace() - begin to trace a process
*/

int
DoTrace()

{
  int pid; /* child pid */
  int waitval;
        struct reg regs;

  pid = fork();
  switch (pid)
  {
    case -1:
    {
      perror("fork");
      break;
    }

    /*
     * Child
     */
    case 0:
    {
      /*
       * Allow parent to trace this child process
       */
      ptrace(PT_TRACE_ME, 0, 0, 0);
      
      /*
       * Execute program to be debugged and cause child to
       * send a signal to parent
       */
      execl("./prog", "prog", NULL);

      exit(0);
    }

    /*
     * Parent
     */
    default:
    {
      int pret;

      /* 
       * Wait for child to stop (execl)
       */
      wait(&waitval);

      printf("waitval = %d\n", waitval);

      /*
                         * Continue exection of process
                         */
                        pret = ptrace(PT_CONTINUE, pid, (caddr_t) 1, 0);
                        if (pret != 0)
                        {
                                /*
                                 * This is where it fails the second time with an
                                 * errno of 1 (EPERM), even though we are tracing
                                 * a completely new pid.
                                 */
                                perror("ptrace");
                        }

      wait(&waitval);

                        pret = ptrace(PT_KILL, pid, 0, 0);
                        if (pret == 0)
                        {
                                printf("Kill successful\n");
                                wait(&waitval);
                        }
                        else
                                printf("Kill unsuccessful, errno = %s\n", 
strerror(errno));
    }
  }

        return (pid);
} /* DoTrace() */

int
main()

{
  int pid;
        char buf[512];

  /*
         * Trace through the process
         */
        pid = DoTrace();
        printf("Pid1 = %d\n", pid);

        fgets(buf, 512, stdin);

        /*
         * Trace through again (this is where it fails)
         */
        pid = DoTrace();
        printf("Pid2 = %d\n", pid);

        return 0;
}

Reply via email to