Basically, what I want to do is:
to trace a process,
to trace its child too, if the process forks a child,
and so on.
So first I have to find where the child process calls fork()(or vfork()
or clone()).
I want to use PTRACE_SETOPTIONS and set PTRACE_O_TRACEFORK option.
As my understanding, the traced process should be stopped by SIGTRAP
when it calls fork(), and the tracer should get the control of it, and
get its status with wait().
Unfortunately, ptrace() doesn't work as I thought.
So I wonder how I use ptrace() to do it.
My test code is below, and I want to use "tracer" to trace "traced".
Can anyone tell me which part is wrong?
---------------tracer.c----------------
#include <stdio.h>
#include <string.h>
#include <sys/ptrace.h>
#include <linux/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <asm-i486/ptrace.h> /* For constants
ORIG_EAX etc */
int main(int argc , char *argv[])
{
pid_t child;
if(argc != 2){
fprintf(stderr , "usage: %s program\n" , argv[0]);
return 1;
}
child = fork();
if(child == 0) {
sleep(1);
execl(argv[1] , argv[1] , NULL);
}
else {
int status;
long data=PTRACE_O_TRACEEXIT
|PTRACE_O_TRACEFORK
|PTRACE_O_TRACEVFORK
|PTRACE_O_TRACECLONE;
ptrace(PTRACE_ATTACH , child , NULL , NULL);
ptrace(PTRACE_SETOPTIONS , child , NULL , data);
while(1){
if(wait(&status) == -1){
perror("wait");
return 0;
}
printf("the child process stops. status: %d, signal? %d, "
"exit? %d, continue? %d, stop? %d\n" ,
WEXITSTATUS(status) , WIFSIGNALED(status) ,
WIFEXITED(status) , WIFCONTINUED(status) ,
WIFSTOPPED(status));
if(WSTOPSIG(status) == SIGTRAP){
if(status & (PTRACE_EVENT_EXIT << 8)){
printf("get the child process while it's exiting\n");
break;
}
else if(status & (PTRACE_EVENT_FORK << 8)){
printf("the child process fork a new process\n");
}
else if(status & (PTRACE_EVENT_VFORK << 8)){
printf("the child process vfork a new process\n");
}
else if(status & (PTRACE_EVENT_CLONE << 8)){
printf("the child process clone a new process\n");
}
}
if (ptrace(PTRACE_CONT, child, 0,
/*WSTOPSIG(status)*/SIGSTOP)) {
perror("stopper: ptrace(PTRACE_CONT, ...)");
return 1;
}
}
if (ptrace(PTRACE_CONT, child, 0, 0)) {
perror("stopper: ptrace(PTRACE_CONT, ...)");
return 1;
}
}
return 0;
}
-----------------traced.c---------------------
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
pid_t child=fork();
if(child){
printf("create a child %d\n" , child);
sleep(1);
}
else{
printf("I'm a child\n");
sleep(1);
}
}
best,
Zheng Da
--
Posted via a free Usenet account from http://www.teranews.com
Examine the source code to the utility program /usr/bin/strace .
See how strace handles its "-f" commandline option, which
"follows" all descendents.
--
What is the knowledge basis on which the strace utility was developed?
When I recommend people to look at the source code of how something else
achieves a goal, I generally try to find something that does just that in
a simple way. In the case of strace, it is a very large and complex code
that does a whole lot of stuff. That doesn't mean the solution cannot be
found within it's source code. It just means it can be harder to find.
If all of the handling of something like that is in one place, that might
make it easy. But some things in some programs end up with the way to do
something scattered about in the whole infrastructure of the program, and
that can be nearly impossible to see, especially given the poor level of
commenting most open source has (comments more intended to remind the
programmer what a strange piece of code is doing, rather than explain to
the general reader what everything is doing). I have not specically
looked at the strace source, so it might be one of the few exceptions to
to the wide rule I have seen.
It would still be helpful for documents that explain how something is to
be used, rather than depend on the source code of something else. In the
above case, it is obvious that strace will have to ptrace the child when
the -f option is in effect. But a correct document will generally be the
better way, even if it is a book to buy. Where did the strace writers
learn?
--
|---------------------------------------/----------------------------------|
| Phil Howard KA9WGN (ka9wgn.ham.org) / Do not send to the address below |
| first name lower case at ipal.net / spamtrap-200...@ipal.net |
|------------------------------------/-------------------------------------|
Hi,
The code of strace is quite complex because it supports so many
different systems.
As my understanding, I think strace traces every system calls.
In this case, strace can get the pid of the new process.
But I don't want to do it in this way because I don't need to trace
every system call. What I need to trace is when the process forks a new
process and exits.
Are there any better ways?
> The code of strace is quite complex because it supports so many
> different systems.
But the tools "grep" etc. are quite powerful at ignoring what is
not important. In this case, find all the PTRACE_* symbols,
and the code that handles the "-f" commandline option (so the
source probably contains
case 'f':
or something analogous.)
> As my understanding, I think strace traces every system calls.
> In this case, strace can get the pid of the new process.
> But I don't want to do it in this way because I don't need to trace
> every system call. What I need to trace is when the process forks a new
> process and exits.
> Are there any better ways?
No, not if you insist on complete coverage and full generality.
Any system call can be written in line, or generated
dynamically at runtime, in such a way that the only method(s)
of detecting it are instruction-by-instruction emulation, or
system_call-by-system_call tracing using ptrace().
_If_ you are certain that the application always calls an external
library subroutine to perform fork(), then you can intercept the
external linkage. Many times this can be done using the LD_PRELOAD
environment variable, but [other] use(r)s of LD_PRELOAD may not
have made provision for co-operative co-existence.
--
If you ptrace the fork and related calls, you get to know the new PID.
The catch is making sure that child process cannot run until your program
can start ptracing it as well. If that much can be isolated from strace
then you might have your solution.
"man ptrace" shows some things to look for. Specifically, some options
like PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK, and PTRACE_O_TRACECLONE,
that will SIGSTOP the child of the fork.
I know about these syscalls/options, but I have never used them. I am
considering using them for a coming project (there are some other ways
possible to achieve the goals of the project, so using ptrace is not a
certainty). If something is not working, I cannot say why. I suggest
actually stracing your code that is calling ptrace. Since I can strace
the strace program itself, I assume this can work for your program.