Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 18 Sep 2000 21:45:49 -0400 (EDT)
From:      Zhiui Zhang <zzhang@cs.binghamton.edu>
To:        Patrick Alken <cosine@ellipse.mcs.drexel.edu>
Cc:        freebsd-questions@FreeBSD.ORG
Subject:   Re: ptrace help 
Message-ID:  <Pine.SOL.4.21.0009182132580.13700-100000@opal>
In-Reply-To: <Pine.BSF.4.21.0009181838410.51465-200000@ellipse.mcs.drexel.edu>

next in thread | previous in thread | raw e-mail | index | archive | help


On Mon, 18 Sep 2000, Patrick Alken wrote:

>  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

First of all, I think this belongs to questions list not the hackers list.
I also think it is better not using attachment. Anyway, I spent some time
on your program which I copy below.  I think I find out the reason:

When a process being traced is run, it will sent a signal that is catched
by its parent.  When it exits, it will sent another SIGCHLD signal that
also needs to be catched. When I run your program, the waitval returned
are 1407 and 0.  Now, the second time you call DoTrace(), the wait() will
get the exiting status of the first child, which is 0.

In other words, the parent does NOT wait for the second child to stop and
goes ahead to execute ptrace(PT_CONTINUE,...). At this time, the second
child probably does not have a chance to run, to set its P_TRACED flag
and being stopped. Therefore, the ptrace(PT_CONTINUE,...) will fail.

You may be able to correct the problem by using waitpid() instead of
wait().  HTH.

-Zhihui

Your programs follows...

/* 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);  <-- problem here, which child do you want to
wait???

      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;
}



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.SOL.4.21.0009182132580.13700-100000>