Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
10
arch/um/kernel/tt/ptproxy/Makefile
Normal file
10
arch/um/kernel/tt/ptproxy/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
obj-y = proxy.o ptrace.o sysdep.o wait.o
|
||||
|
||||
USER_OBJS := $(obj-y)
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
377
arch/um/kernel/tt/ptproxy/proxy.c
Normal file
377
arch/um/kernel/tt/ptproxy/proxy.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/**********************************************************************
|
||||
proxy.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
|
||||
**********************************************************************/
|
||||
|
||||
/* XXX This file shouldn't refer to CONFIG_* */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <asm/unistd.h>
|
||||
#include "ptrace_user.h"
|
||||
|
||||
#include "ptproxy.h"
|
||||
#include "sysdep.h"
|
||||
#include "wait.h"
|
||||
|
||||
#include "user_util.h"
|
||||
#include "user.h"
|
||||
#include "os.h"
|
||||
#include "tempfile.h"
|
||||
|
||||
static int debugger_wait(debugger_state *debugger, int *status, int options,
|
||||
int (*syscall)(debugger_state *debugger, pid_t child),
|
||||
int (*normal_return)(debugger_state *debugger,
|
||||
pid_t unused),
|
||||
int (*wait_return)(debugger_state *debugger,
|
||||
pid_t unused))
|
||||
{
|
||||
if(debugger->real_wait){
|
||||
debugger->handle_trace = normal_return;
|
||||
syscall_continue(debugger->pid);
|
||||
debugger->real_wait = 0;
|
||||
return(1);
|
||||
}
|
||||
debugger->wait_status_ptr = status;
|
||||
debugger->wait_options = options;
|
||||
if((debugger->debugee != NULL) && debugger->debugee->event){
|
||||
syscall_continue(debugger->pid);
|
||||
wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL,
|
||||
NULL);
|
||||
(*wait_return)(debugger, -1);
|
||||
return(0);
|
||||
}
|
||||
else if(debugger->wait_options & WNOHANG){
|
||||
syscall_cancel(debugger->pid, 0);
|
||||
debugger->handle_trace = syscall;
|
||||
return(0);
|
||||
}
|
||||
else {
|
||||
syscall_pause(debugger->pid);
|
||||
debugger->handle_trace = wait_return;
|
||||
debugger->waiting = 1;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle debugger trap, i.e. syscall.
|
||||
*/
|
||||
|
||||
int debugger_syscall(debugger_state *debugger, pid_t child)
|
||||
{
|
||||
long arg1, arg2, arg3, arg4, arg5, result;
|
||||
int syscall, ret = 0;
|
||||
|
||||
syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4,
|
||||
&arg5);
|
||||
|
||||
switch(syscall){
|
||||
case __NR_execve:
|
||||
/* execve never returns */
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
break;
|
||||
|
||||
case __NR_ptrace:
|
||||
if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid;
|
||||
if(!debugger->debugee->in_context)
|
||||
child = debugger->debugee->pid;
|
||||
result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child,
|
||||
&ret);
|
||||
syscall_cancel(debugger->pid, result);
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
return(ret);
|
||||
|
||||
#ifdef __NR_waitpid
|
||||
case __NR_waitpid:
|
||||
#endif
|
||||
case __NR_wait4:
|
||||
if(!debugger_wait(debugger, (int *) arg2, arg3,
|
||||
debugger_syscall, debugger_normal_return,
|
||||
proxy_wait_return))
|
||||
return(0);
|
||||
break;
|
||||
|
||||
case __NR_kill:
|
||||
if(!debugger->debugee->in_context)
|
||||
child = debugger->debugee->pid;
|
||||
if(arg1 == debugger->debugee->pid){
|
||||
result = kill(child, arg2);
|
||||
syscall_cancel(debugger->pid, result);
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
return(0);
|
||||
}
|
||||
else debugger->handle_trace = debugger_normal_return;
|
||||
break;
|
||||
|
||||
default:
|
||||
debugger->handle_trace = debugger_normal_return;
|
||||
}
|
||||
|
||||
syscall_continue(debugger->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Used by the tracing thread */
|
||||
static debugger_state parent;
|
||||
static int parent_syscall(debugger_state *debugger, int pid);
|
||||
|
||||
int init_parent_proxy(int pid)
|
||||
{
|
||||
parent = ((debugger_state) { .pid = pid,
|
||||
.wait_options = 0,
|
||||
.wait_status_ptr = NULL,
|
||||
.waiting = 0,
|
||||
.real_wait = 0,
|
||||
.expecting_child = 0,
|
||||
.handle_trace = parent_syscall,
|
||||
.debugee = NULL } );
|
||||
return(0);
|
||||
}
|
||||
|
||||
int parent_normal_return(debugger_state *debugger, pid_t unused)
|
||||
{
|
||||
debugger->handle_trace = parent_syscall;
|
||||
syscall_continue(debugger->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int parent_syscall(debugger_state *debugger, int pid)
|
||||
{
|
||||
long arg1, arg2, arg3, arg4, arg5;
|
||||
int syscall;
|
||||
|
||||
syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5);
|
||||
|
||||
if((syscall == __NR_wait4)
|
||||
#ifdef __NR_waitpid
|
||||
|| (syscall == __NR_waitpid)
|
||||
#endif
|
||||
){
|
||||
debugger_wait(&parent, (int *) arg2, arg3, parent_syscall,
|
||||
parent_normal_return, parent_wait_return);
|
||||
}
|
||||
else ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int debugger_normal_return(debugger_state *debugger, pid_t unused)
|
||||
{
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
syscall_continue(debugger->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void debugger_cancelled_return(debugger_state *debugger, int result)
|
||||
{
|
||||
debugger->handle_trace = debugger_syscall;
|
||||
syscall_set_result(debugger->pid, result);
|
||||
syscall_continue(debugger->pid);
|
||||
}
|
||||
|
||||
/* Used by the tracing thread */
|
||||
static debugger_state debugger;
|
||||
static debugee_state debugee;
|
||||
|
||||
void init_proxy (pid_t debugger_pid, int stopped, int status)
|
||||
{
|
||||
debugger.pid = debugger_pid;
|
||||
debugger.handle_trace = debugger_syscall;
|
||||
debugger.debugee = &debugee;
|
||||
debugger.waiting = 0;
|
||||
debugger.real_wait = 0;
|
||||
debugger.expecting_child = 0;
|
||||
|
||||
debugee.pid = 0;
|
||||
debugee.traced = 0;
|
||||
debugee.stopped = stopped;
|
||||
debugee.event = 0;
|
||||
debugee.zombie = 0;
|
||||
debugee.died = 0;
|
||||
debugee.wait_status = status;
|
||||
debugee.in_context = 1;
|
||||
}
|
||||
|
||||
int debugger_proxy(int status, int pid)
|
||||
{
|
||||
int ret = 0, sig;
|
||||
|
||||
if(WIFSTOPPED(status)){
|
||||
sig = WSTOPSIG(status);
|
||||
if (sig == SIGTRAP)
|
||||
ret = (*debugger.handle_trace)(&debugger, pid);
|
||||
|
||||
else if(sig == SIGCHLD){
|
||||
if(debugger.expecting_child){
|
||||
ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
||||
debugger.expecting_child = 0;
|
||||
}
|
||||
else if(debugger.waiting)
|
||||
real_wait_return(&debugger);
|
||||
else {
|
||||
ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
||||
debugger.real_wait = 1;
|
||||
}
|
||||
}
|
||||
else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig);
|
||||
}
|
||||
else if(WIFEXITED(status)){
|
||||
tracer_panic("debugger (pid %d) exited with status %d",
|
||||
debugger.pid, WEXITSTATUS(status));
|
||||
}
|
||||
else if(WIFSIGNALED(status)){
|
||||
tracer_panic("debugger (pid %d) exited with signal %d",
|
||||
debugger.pid, WTERMSIG(status));
|
||||
}
|
||||
else {
|
||||
tracer_panic("proxy got unknown status (0x%x) on debugger "
|
||||
"(pid %d)", status, debugger.pid);
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void child_proxy(pid_t pid, int status)
|
||||
{
|
||||
debugee.event = 1;
|
||||
debugee.wait_status = status;
|
||||
|
||||
if(WIFSTOPPED(status)){
|
||||
debugee.stopped = 1;
|
||||
debugger.expecting_child = 1;
|
||||
kill(debugger.pid, SIGCHLD);
|
||||
}
|
||||
else if(WIFEXITED(status) || WIFSIGNALED(status)){
|
||||
debugee.zombie = 1;
|
||||
debugger.expecting_child = 1;
|
||||
kill(debugger.pid, SIGCHLD);
|
||||
}
|
||||
else panic("proxy got unknown status (0x%x) on child (pid %d)",
|
||||
status, pid);
|
||||
}
|
||||
|
||||
void debugger_parent_signal(int status, int pid)
|
||||
{
|
||||
int sig;
|
||||
|
||||
if(WIFSTOPPED(status)){
|
||||
sig = WSTOPSIG(status);
|
||||
if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid);
|
||||
else ptrace(PTRACE_SYSCALL, pid, 0, sig);
|
||||
}
|
||||
}
|
||||
|
||||
void fake_child_exit(void)
|
||||
{
|
||||
int status, pid;
|
||||
|
||||
child_proxy(1, W_EXITCODE(0, 0));
|
||||
while(debugger.waiting == 1){
|
||||
CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
|
||||
if(pid != debugger.pid){
|
||||
printk("fake_child_exit - waitpid failed, "
|
||||
"errno = %d\n", errno);
|
||||
return;
|
||||
}
|
||||
debugger_proxy(status, debugger.pid);
|
||||
}
|
||||
CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
|
||||
if(pid != debugger.pid){
|
||||
printk("fake_child_exit - waitpid failed, "
|
||||
"errno = %d\n", errno);
|
||||
return;
|
||||
}
|
||||
if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0)
|
||||
printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
|
||||
char gdb_init_string[] =
|
||||
"att 1 \n\
|
||||
b panic \n\
|
||||
b stop \n\
|
||||
handle SIGWINCH nostop noprint pass \n\
|
||||
";
|
||||
|
||||
int start_debugger(char *prog, int startup, int stop, int *fd_out)
|
||||
{
|
||||
int slave, child;
|
||||
|
||||
slave = open_gdb_chan();
|
||||
child = fork();
|
||||
if(child == 0){
|
||||
char *tempname = NULL;
|
||||
int fd;
|
||||
|
||||
if(setsid() < 0) perror("setsid");
|
||||
if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) ||
|
||||
(dup2(slave, 2) < 0)){
|
||||
printk("start_debugger : dup2 failed, errno = %d\n",
|
||||
errno);
|
||||
exit(1);
|
||||
}
|
||||
if(ioctl(0, TIOCSCTTY, 0) < 0){
|
||||
printk("start_debugger : TIOCSCTTY failed, "
|
||||
"errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
if(tcsetpgrp (1, os_getpid()) < 0){
|
||||
printk("start_debugger : tcsetpgrp failed, "
|
||||
"errno = %d\n", errno);
|
||||
#ifdef notdef
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
|
||||
if(fd < 0){
|
||||
printk("start_debugger : make_tempfile failed,"
|
||||
"err = %d\n", -fd);
|
||||
exit(1);
|
||||
}
|
||||
os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
|
||||
if(startup){
|
||||
if(stop){
|
||||
os_write_file(fd, "b start_kernel\n",
|
||||
strlen("b start_kernel\n"));
|
||||
}
|
||||
os_write_file(fd, "c\n", strlen("c\n"));
|
||||
}
|
||||
if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
|
||||
printk("start_debugger : PTRACE_TRACEME failed, "
|
||||
"errno = %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
execlp("gdb", "gdb", "--command", tempname, prog, NULL);
|
||||
printk("start_debugger : exec of gdb failed, errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
if(child < 0){
|
||||
printk("start_debugger : fork for gdb failed, errno = %d\n",
|
||||
errno);
|
||||
return(-1);
|
||||
}
|
||||
*fd_out = slave;
|
||||
return(child);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
61
arch/um/kernel/tt/ptproxy/ptproxy.h
Normal file
61
arch/um/kernel/tt/ptproxy/ptproxy.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/**********************************************************************
|
||||
ptproxy.h
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __PTPROXY_H
|
||||
#define __PTPROXY_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct debugger debugger_state;
|
||||
typedef struct debugee debugee_state;
|
||||
|
||||
struct debugger
|
||||
{
|
||||
pid_t pid;
|
||||
int wait_options;
|
||||
int *wait_status_ptr;
|
||||
unsigned int waiting : 1;
|
||||
unsigned int real_wait : 1;
|
||||
unsigned int expecting_child : 1;
|
||||
int (*handle_trace) (debugger_state *, pid_t);
|
||||
|
||||
debugee_state *debugee;
|
||||
};
|
||||
|
||||
struct debugee
|
||||
{
|
||||
pid_t pid;
|
||||
int wait_status;
|
||||
unsigned int died : 1;
|
||||
unsigned int event : 1;
|
||||
unsigned int stopped : 1;
|
||||
unsigned int trace_singlestep : 1;
|
||||
unsigned int trace_syscall : 1;
|
||||
unsigned int traced : 1;
|
||||
unsigned int zombie : 1;
|
||||
unsigned int in_context : 1;
|
||||
};
|
||||
|
||||
extern int debugger_syscall(debugger_state *debugger, pid_t pid);
|
||||
extern int debugger_normal_return (debugger_state *debugger, pid_t unused);
|
||||
|
||||
extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t,
|
||||
int *strace_out);
|
||||
extern void debugger_cancelled_return(debugger_state *debugger, int result);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
237
arch/um/kernel/tt/ptproxy/ptrace.c
Normal file
237
arch/um/kernel/tt/ptproxy/ptrace.c
Normal file
@@ -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:
|
||||
*/
|
70
arch/um/kernel/tt/ptproxy/sysdep.c
Normal file
70
arch/um/kernel/tt/ptproxy/sysdep.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/**********************************************************************
|
||||
sysdep.c
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/unistd.h>
|
||||
#include "ptrace_user.h"
|
||||
#include "user_util.h"
|
||||
#include "user.h"
|
||||
|
||||
int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4,
|
||||
long *arg5)
|
||||
{
|
||||
*arg1 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG1_OFFSET, 0);
|
||||
*arg2 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG2_OFFSET, 0);
|
||||
*arg3 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG3_OFFSET, 0);
|
||||
*arg4 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG4_OFFSET, 0);
|
||||
*arg5 = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_ARG5_OFFSET, 0);
|
||||
return(ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, 0));
|
||||
}
|
||||
|
||||
void syscall_cancel(pid_t pid, int result)
|
||||
{
|
||||
if((ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
|
||||
__NR_getpid) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ||
|
||||
(wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) ||
|
||||
(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0))
|
||||
printk("ptproxy: couldn't cancel syscall: errno = %d\n",
|
||||
errno);
|
||||
}
|
||||
|
||||
void syscall_set_result(pid_t pid, long result)
|
||||
{
|
||||
ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, result);
|
||||
}
|
||||
|
||||
void syscall_continue(pid_t pid)
|
||||
{
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
}
|
||||
|
||||
int syscall_pause(pid_t pid)
|
||||
{
|
||||
if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){
|
||||
printk("syscall_change - ptrace failed, errno = %d\n", errno);
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
25
arch/um/kernel/tt/ptproxy/sysdep.h
Normal file
25
arch/um/kernel/tt/ptproxy/sysdep.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**********************************************************************
|
||||
sysdep.h
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff.
|
||||
Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
||||
See the file COPYING for licensing terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3,
|
||||
long *arg4, long *arg5);
|
||||
extern void syscall_cancel (pid_t pid, long result);
|
||||
extern void syscall_set_result (pid_t pid, long result);
|
||||
extern void syscall_continue (pid_t pid);
|
||||
extern int syscall_pause(pid_t pid);
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
86
arch/um/kernel/tt/ptproxy/wait.c
Normal file
86
arch/um/kernel/tt/ptproxy/wait.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/**********************************************************************
|
||||
wait.c
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "ptproxy.h"
|
||||
#include "sysdep.h"
|
||||
#include "wait.h"
|
||||
#include "user_util.h"
|
||||
#include "ptrace_user.h"
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "sysdep/sigcontext.h"
|
||||
|
||||
int proxy_wait_return(struct debugger *debugger, pid_t unused)
|
||||
{
|
||||
debugger->waiting = 0;
|
||||
|
||||
if(debugger->debugee->died || (debugger->wait_options & __WCLONE)){
|
||||
debugger_cancelled_return(debugger, -ECHILD);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(debugger->debugee->zombie && debugger->debugee->event)
|
||||
debugger->debugee->died = 1;
|
||||
|
||||
if(debugger->debugee->event){
|
||||
debugger->debugee->event = 0;
|
||||
ptrace(PTRACE_POKEDATA, debugger->pid,
|
||||
debugger->wait_status_ptr,
|
||||
debugger->debugee->wait_status);
|
||||
/* if (wait4)
|
||||
ptrace (PTRACE_POKEDATA, pid, rusage_ptr, ...); */
|
||||
debugger_cancelled_return(debugger, debugger->debugee->pid);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* pause will return -EINTR, which happens to be right for wait */
|
||||
debugger_normal_return(debugger, -1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int parent_wait_return(struct debugger *debugger, pid_t unused)
|
||||
{
|
||||
return(debugger_normal_return(debugger, -1));
|
||||
}
|
||||
|
||||
int real_wait_return(struct debugger *debugger)
|
||||
{
|
||||
unsigned long ip;
|
||||
int pid;
|
||||
|
||||
pid = debugger->pid;
|
||||
|
||||
ip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
|
||||
IP_RESTART_SYSCALL(ip);
|
||||
|
||||
if(ptrace(PTRACE_POKEUSR, pid, PT_IP_OFFSET, ip) < 0)
|
||||
tracer_panic("real_wait_return : Failed to restart system "
|
||||
"call, errno = %d\n", errno);
|
||||
|
||||
if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
|
||||
(ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
|
||||
debugger_normal_return(debugger, -1))
|
||||
tracer_panic("real_wait_return : gdb failed to wait, "
|
||||
"errno = %d\n", errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
15
arch/um/kernel/tt/ptproxy/wait.h
Normal file
15
arch/um/kernel/tt/ptproxy/wait.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/**********************************************************************
|
||||
wait.h
|
||||
|
||||
Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing
|
||||
terms and conditions.
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __PTPROXY_WAIT_H
|
||||
#define __PTPROXY_WAIT_H
|
||||
|
||||
extern int proxy_wait_return(struct debugger *debugger, pid_t unused);
|
||||
extern int real_wait_return(struct debugger *debugger);
|
||||
extern int parent_wait_return(struct debugger *debugger, pid_t unused);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user