summaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/tt/ptproxy/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/tt/ptproxy/ptrace.c')
-rw-r--r--arch/um/kernel/tt/ptproxy/ptrace.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
new file mode 100644
index 00000000000..528a5fc8d88
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -0,0 +1,237 @@
+/**********************************************************************
+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"
+
+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:
+ */