On Wed, 29 Dec 2004, Linus Torvalds wrote:
On Wed, 29 Dec 2004, Jesse Allen wrote:
So instead of removing the setting of TIF_SINGLESTEP in set_singlestep(), can you test whether removing the _testing_ of it in do_syscall_trace() makes things happier for you? Hmm?
Yes, doing that does work. But I still have to remove the conditional TF clear. Here's the diff now to show you.
Ok. That's a good piece of information.
I don't actually understand why do_syscall_trace() does that TIF_SINGLESTEP test in the first place, since the ptrace_notify() should happen as part of the _normal_ TIF_SINGLESTEP handling, afaiks. No apparent need to do it in syscall tracing, and do_syscall_trace() does that bogus fake signal sending.
Hmm.. That TF_SINGLESTEP test was added by Davide Libenzi in August, and I think Davide had some test for exactly this. Davide? Can you recall why you did this in the system call tracing code, rather than depend on the regular TIF_SINGLESTEP handling in arch/i386/kernel/signal.c: do_notify_resume()?
That test went in to be able to have ptrace single step, to see even the instruction following the #int instruction (this was the target of the patch itself). I just verified that, in 2.6.8 that does not have such test anymore, the single-step-after-int capability is lost. Below I inlining a simple test program (that I already sent you time ago) to test this. In my 2.6.8 I get this output:
waiting ... done: pid=21398 status=1407 sig=5 EIP=0x080485d5 waiting ... done: pid=21398 status=1407 sig=5 EIP=0x080485da waiting ... done: pid=21398 status=1407 sig=5 EIP=0x080485df waiting ... done: pid=21398 status=1407 sig=5 EIP=0x080485d5 waiting ... done: pid=21398 status=1407 sig=5 EIP=0x080485da waiting ... done: pid=21398 status=1407 sig=5 EIP=0x080485df
in front of this code:
80485d5: b8 14 00 00 00 mov $0x14,%eax 80485da: cd 80 int $0x80 80485dc: 89 45 ec mov %eax,0xffffffec(%ebp) 80485df: eb f4 jmp 80485d5 <main+0x85>
You can see that the "mov %eax,0xffffffec(%ebp)" instruction at 0x80485dc is not seen by ptrace single step. With the test in place, it will show up again in your traces.
- Davide
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <linux/user.h> #include <linux/unistd.h>
int main(int ac, char **av) { int i, status, res; long start, end; pid_t cpid, pid; struct user_regs_struct ur; struct sigaction sa;
sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigaction(SIGCHLD, &sa, NULL);
printf("nargs=%d\n", ac); if (ac == 1) goto tracer;
printf("arg=%s\n", av[1]); loop: __asm__ volatile ("int $0x80" : "=a" (res) : "0" (__NR_getpid)); goto loop; endloop: exit(0);
tracer: if ((cpid = fork()) != 0) goto parent;
printf("child=%d\n", getpid()); ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(av[0], av[0], "child", NULL);
exit(0);
parent: start = (long) &&loop; end = (long) &&endloop;
printf("pchild=%d\n", cpid);
for (;;) { pid = wait(&status); if (pid != cpid) continue; res = WSTOPSIG(status); if (ptrace(PTRACE_GETREGS, pid, NULL, &ur)) { printf("[%d] error: ptrace(PTRACE_GETREGS, %d)\n", pid, pid); return 1; }
if (ptrace(PTRACE_SINGLESTEP, pid, NULL, res != SIGTRAP ? res: 0)) { perror("ptrace(PTRACE_SINGLESTEP)"); return 1; }
if (ur.eip >= start && ur.eip <= end) break; }
for (i = 0; i < 15; i++) { printf("waiting ...\n"); pid = wait(&status); printf("done: pid=%d status=%d\n", pid, status); if (pid != cpid) continue; res = WSTOPSIG(status); printf("sig=%d\n", res); if (ptrace(PTRACE_GETREGS, pid, NULL, &ur)) { printf("[%d] error: ptrace(PTRACE_GETREGS, %d)\n", pid, pid); return 1; }
printf("EIP=0x%08x\n", ur.eip);
if (ptrace(PTRACE_SINGLESTEP, pid, NULL, res != SIGTRAP ? res: 0)) { perror("ptrace(PTRACE_SINGLESTEP)"); return 1; } }
if (ptrace(PTRACE_CONT, cpid, NULL, SIGKILL)) { perror("ptrace(PTRACE_SINGLESTEP)"); return 1; }
return 0; }