First, start process B (see mt.cpp
below) , it will create a thread with pthread_create()
. The ppid
, pid
and tid
of main thread and the new thread will be outputted for process A, then both of them start a for loop and raise SIGTRAP
, which should be caught by waitpid()
in process A.
Second, start process A (see attach.cpp
below) with pid
of process B. Process A will attach to process B by ptrace(PTRACE_ATTACH, ...)
, then wait signal event using waitpid()
in while(true)
, call ptrace(PTRACE_CONT, ...)
if get a SIGTRAP
, or break the loop if get a SIGSTOP
.
Now is the problem:
Process A can catch the SIGTRAP
raised by main thread of process B and call ptrace(PTRACE_CONT, ...)
successfully, and then process B will continue to execute as expected.
BUT!!!
When the new thread of process B raised SIGTRAP
, process A failed to ptrace(PTRACE_CONT, ...)
with a errmsg
"No such process", because process B has core dumped with a errmsg
"Trace/breakpoint trap (core dumped)".
In addition, WIFSTOPPED(status)
turned to false and WIFSIGNALED(status)
turned to true.
I know the default action of SIGTRAP
is terminate the process, it seems that the SIGTRAP
was transfered to process A after the termination action, NOT before, so process A had no chance to continue process B.
I have tried gdb
instead of process A, both SIGTRAP
can be caught and continued successfully. So there must be something wrong in the code of process A.
Here is attach.cpp
executed as process A:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
pid_t pid = 0;
int ret = 0;
int status = 0;
if (argc > 1) {
pid = atoi(argv[1]);
printf("pid=%d\n", pid);
}
ret = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
printf("attach ret=%d\n", ret);
waitpid(pid, &status, 0);
ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
printf("cont ret=%d\n", ret);
while (true) {
ret = waitpid(pid, &status, WUNTRACED);
printf("\nwaitpid ret=%d.\n", ret);
int sig = 0;
if (WIFSIGNALED(status)) {
printf("WIFSIGNALED\n");
sig = WTERMSIG(status);
} else if (WIFSTOPPED(status)) {
printf("WIFSTOPPED\n");
sig = WSTOPSIG(status);
} else {
printf("other status %d\n", status);
}
if (SIGTRAP == sig) {
ret = ptrace(PTRACE_CONT, pid, NULL, NULL);
printf("SIGTRAP cont ret=%d err=%s\n", ret, strerror(errno));
} else if (SIGSTOP == sig) {
ret = ptrace(PTRACE_DETACH, pid, NULL, NULL);
printf("SIGSTOP detach ret=%d\n", ret);
break;
} else {
printf("other signal %d\n", sig);
}
sleep(2);
}
return 0;
}
Here is mt.cpp
executed as process B:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
void *func(void * arg)
{
printf("child ppid=%d pid=%d tid=%d\n", getppid(), getpid(), gettid());
int i = 0;
for (; i < 5; i++) {
printf("child loop i=%d\n", i);
sleep(2);
}
printf("\nchild before SIGTRAP\n", gettid());
raise(SIGTRAP);
printf("child after SIGTRAP\n\n", gettid());
for (; i < 8; i++) {
printf("child loop i=%d\n", i);
sleep(2);
}
return NULL;
}
int main(void)
{
printf("parent ppid=%d pid=%d tid=%d\n", getppid(), getpid(), gettid());
pthread_t tid;
pthread_create(&tid, NULL, func, NULL);
int i = 0;
for (; i < 3; i++) {
printf("parent loop i=%d\n", i);
sleep(2);
}
printf("\nparent before SIGTRAP\n", gettid());
raise(SIGTRAP);
printf("parent after SIGTRAP\n\n", gettid());
for (; i < 10; i++) {
printf("parent loop i=%d\n", i);
sleep(2);
}
pthread_join(tid, NULL);
return 0;
}
Here the result:
- if you want execute the two programs by yourself, be sure that process A (attach) should be started as soon as possible after start process B.
process B:
$ ./mt
parent ppid=12238 pid=30389 tid=30389
parent loop i=0
child ppid=12238 pid=30389 tid=30390
child loop i=0
parent loop i=1
child loop i=1
parent loop i=2
child loop i=2
parent before SIGTRAP
child loop i=3
parent after SIGTRAP
parent loop i=3
child loop i=4
parent loop i=4
child before SIGTRAP
Trace/breakpoint trap (core dumped)
process A:
$ ./attach 30389
pid=30389
attach ret=0
cont ret=0
waitpid ret=30389.
WIFSTOPPED
SIGTRAP cont ret=0 err=Success
waitpid ret=30389.
WIFSIGNALED
SIGTRAP cont ret=-1 err=No such process
^C