blob: 4b4f6179b21287677f44cad7dd75bfb25d247c73 [file] [log] [blame]
/**********************************************************************
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 "kern_util.h"
#include "ptrace_user.h"
#include "tt.h"
#include "os.h"
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:
*/