From owner-freebsd-questions Mon Sep 18 18:46:14 2000 Delivered-To: freebsd-questions@freebsd.org Received: from bingnet2.cc.binghamton.edu (bingnet2.cc.binghamton.edu [128.226.1.18]) by hub.freebsd.org (Postfix) with ESMTP id C435B37B423 for ; Mon, 18 Sep 2000 18:46:09 -0700 (PDT) Received: from opal (cs.binghamton.edu [128.226.123.101]) by bingnet2.cc.binghamton.edu (8.9.3/8.9.3) with ESMTP id VAA27370; Mon, 18 Sep 2000 21:46:00 -0400 (EDT) Date: Mon, 18 Sep 2000 21:45:49 -0400 (EDT) From: Zhiui Zhang X-Sender: zzhang@opal To: Patrick Alken Cc: freebsd-questions@FreeBSD.ORG Subject: Re: ptrace help In-Reply-To: Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-questions@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG 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 #include #include #include #include #include #include #include /* 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