• Davide Libenzi's avatar
    [PATCH] ptrace single-stepping fix · 1e11a6c0
    Davide Libenzi authored
    This patch permits a ptrace process on x86 to "see" the instruction following
    the INT #80h op.  This has been tested on 2.6.6 using the appended test
    source.  Running over this:
    
    80485a9:       b8 14 00 00 00          mov    $0x14,%eax
    80485ae:       cd 80                   int    $0x80
    80485b0:       89 45 ec                mov    %eax,0xffffffec(%ebp)
    80485b3:       eb f4                   jmp    80485a9 <main+0x85>
    
    it produces:
    
    waiting ...
    done: pid=12387  status=1407
    sig=5
    EIP=0x080485a9
    waiting ...
    done: pid=12387  status=1407
    sig=5
    EIP=0x080485ae
    waiting ...
    done: pid=12387  status=1407
    sig=5
    EIP=0x080485b0
    waiting ...
    done: pid=12387  status=1407
    sig=5
    EIP=0x080485b3
    
    (Andi says: "I think this patch is a bad idea.  The ptrace handling is
    traditionally fragile (I remember when merging a rather simple patch from IBM
    for DR allocation long ago into the suse it broke several debuggers).  If you
    really want to do that wait for 2.7.")
    
    
    test-program.c:
    
    #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;
    }
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    1e11a6c0
ptrace.c 13.3 KB