2005-04-17 06:20:36 +08:00
|
|
|
/**********************************************************************
|
|
|
|
ptrace.c
|
|
|
|
|
|
|
|
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
|
|
|
terms and conditions.
|
|
|
|
|
|
|
|
Jeff Dike (jdike@karaya.com) : Modified for integration into uml
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
|
|
#include "ptproxy.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "user_util.h"
|
|
|
|
#include "kern_util.h"
|
|
|
|
#include "ptrace_user.h"
|
|
|
|
#include "tt.h"
|
2006-01-19 09:42:41 +08:00
|
|
|
#include "os.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2,
|
|
|
|
long arg3, long arg4, pid_t child, int *ret)
|
|
|
|
{
|
|
|
|
sigset_t relay;
|
|
|
|
long result;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
*ret = 0;
|
|
|
|
if(debugger->debugee->died) return(-ESRCH);
|
|
|
|
|
|
|
|
switch(arg1){
|
|
|
|
case PTRACE_ATTACH:
|
|
|
|
if(debugger->debugee->traced) return(-EPERM);
|
|
|
|
|
|
|
|
debugger->debugee->pid = arg2;
|
|
|
|
debugger->debugee->traced = 1;
|
|
|
|
|
|
|
|
if(is_valid_pid(arg2) && (arg2 != child)){
|
|
|
|
debugger->debugee->in_context = 0;
|
|
|
|
kill(arg2, SIGSTOP);
|
|
|
|
debugger->debugee->event = 1;
|
|
|
|
debugger->debugee->wait_status = W_STOPCODE(SIGSTOP);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
debugger->debugee->in_context = 1;
|
|
|
|
if(debugger->debugee->stopped)
|
|
|
|
child_proxy(child, W_STOPCODE(SIGSTOP));
|
|
|
|
else kill(child, SIGSTOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
case PTRACE_DETACH:
|
|
|
|
if(!debugger->debugee->traced) return(-EPERM);
|
|
|
|
|
|
|
|
debugger->debugee->traced = 0;
|
|
|
|
debugger->debugee->pid = 0;
|
|
|
|
if(!debugger->debugee->in_context)
|
|
|
|
kill(child, SIGCONT);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
case PTRACE_CONT:
|
|
|
|
if(!debugger->debugee->in_context) return(-EPERM);
|
|
|
|
*ret = PTRACE_CONT;
|
|
|
|
return(ptrace(PTRACE_CONT, child, arg3, arg4));
|
|
|
|
|
|
|
|
#ifdef UM_HAVE_GETFPREGS
|
|
|
|
case PTRACE_GETFPREGS:
|
|
|
|
{
|
|
|
|
long regs[FP_FRAME_SIZE];
|
|
|
|
int i, result;
|
|
|
|
|
|
|
|
result = ptrace(PTRACE_GETFPREGS, child, 0, regs);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
|
|
ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
|
|
|
|
regs[i]);
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UM_HAVE_GETFPXREGS
|
|
|
|
case PTRACE_GETFPXREGS:
|
|
|
|
{
|
|
|
|
long regs[FPX_FRAME_SIZE];
|
|
|
|
int i, result;
|
|
|
|
|
|
|
|
result = ptrace(PTRACE_GETFPXREGS, child, 0, regs);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
|
|
ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i,
|
|
|
|
regs[i]);
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UM_HAVE_GETREGS
|
|
|
|
case PTRACE_GETREGS:
|
|
|
|
{
|
|
|
|
long regs[FRAME_SIZE];
|
|
|
|
int i, result;
|
|
|
|
|
|
|
|
result = ptrace(PTRACE_GETREGS, child, 0, regs);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
|
|
ptrace (PTRACE_POKEDATA, debugger->pid,
|
|
|
|
arg4 + 4 * i, regs[i]);
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case PTRACE_KILL:
|
|
|
|
result = ptrace(PTRACE_KILL, child, arg3, arg4);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
|
|
|
|
case PTRACE_PEEKDATA:
|
|
|
|
case PTRACE_PEEKTEXT:
|
|
|
|
case PTRACE_PEEKUSR:
|
|
|
|
/* The value being read out could be -1, so we have to
|
|
|
|
* check errno to see if there's an error, and zero it
|
|
|
|
* beforehand so we're not faked out by an old error
|
|
|
|
*/
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
result = ptrace(arg1, child, arg3, 0);
|
|
|
|
if((result == -1) && (errno != 0)) return(-errno);
|
|
|
|
|
|
|
|
result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
|
|
|
|
case PTRACE_POKEDATA:
|
|
|
|
case PTRACE_POKETEXT:
|
|
|
|
case PTRACE_POKEUSR:
|
|
|
|
result = ptrace(arg1, child, arg3, arg4);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
if(arg1 == PTRACE_POKEUSR) ptrace_pokeuser(arg3, arg4);
|
|
|
|
return(result);
|
|
|
|
|
|
|
|
#ifdef UM_HAVE_SETFPREGS
|
|
|
|
case PTRACE_SETFPREGS:
|
|
|
|
{
|
|
|
|
long regs[FP_FRAME_SIZE];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
|
|
regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
|
|
|
|
arg4 + 4 * i, 0);
|
|
|
|
result = ptrace(PTRACE_SETFPREGS, child, 0, regs);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UM_HAVE_SETFPXREGS
|
|
|
|
case PTRACE_SETFPXREGS:
|
|
|
|
{
|
|
|
|
long regs[FPX_FRAME_SIZE];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
|
|
regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid,
|
|
|
|
arg4 + 4 * i, 0);
|
|
|
|
result = ptrace(PTRACE_SETFPXREGS, child, 0, regs);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UM_HAVE_SETREGS
|
|
|
|
case PTRACE_SETREGS:
|
|
|
|
{
|
|
|
|
long regs[FRAME_SIZE];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++)
|
|
|
|
regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid,
|
|
|
|
arg4 + 4 * i, 0);
|
|
|
|
result = ptrace(PTRACE_SETREGS, child, 0, regs);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case PTRACE_SINGLESTEP:
|
|
|
|
if(!debugger->debugee->in_context) return(-EPERM);
|
|
|
|
sigemptyset(&relay);
|
|
|
|
sigaddset(&relay, SIGSEGV);
|
|
|
|
sigaddset(&relay, SIGILL);
|
|
|
|
sigaddset(&relay, SIGBUS);
|
|
|
|
result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP,
|
|
|
|
&relay);
|
|
|
|
child_proxy(child, status);
|
|
|
|
return(result);
|
|
|
|
|
|
|
|
case PTRACE_SYSCALL:
|
|
|
|
if(!debugger->debugee->in_context) return(-EPERM);
|
|
|
|
result = ptrace(PTRACE_SYSCALL, child, arg3, arg4);
|
|
|
|
if(result == -1) return(-errno);
|
|
|
|
|
|
|
|
*ret = PTRACE_SYSCALL;
|
|
|
|
return(result);
|
|
|
|
|
|
|
|
case PTRACE_TRACEME:
|
|
|
|
default:
|
|
|
|
return(-EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Overrides for Emacs so that we follow Linus's tabbing style.
|
|
|
|
* Emacs will notice this stuff at the end of the file and automatically
|
|
|
|
* adjust the settings for this buffer only. This must remain at the end
|
|
|
|
* of the file.
|
|
|
|
* ---------------------------------------------------------------------------
|
|
|
|
* Local variables:
|
|
|
|
* c-file-style: "linux"
|
|
|
|
* End:
|
|
|
|
*/
|