ptrace single-stepping change breaks Wine

Davide Libenzi davidel at xmailserver.org
Wed Dec 29 19:13:57 CST 2004


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




More information about the wine-devel mailing list