Im fairly certain of what WIFEXITED and WIFSIGNALED are and how they work. I dont know why its not working since the program does a segfault, and I can very well see(debugged) that that signal on the third while iteration is a SEGFAULT. Thanks for any info.
segfault_prog
#include <stdlib.h>
#include <stdio.h>
int main() {
int *i = 0x478734;
printf("%d", *i);
}
int main(void) {
int status;
int ret = fork();
if (ret == 0) {
ptrace(PTRACE_TRACEME, ret, NULL, NULL);
raise(SIGSTOP);
execve(argv[1], &argv[1], NULL);
return 1;
}
else {
while (1) {
pid_t val = waitpid(ret, &status, 0);
ptrace(PTRACE_SETOPTIONS, ret, 0,PTRACE_O_EXITKILL | PTRACE_O_TRACEEXEC);
if (WIFEXITED(status) && val == ret){
printf("exited normally");
return WEXITSTATUS (status);
}
else if (WIFSIGNALED(status)){
//if I change for WEXITSTATUS(status) == SIGSEGV. then it works. First while iteration wIFEXITVAL(SIGSTOP/19), 2nd (SIGTRAP/5), 3rd (SIGSEGV 11);
printf("signal error");
return WEXITSTATUS (status);
}
ptrace(PTRACE_CONT, val, 0, 0);
}
}
return (0);
}
CodePudding user response:
A few issues ...
When tracee/child is stopped (i.e. WIFSTOPPED), the signal (i.e. WSTOPSIG) must be sent down to the tracee. This is the last arg for
PTRACE_CONT
Doing
PTRACE_SETOPTIONS
is only needed after the firstwaitpid
waitpid
should have a first arg of-1
to catch all children
By not sending the signal down via the PTRACE_CONT
[AFAICT], the signal is deferred [until the tracer elects to send it down]. So, the tracee/child generated the signal but it was never sent to the tracee/child.
Also, as I mentioned, you may want to have a look at my recent answer: ptrace options not working in parent process
Here is the refactored code. It is annotated with the bugs and fixes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
int
main(int argc,char **argv)
{
int status;
int ret = fork();
if (ret == 0) {
ptrace(PTRACE_TRACEME, ret, NULL, NULL);
// NOTE/BUG: not needed
#if 0
raise(SIGSTOP);
#endif
execve(argv[1], &argv[1], NULL);
#if 0
return 1;
#else
exit(1);
#endif
}
#if TEST
int iter = 20;
#else
int iter = 0x7FFFFFFF;
#endif
int first = 1;
for (; iter > 0; --iter) {
// NOTE/BUG: we should catch all children (tracee might do fork but not wait
// and orphan/zombie its child (our grandchild) and we'd want to see that)
#if 0
pid_t val = waitpid(ret, &status, 0);
#else
pid_t val = waitpid(-1, &status, 0);
#endif
#if 1
if (first) {
ptrace(PTRACE_SETOPTIONS, ret, 0,
PTRACE_O_EXITKILL | PTRACE_O_TRACEEXEC);
first = 0;
}
#endif
printf("pt: status=%8.8X\n",status);
int signo = 0;
if (WIFEXITED(status)) {
printf("pt: WIFEXITED %d\n",WEXITSTATUS(status));
}
if (WIFSTOPPED(status)) {
signo = WSTOPSIG(status);
printf("pt: WIFSTOPPED %d\n",signo);
if (signo == SIGTRAP)
signo = 0;
}
if (WIFSIGNALED(status)) {
printf("pt: WIFSIGNALED %d\n",WTERMSIG(status));
}
if (WIFEXITED(status) && val == ret) {
printf("exited normally");
return WEXITSTATUS(status);
}
else if (WIFSIGNALED(status)) {
// if I change for WEXITSTATUS(status) == SIGSEGV. then it works.
// First while iteration wIFEXITVAL(SIGSTOP/19), 2nd (SIGTRAP/5),
// 3rd (SIGSEGV 11);
#if 0
printf("signal error");
#else
printf("signal error -- %d\n",WTERMSIG(status));
#endif
return WEXITSTATUS(status);
}
// NOTE/BUG: must send signo from WIFSTOPPED/WSTOPSIG to tracee
#if SHOWBUG
ptrace(PTRACE_CONT, val, 0, 0);
#else
ptrace(PTRACE_CONT, val, 0, signo);
#endif
}
if (iter <= 0)
printf("pt: fault -- not seen\n");
return (0);
}
In the above code, I've used cpp
conditionals to denote old vs new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Here is the original behavior (compiled with -DTEST -DSHOWBUG
):
pt: status=0000057F
pt: WIFSTOPPED 5
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: fault -- not seen
Here is the output with the fix:
pt: status=0000057F
pt: WIFSTOPPED 5
pt: status=00000B7F
pt: WIFSTOPPED 11
pt: status=0000008B
pt: WIFSIGNALED 11
signal error -- 11