Re: ptrace single-stepping change breaks Wine

Davide Libenzi
2005-01-01T22:04:29Z

On Fri, 31 Dec 2004, Linus Torvalds wrote:

>
>
> On Fri, 31 Dec 2004, Davide Libenzi wrote:
> >
> > I don't think Linus ever posted a POPF-only patch. Try to comment those
> > lines in his POPF patch ...
>
> Here the two patches are independently, if people want to take a look.
>
> If somebody wants to split (and test) the TF-careful thing further (the
> "send_sigtrap()" changes are independent, I think), that would be
> wonderful... Hint hint.

I used the test program below on 2.4.27, 2.6.8.1 and latest BK + TF-careful.
In all cases single stepping over POPF succeeded. In the 2.4.27 and 2.6.8.1
cases, we lost the instruction following "int $0x80" (since 2.6.8.1
removed the test I put in do_syscall_trace()). The latest BK plus TF-careful
gets things right WRT single-step-after-syscall case. What was your test
case about non-working single step over POPF?

- 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>

#define INEXT(i, n) ((i + 1) % n)

int main(int ac, char **av) {
int i, nins, miss, status, res;
long start, end;
long inss[32];
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);

if (ac > 1) {
fprintf(stderr, "tracee child: pid=%d\n", getpid());

loop:
l0:
__asm__ volatile ("mov %0, %%eax\n\t":: "I" (__NR_getpid));
l1:
__asm__ volatile ("int $0x80\n\t");
l2:
__asm__ volatile ("xor %eax, %eax\n\t");
l3:
__asm__ volatile ("pushf\n\t");
l4:
__asm__ volatile ("pop %eax\n\t");
l5:
__asm__ volatile ("orl $0x100, %eax\n\t");
l6:
__asm__ volatile ("push %eax\n\t");
l7:
__asm__ volatile ("popf\n\t");
l8:
__asm__ volatile ("xor %eax, %eax\n\t");
l9:
goto loop;
endloop:
exit(0);
}

if ((cpid = fork()) == 0) {
fprintf(stderr, "tracee: pid=%d\n", getpid());
ptrace(PTRACE_TRACEME, 0, NULL, NULL);

execl(av[0], av[0], "child", NULL);
exit(1);
}

start = (long) &&loop;
end = (long) &&endloop;
nins = 0;
inss[nins++] = (long) &&l0;
inss[nins++] = (long) &&l1;
inss[nins++] = (long) &&l2;
inss[nins++] = (long) &&l3;
inss[nins++] = (long) &&l4;
inss[nins++] = (long) &&l5;
inss[nins++] = (long) &&l6;
inss[nins++] = (long) &&l7;
inss[nins++] = (long) &&l8;
inss[nins++] = (long) &&l9;

fprintf(stderr, "tracer: child=%d\n", cpid);

for (;;) {
pid = wait(&status);
if (pid != cpid)
continue;
res = WSTOPSIG(status);
if (ptrace(PTRACE_GETREGS, pid, NULL, &ur)) {
perror("ptrace(PTRACE_GETREGS)");
return 1;
}

if (ptrace(PTRACE_SINGLESTEP, pid, NULL, res != SIGTRAP ? res: 0)) {
perror("ptrace(PTRACE_SINGLESTEP)");
return 1;
}

if (ur.eip == start)
break;
}
fprintf(stdout, "EIP=0x%08x (0)\n", ur.eip);
for (i = 1;;) {
fprintf(stderr, "waiting ...\n");
pid = wait(&status);
fprintf(stderr, "done: pid=%d status=0x%08x (%d)\n",
pid, status, status);
if (pid != cpid)
continue;
res = WSTOPSIG(status);
fprintf(stderr, "sig=%d\n", res);
if (ptrace(PTRACE_GETREGS, pid, NULL, &ur)) {
perror("ptrace(PTRACE_GETREGS)");
return 1;
}
for (miss = 0; miss < nins && inss[i] != ur.eip; miss++) {
fprintf(stderr, "missed ins at 0x%08x (%d)\n", inss[i], i);
i = INEXT(i, nins);
}
if (miss == nins) {
fprintf(stderr, "EIP=0x%08x - lost contact with apollo-%d\n",
ur.eip, cpid);
break;
}
fprintf(stdout, "EIP=0x%08x (%d)\n", ur.eip, i);
i = INEXT(i, nins);
if (ur.eip == start)
break;

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_CONT)");
return 1;
}

return 0;
}