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!
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
new file mode 100644
index 0000000..3d5177d
--- /dev/null
+++ b/arch/um/kernel/tt/Makefile
@@ -0,0 +1,28 @@
+# 
+# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+# Licensed under the GPL
+#
+
+extra-y := unmap_fin.o
+clean-files := unmap_tmp.o
+
+obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
+	syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
+	uaccess.o uaccess_user.o
+
+obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
+
+USER_OBJS := gdb.o time.o tracer.o
+
+include arch/um/scripts/Makefile.rules
+
+UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
+UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
+
+#XXX: partially copied from arch/um/scripts/Makefile.rules
+$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
+
+$(obj)/unmap_fin.o : $(obj)/unmap.o
+	$(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
+	$(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
+
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
new file mode 100644
index 0000000..065b504
--- /dev/null
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -0,0 +1,87 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/mm.h"
+#include "asm/signal.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/pgalloc.h"
+#include "asm/tlbflush.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "irq_user.h"
+#include "time_user.h"
+#include "signal_user.h"
+#include "mem_user.h"
+#include "os.h"
+#include "tlb.h"
+#include "mode.h"
+
+static int exec_tramp(void *sig_stack)
+{
+	init_new_thread_stack(sig_stack, NULL);
+	init_new_thread_signals(1);
+	os_stop_process(os_getpid());
+	return(0);
+}
+
+void flush_thread_tt(void)
+{
+	unsigned long stack;
+	int new_pid;
+
+	stack = alloc_stack(0, 0);
+	if(stack == 0){
+		printk(KERN_ERR 
+		       "flush_thread : failed to allocate temporary stack\n");
+		do_exit(SIGKILL);
+	}
+		
+	new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp);
+	if(new_pid < 0){
+		printk(KERN_ERR 
+		       "flush_thread : new thread failed, errno = %d\n",
+		       -new_pid);
+		do_exit(SIGKILL);
+	}
+
+	if(current_thread->cpu == 0)
+		forward_interrupts(new_pid);
+	current->thread.request.op = OP_EXEC;
+	current->thread.request.u.exec.pid = new_pid;
+	unprotect_stack((unsigned long) current_thread);
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+
+	change_sig(SIGUSR1, 0);
+	enable_timer();
+	free_page(stack);
+	protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+	task_protections((unsigned long) current_thread);
+	force_flush_all();
+	unblock_signals();
+}
+
+void start_thread_tt(struct pt_regs *regs, unsigned long eip, 
+		     unsigned long esp)
+{
+	set_fs(USER_DS);
+	flush_tlb_mm(current->mm);
+	PT_REGS_IP(regs) = eip;
+	PT_REGS_SP(regs) = esp;
+	PT_FIX_EXEC_STACK(esp);
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
new file mode 100644
index 0000000..a92c02f
--- /dev/null
+++ b/arch/um/kernel/tt/exec_user.c
@@ -0,0 +1,57 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include "user_util.h"
+#include "kern_util.h"
+#include "user.h"
+#include "ptrace_user.h"
+#include "os.h"
+
+void do_exec(int old_pid, int new_pid)
+{
+	unsigned long regs[FRAME_SIZE];
+	int err;
+
+	if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
+		tracer_panic("do_exec failed to attach proc - errno = %d",
+			     errno);
+
+	CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
+	if (err < 0)
+		tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
+			     errno);
+
+	if(ptrace_getregs(old_pid, regs) < 0)
+		tracer_panic("do_exec failed to get registers - errno = %d",
+			     errno);
+
+	os_kill_ptraced_process(old_pid, 0);
+
+	if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno);
+
+	if(ptrace_setregs(new_pid, regs) < 0)
+		tracer_panic("do_exec failed to start new proc - errno = %d",
+			     errno);
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
new file mode 100644
index 0000000..19a0ad7
--- /dev/null
+++ b/arch/um/kernel/tt/gdb.c
@@ -0,0 +1,278 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include "ptrace_user.h"
+#include "uml-config.h"
+#include "kern_constants.h"
+#include "chan_user.h"
+#include "init.h"
+#include "user.h"
+#include "debug.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "tt.h"
+#include "sysdep/thread.h"
+
+extern int debugger_pid;
+extern int debugger_fd;
+extern int debugger_parent;
+
+int detach(int pid, int sig)
+{
+	return(ptrace(PTRACE_DETACH, pid, 0, sig));
+}
+
+int attach(int pid)
+{
+	int err;
+
+	err = ptrace(PTRACE_ATTACH, pid, 0, 0);
+	if(err < 0) return(-errno);
+	else return(err);
+}
+
+int cont(int pid)
+{
+	return(ptrace(PTRACE_CONT, pid, 0, 0));
+}
+
+#ifdef UML_CONFIG_PT_PROXY
+
+int debugger_signal(int status, pid_t pid)
+{
+	return(debugger_proxy(status, pid));
+}
+
+void child_signal(pid_t pid, int status)
+{
+	child_proxy(pid, status);
+}
+
+static void gdb_announce(char *dev_name, int dev)
+{
+	printf("gdb assigned device '%s'\n", dev_name);
+}
+
+static struct chan_opts opts = {
+	.announce  	= gdb_announce,
+	.xterm_title 	= "UML kernel debugger",
+	.raw 		= 0,
+	.tramp_stack 	= 0,
+	.in_kernel  	= 0,
+};
+
+/* Accessed by the tracing thread, which automatically serializes access */
+static void *xterm_data;
+static int xterm_fd;
+
+extern void *xterm_init(char *, int, struct chan_opts *);
+extern int xterm_open(int, int, int, void *, char **);
+extern void xterm_close(int, void *);
+
+int open_gdb_chan(void)
+{
+	char stack[UM_KERN_PAGE_SIZE], *dummy;
+
+	opts.tramp_stack = (unsigned long) stack;
+	xterm_data = xterm_init("", 0, &opts);
+	xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy);
+	return(xterm_fd);
+}
+
+static void exit_debugger_cb(void *unused)
+{
+	if(debugger_pid != -1){
+		if(gdb_pid != -1){
+			fake_child_exit();
+			gdb_pid = -1;
+		}
+		else kill_child_dead(debugger_pid);
+		debugger_pid = -1;
+		if(debugger_parent != -1)
+			detach(debugger_parent, SIGINT);
+	}
+	if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data);
+}
+
+static void exit_debugger(void)
+{
+	initial_thread_cb(exit_debugger_cb, NULL);
+}
+
+__uml_exitcall(exit_debugger);
+
+struct gdb_data {
+	char *str;
+	int err;
+};
+
+static void config_gdb_cb(void *arg)
+{
+	struct gdb_data *data = arg;
+	void *task;
+	int pid;
+
+	data->err = -1;
+	if(debugger_pid != -1) exit_debugger_cb(NULL);
+	if(!strncmp(data->str, "pid,", strlen("pid,"))){
+		data->str += strlen("pid,");
+		pid = strtoul(data->str, NULL, 0);
+		task = cpu_tasks[0].task;
+		debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0);
+		if(debugger_pid != -1){
+			data->err = 0;
+			gdb_pid = pid;
+		}
+		return;
+	}
+	data->err = 0;
+	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+	init_proxy(debugger_pid, 0, 0);
+}
+
+int gdb_config(char *str)
+{
+	struct gdb_data data;
+
+	if(*str++ != '=') return(-1);
+	data.str = str;
+	initial_thread_cb(config_gdb_cb, &data);
+	return(data.err);
+}
+
+void remove_gdb_cb(void *unused)
+{
+	exit_debugger_cb(NULL);
+}
+
+int gdb_remove(char *unused)
+{
+	initial_thread_cb(remove_gdb_cb, NULL);
+	return(0);
+}
+
+void signal_usr1(int sig)
+{
+	if(debugger_pid != -1){
+		printf("The debugger is already running\n");
+		return;
+	}
+	debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd);
+	init_proxy(debugger_pid, 0, 0);
+}
+
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+	int pid, status;
+
+	pid = start_debugger(linux_prog, startup, stop, &debugger_fd);
+	status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
+ 	if(pid < 0){
+		cont(idle_pid);
+		return(-1);
+	}
+	init_proxy(pid, 1, status);
+	return(pid);
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	int status = 0, err;
+
+	err = attach(pid);
+	if(err < 0){
+		printf("Failed to attach pid %d, errno = %d\n", pid, -err);
+		return(-1);
+	}
+	if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL);
+	init_proxy(pid, 1, status);
+	return(pid);
+}
+
+#ifdef notdef /* Put this back in when it does something useful */
+static int __init uml_gdb_init_setup(char *line, int *add)
+{
+	gdb_init = uml_strdup(line);
+	return 0;
+}
+
+__uml_setup("gdb=", uml_gdb_init_setup, 
+"gdb=<channel description>\n\n"
+);
+#endif
+
+static int __init uml_gdb_pid_setup(char *line, int *add)
+{
+	gdb_pid = strtoul(line, NULL, 0);
+	*add = 0;
+	return 0;
+}
+
+__uml_setup("gdb-pid=", uml_gdb_pid_setup, 
+"gdb-pid=<pid>\n"
+"    gdb-pid is used to attach an external debugger to UML.  This may be\n"
+"    an already-running gdb or a debugger-like process like strace.\n\n"
+);
+
+#else
+
+int debugger_signal(int status, pid_t pid){ return(0); }
+void child_signal(pid_t pid, int status){ }
+int init_ptrace_proxy(int idle_pid, int startup, int stop)
+{
+	printf("debug requested when CONFIG_PT_PROXY is off\n");
+	kill_child_dead(idle_pid);
+	exit(1);
+}
+
+void signal_usr1(int sig)
+{
+	printf("debug requested when CONFIG_PT_PROXY is off\n");
+}
+
+int attach_debugger(int idle_pid, int pid, int stop)
+{
+	printf("attach_debugger called when CONFIG_PT_PROXY "
+	       "is off\n");
+	return(-1);
+}
+
+int config_gdb(char *str)
+{
+	return(-1);
+}
+
+int remove_gdb(void)
+{
+	return(-1);
+}
+
+int init_parent_proxy(int pid)
+{
+	return(-1);
+}
+
+void debugger_parent_signal(int status, int pid)
+{
+}
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
new file mode 100644
index 0000000..93fb121
--- /dev/null
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -0,0 +1,40 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/init.h"
+#include "linux/config.h"
+#include "mconsole_kern.h"
+
+#ifdef CONFIG_MCONSOLE
+
+extern int gdb_config(char *str);
+extern int gdb_remove(char *unused);
+
+static struct mc_device gdb_mc = {
+	.name		= "gdb",
+	.config		= gdb_config,
+	.remove		= gdb_remove,
+};
+
+int gdb_mc_init(void)
+{
+	mconsole_register_dev(&gdb_mc);
+	return(0);
+}
+
+__initcall(gdb_mc_init);
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
new file mode 100644
index 0000000..8eff674
--- /dev/null
+++ b/arch/um/kernel/tt/include/debug.h
@@ -0,0 +1,29 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002  Jeff Dike (jdike@karaya.com) and
+ * Lars Brinkhoff.
+ * Licensed under the GPL
+ */
+
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+extern int debugger_proxy(int status, pid_t pid);
+extern void child_proxy(pid_t pid, int status);
+extern void init_proxy (pid_t pid, int waiting, int status);
+extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
+extern void fake_child_exit(void);
+extern int gdb_config(char *str);
+extern int gdb_remove(char *unused);
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/include/mmu-tt.h b/arch/um/kernel/tt/include/mmu-tt.h
new file mode 100644
index 0000000..0440510
--- /dev/null
+++ b/arch/um/kernel/tt/include/mmu-tt.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MMU_H
+#define __TT_MMU_H
+
+struct mmu_context_tt {
+};
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
new file mode 100644
index 0000000..efe4620
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode-tt.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MODE_TT_H__
+#define __MODE_TT_H__
+
+#include "sysdep/ptrace.h"
+
+enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
+
+extern int tracing_pid;
+
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void user_time_init_tt(void);
+extern void sig_handler_common_tt(int sig, void *sc);
+extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
+extern void reboot_tt(void);
+extern void halt_tt(void);
+extern int is_tracer_winch(int pid, int fd, void *data);
+extern void kill_off_processes_tt(void);
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
new file mode 100644
index 0000000..28aaab3
--- /dev/null
+++ b/arch/um/kernel/tt/include/mode_kern-tt.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_MODE_KERN_H__
+#define __TT_MODE_KERN_H__
+
+#include "linux/sched.h"
+#include "asm/page.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+
+extern void *switch_to_tt(void *prev, void *next);
+extern void flush_thread_tt(void);
+extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
+			   unsigned long esp);
+extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+			  unsigned long stack_top, struct task_struct *p,
+			  struct pt_regs *regs);
+extern void release_thread_tt(struct task_struct *task);
+extern void exit_thread_tt(void);
+extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
+extern void init_idle_tt(void);
+extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_vm_tt(void);
+extern void __flush_tlb_one_tt(unsigned long addr);
+extern void flush_tlb_range_tt(struct vm_area_struct *vma,
+			       unsigned long start, unsigned long end);
+extern void flush_tlb_mm_tt(struct mm_struct *mm);
+extern void force_flush_all_tt(void);
+extern long execute_syscall_tt(void *r);
+extern void before_mem_tt(unsigned long brk_start);
+extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
+				       unsigned long *task_size_out);
+extern int start_uml_tt(void);
+extern int external_pid_tt(struct task_struct *task);
+extern int thread_pid_tt(struct task_struct *task);
+
+#define kmem_end_tt (host_task_size - ABOVE_KMEM)
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/include/tt.h b/arch/um/kernel/tt/include/tt.h
new file mode 100644
index 0000000..c667b67
--- /dev/null
+++ b/arch/um/kernel/tt/include/tt.h
@@ -0,0 +1,46 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_H__
+#define __TT_H__
+
+#include "sysdep/ptrace.h"
+
+extern int gdb_pid;
+extern int debug;
+extern int debug_stop;
+extern int debug_trace;
+
+extern int honeypot;
+
+extern int fork_tramp(void *sig_stack);
+extern int do_proc_op(void *t, int proc_id);
+extern int tracer(int (*init_proc)(void *), void *sp);
+extern void attach_process(int pid);
+extern void tracer_panic(char *format, ...);
+extern void set_init_pid(int pid);
+extern int set_user_mode(void *task);
+extern void set_tracing(void *t, int tracing);
+extern int is_tracing(void *task);
+extern void syscall_handler(int sig, union uml_pt_regs *regs);
+extern void exit_kernel(int pid, void *task);
+extern void do_syscall(void *task, int pid, int local_using_sysemu);
+extern void do_sigtrap(void *task);
+extern int is_valid_pid(int pid);
+extern void remap_data(void *segment_start, void *segment_end, int w);
+extern long execute_syscall_tt(void *r);
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
new file mode 100644
index 0000000..f0bad01
--- /dev/null
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TT_UACCESS_H
+#define __TT_UACCESS_H
+
+#include "linux/string.h"
+#include "linux/sched.h"
+#include "asm/processor.h"
+#include "asm/errno.h"
+#include "asm/current.h"
+#include "asm/a.out.h"
+#include "uml_uaccess.h"
+
+#define ABOVE_KMEM (16 * 1024 * 1024)
+
+extern unsigned long end_vm;
+extern unsigned long uml_physmem;
+
+#define under_task_size(addr, size) \
+	(((unsigned long) (addr) < TASK_SIZE) && \
+         (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define is_stack(addr, size) \
+	(((unsigned long) (addr) < STACK_TOP) && \
+	 ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
+	 (((unsigned long) (addr) + (size)) <= STACK_TOP))
+
+#define access_ok_tt(type, addr, size) \
+	((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
+         (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
+          (under_task_size(addr, size) || is_stack(addr, size))))
+
+static inline int verify_area_tt(int type, const void * addr,
+				 unsigned long size)
+{
+	return(access_ok_tt(type, addr, size) ? 0 : -EFAULT);
+}
+
+extern unsigned long get_fault_addr(void);
+
+extern int __do_copy_from_user(void *to, const void *from, int n,
+			       void **fault_addr, void **fault_catcher);
+extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+				  void **fault_addr, void **fault_catcher);
+extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+			   void **fault_catcher);
+extern int __do_strnlen_user(const char *str, unsigned long n,
+			     void **fault_addr, void **fault_catcher);
+
+extern int copy_from_user_tt(void *to, const void *from, int n);
+extern int copy_to_user_tt(void *to, const void *from, int n);
+extern int strncpy_from_user_tt(char *dst, const char *src, int count);
+extern int __clear_user_tt(void *mem, int len);
+extern int clear_user_tt(void *mem, int len);
+extern int strnlen_user_tt(const void *str, int len);
+
+#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:
+ */
diff --git a/arch/um/kernel/tt/ksyms.c b/arch/um/kernel/tt/ksyms.c
new file mode 100644
index 0000000..92ec85d
--- /dev/null
+++ b/arch/um/kernel/tt/ksyms.c
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/module.h"
+#include "asm/uaccess.h"
+#include "mode.h"
+
+EXPORT_SYMBOL(__do_copy_from_user);
+EXPORT_SYMBOL(__do_copy_to_user);
+EXPORT_SYMBOL(__do_strncpy_from_user);
+EXPORT_SYMBOL(__do_strnlen_user); 
+EXPORT_SYMBOL(__do_clear_user);
+
+EXPORT_SYMBOL(tracing_pid);
+EXPORT_SYMBOL(honeypot);
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
new file mode 100644
index 0000000..74346a0
--- /dev/null
+++ b/arch/um/kernel/tt/mem.c
@@ -0,0 +1,51 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/config.h"
+#include "linux/mm.h"
+#include "asm/uaccess.h"
+#include "mem_user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "kern.h"
+#include "tt.h"
+
+void before_mem_tt(unsigned long brk_start)
+{
+	if(debug)
+		remap_data(UML_ROUND_DOWN(&_stext), UML_ROUND_UP(&_etext), 1);
+	remap_data(UML_ROUND_DOWN(&_sdata), UML_ROUND_UP(&_edata), 1);
+	remap_data(UML_ROUND_DOWN(&__bss_start), UML_ROUND_UP(&_end), 1);
+}
+
+#ifdef CONFIG_HOST_2G_2G
+#define TOP 0x80000000
+#else
+#define TOP 0xc0000000
+#endif
+
+#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
+#define START (TOP - SIZE)
+
+unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, 
+				unsigned long *task_size_out)
+{
+	/* Round up to the nearest 4M */
+	*host_size_out = ROUND_4M((unsigned long) &arg);
+	*task_size_out = START;
+	return(START);
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
new file mode 100644
index 0000000..3085267
--- /dev/null
+++ b/arch/um/kernel/tt/mem_user.c
@@ -0,0 +1,49 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include "tt.h"
+#include "mem_user.h"
+#include "user_util.h"
+
+void remap_data(void *segment_start, void *segment_end, int w)
+{
+	void *addr;
+	unsigned long size;
+	int data, prot;
+
+	if(w) prot = PROT_WRITE;
+	else prot = 0;
+	prot |= PROT_READ | PROT_EXEC;
+	size = (unsigned long) segment_end - 
+		(unsigned long) segment_start;
+	data = create_mem_file(size);
+	addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
+	if(addr == MAP_FAILED){
+		perror("mapping new data segment");
+		exit(1);
+	}
+	memcpy(addr, segment_start, size);
+	if(switcheroo(data, prot, addr, segment_start, size) < 0){
+		printf("switcheroo failed\n");
+		exit(1);
+	}
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
new file mode 100644
index 0000000..f19f7c1
--- /dev/null
+++ b/arch/um/kernel/tt/process_kern.c
@@ -0,0 +1,476 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/signal.h"
+#include "linux/kernel.h"
+#include "linux/interrupt.h"
+#include "linux/ptrace.h"
+#include "asm/system.h"
+#include "asm/pgalloc.h"
+#include "asm/ptrace.h"
+#include "asm/tlbflush.h"
+#include "irq_user.h"
+#include "signal_user.h"
+#include "kern_util.h"
+#include "user_util.h"
+#include "os.h"
+#include "kern.h"
+#include "sigcontext.h"
+#include "time_user.h"
+#include "mem_user.h"
+#include "tlb.h"
+#include "mode.h"
+#include "init.h"
+#include "tt.h"
+
+void *switch_to_tt(void *prev, void *next, void *last)
+{
+	struct task_struct *from, *to, *prev_sched;
+	unsigned long flags;
+	int err, vtalrm, alrm, prof, cpu;
+	char c;
+	/* jailing and SMP are incompatible, so this doesn't need to be 
+	 * made per-cpu 
+	 */
+	static int reading;
+
+	from = prev;
+	to = next;
+
+	to->thread.prev_sched = from;
+
+	cpu = from->thread_info->cpu;
+	if(cpu == 0)
+		forward_interrupts(to->thread.mode.tt.extern_pid);
+#ifdef CONFIG_SMP
+	forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid);
+#endif
+	local_irq_save(flags);
+
+	vtalrm = change_sig(SIGVTALRM, 0);
+	alrm = change_sig(SIGALRM, 0);
+	prof = change_sig(SIGPROF, 0);
+
+	forward_pending_sigio(to->thread.mode.tt.extern_pid);
+
+	c = 0;
+	set_current(to);
+
+	reading = 0;
+	err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("write of switch_pipe failed, err = %d", -err);
+
+	reading = 1;
+	if((from->exit_state == EXIT_ZOMBIE) ||
+	   (from->exit_state == EXIT_DEAD))
+		os_kill_process(os_getpid(), 0);
+
+	err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("read of switch_pipe failed, errno = %d", -err);
+
+	/* If the process that we have just scheduled away from has exited,
+	 * then it needs to be killed here.  The reason is that, even though
+	 * it will kill itself when it next runs, that may be too late.  Its
+	 * stack will be freed, possibly before then, and if that happens,
+	 * we have a use-after-free situation.  So, it gets killed here
+	 * in case it has not already killed itself.
+	 */
+	prev_sched = current->thread.prev_sched;
+	if((prev_sched->exit_state == EXIT_ZOMBIE) ||
+	   (prev_sched->exit_state == EXIT_DEAD))
+		os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
+
+	change_sig(SIGVTALRM, vtalrm);
+	change_sig(SIGALRM, alrm);
+	change_sig(SIGPROF, prof);
+
+	arch_switch();
+
+	flush_tlb_all();
+	local_irq_restore(flags);
+
+	return(current->thread.prev_sched);
+}
+
+void release_thread_tt(struct task_struct *task)
+{
+	int pid = task->thread.mode.tt.extern_pid;
+
+	if(os_getpid() != pid)
+		os_kill_process(pid, 0);
+}
+
+void exit_thread_tt(void)
+{
+	os_close_file(current->thread.mode.tt.switch_pipe[0]);
+	os_close_file(current->thread.mode.tt.switch_pipe[1]);
+}
+
+void suspend_new_thread(int fd)
+{
+	int err;
+	char c;
+
+	os_stop_process(os_getpid());
+	err = os_read_file(fd, &c, sizeof(c));
+	if(err != sizeof(c))
+		panic("read failed in suspend_new_thread, err = %d", -err);
+}
+
+void schedule_tail(task_t *prev);
+
+static void new_thread_handler(int sig)
+{
+	unsigned long disable;
+	int (*fn)(void *);
+	void *arg;
+
+	fn = current->thread.request.u.thread.proc;
+	arg = current->thread.request.u.thread.arg;
+
+	UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+	disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
+		(1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
+	SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
+
+	suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+
+	force_flush_all();
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	init_new_thread_signals(1);
+	enable_timer();
+	free_page(current->thread.temp_stack);
+	set_cmdline("(kernel thread)");
+
+	change_sig(SIGUSR1, 1);
+	change_sig(SIGVTALRM, 1);
+	change_sig(SIGPROF, 1);
+	local_irq_enable();
+	if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
+		do_exit(0);
+
+	/* XXX No set_user_mode here because a newly execed process will
+	 * immediately segfault on its non-existent IP, coming straight back
+	 * to the signal handler, which will call set_user_mode on its way
+	 * out.  This should probably change since it's confusing.
+	 */
+}
+
+static int new_thread_proc(void *stack)
+{
+	/* local_irq_disable is needed to block out signals until this thread is
+	 * properly scheduled.  Otherwise, the tracing thread will get mighty
+	 * upset about any signals that arrive before that.
+	 * This has the complication that it sets the saved signal mask in
+	 * the sigcontext to block signals.  This gets restored when this
+	 * thread (or a descendant, since they get a copy of this sigcontext)
+	 * returns to userspace.
+	 * So, this is compensated for elsewhere.
+	 * XXX There is still a small window until local_irq_disable() actually
+	 * finishes where signals are possible - shouldn't be a problem in
+	 * practice since SIGIO hasn't been forwarded here yet, and the
+	 * local_irq_disable should finish before a SIGVTALRM has time to be
+	 * delivered.
+	 */
+
+	local_irq_disable();
+	init_new_thread_stack(stack, new_thread_handler);
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+	return(0);
+}
+
+/* Signal masking - signals are blocked at the start of fork_tramp.  They
+ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting
+ * itself with a SIGUSR1.  set_user_mode has to be run with SIGUSR1 off,
+ * so it is blocked before it's called.  They are re-enabled on sigreturn
+ * despite the fact that they were blocked when the SIGUSR1 was issued because
+ * copy_thread copies the parent's sigcontext, including the signal mask
+ * onto the signal frame.
+ */
+
+void finish_fork_handler(int sig)
+{
+ 	UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+	suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+
+	force_flush_all();
+	if(current->thread.prev_sched != NULL)
+		schedule_tail(current->thread.prev_sched);
+	current->thread.prev_sched = NULL;
+
+	enable_timer();
+	change_sig(SIGVTALRM, 1);
+	local_irq_enable();
+	if(current->mm != current->parent->mm)
+		protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
+			       1, 0, 1);
+	task_protections((unsigned long) current_thread);
+
+	free_page(current->thread.temp_stack);
+	local_irq_disable();
+	change_sig(SIGUSR1, 0);
+	set_user_mode(current);
+}
+
+int fork_tramp(void *stack)
+{
+	local_irq_disable();
+	arch_init_thread();
+	init_new_thread_stack(stack, finish_fork_handler);
+
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+	return(0);
+}
+
+int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
+		   unsigned long stack_top, struct task_struct * p, 
+		   struct pt_regs *regs)
+{
+	int (*tramp)(void *);
+	int new_pid, err;
+	unsigned long stack;
+	
+	if(current->thread.forking)
+		tramp = fork_tramp;
+	else {
+		tramp = new_thread_proc;
+		p->thread.request.u.thread = current->thread.request.u.thread;
+	}
+
+	err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
+	if(err < 0){
+		printk("copy_thread : pipe failed, err = %d\n", -err);
+		return(err);
+	}
+
+	stack = alloc_stack(0, 0);
+	if(stack == 0){
+		printk(KERN_ERR "copy_thread : failed to allocate "
+		       "temporary stack\n");
+		return(-ENOMEM);
+	}
+
+	clone_flags &= CLONE_VM;
+	p->thread.temp_stack = stack;
+	new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp);
+	if(new_pid < 0){
+		printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", 
+		       -new_pid);
+		return(new_pid);
+	}
+
+	if(current->thread.forking){
+		sc_to_sc(UPT_SC(&p->thread.regs.regs), 
+			 UPT_SC(&current->thread.regs.regs));
+		SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
+		if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
+	}
+	p->thread.mode.tt.extern_pid = new_pid;
+
+	current->thread.request.op = OP_FORK;
+	current->thread.request.u.fork.pid = new_pid;
+	os_usr1_process(os_getpid());
+
+	/* Enable the signal and then disable it to ensure that it is handled
+	 * here, and nowhere else.
+	 */
+	change_sig(SIGUSR1, 1);
+
+	change_sig(SIGUSR1, 0);
+	err = 0;
+	return(err);
+}
+
+void reboot_tt(void)
+{
+	current->thread.request.op = OP_REBOOT;
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+}
+
+void halt_tt(void)
+{
+	current->thread.request.op = OP_HALT;
+	os_usr1_process(os_getpid());
+	change_sig(SIGUSR1, 1);
+}
+
+void kill_off_processes_tt(void)
+{
+	struct task_struct *p;
+	int me;
+
+	me = os_getpid();
+        for_each_process(p){
+		if(p->thread.mode.tt.extern_pid != me) 
+			os_kill_process(p->thread.mode.tt.extern_pid, 0);
+	}
+	if(init_task.thread.mode.tt.extern_pid != me) 
+		os_kill_process(init_task.thread.mode.tt.extern_pid, 0);
+}
+
+void initial_thread_cb_tt(void (*proc)(void *), void *arg)
+{
+	if(os_getpid() == tracing_pid){
+		(*proc)(arg);
+	}
+	else {
+		current->thread.request.op = OP_CB;
+		current->thread.request.u.cb.proc = proc;
+		current->thread.request.u.cb.arg = arg;
+		os_usr1_process(os_getpid());
+		change_sig(SIGUSR1, 1);
+
+		change_sig(SIGUSR1, 0);
+	}
+}
+
+int do_proc_op(void *t, int proc_id)
+{
+	struct task_struct *task;
+	struct thread_struct *thread;
+	int op, pid;
+
+	task = t;
+	thread = &task->thread;
+	op = thread->request.op;
+	switch(op){
+	case OP_NONE:
+	case OP_TRACE_ON:
+		break;
+	case OP_EXEC:
+		pid = thread->request.u.exec.pid;
+		do_exec(thread->mode.tt.extern_pid, pid);
+		thread->mode.tt.extern_pid = pid;
+		cpu_tasks[task->thread_info->cpu].pid = pid;
+		break;
+	case OP_FORK:
+		attach_process(thread->request.u.fork.pid);
+		break;
+	case OP_CB:
+		(*thread->request.u.cb.proc)(thread->request.u.cb.arg);
+		break;
+	case OP_REBOOT:
+	case OP_HALT:
+		break;
+	default:
+		tracer_panic("Bad op in do_proc_op");
+		break;
+	}
+	thread->request.op = OP_NONE;
+	return(op);
+}
+
+void init_idle_tt(void)
+{
+	default_idle();
+}
+
+extern void start_kernel(void);
+
+static int start_kernel_proc(void *unused)
+{
+	int pid;
+
+	block_signals();
+	pid = os_getpid();
+
+	cpu_tasks[0].pid = pid;
+	cpu_tasks[0].task = current;
+#ifdef CONFIG_SMP
+ 	cpu_online_map = cpumask_of_cpu(0);
+#endif
+	if(debug) os_stop_process(pid);
+	start_kernel();
+	return(0);
+}
+
+void set_tracing(void *task, int tracing)
+{
+	((struct task_struct *) task)->thread.mode.tt.tracing = tracing;
+}
+
+int is_tracing(void *t)
+{
+	return (((struct task_struct *) t)->thread.mode.tt.tracing);
+}
+
+int set_user_mode(void *t)
+{
+	struct task_struct *task;
+
+	task = t ? t : current;
+	if(task->thread.mode.tt.tracing) 
+		return(1);
+	task->thread.request.op = OP_TRACE_ON;
+	os_usr1_process(os_getpid());
+	return(0);
+}
+
+void set_init_pid(int pid)
+{
+	int err;
+
+	init_task.thread.mode.tt.extern_pid = pid;
+	err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
+	if(err)
+		panic("Can't create switch pipe for init_task, errno = %d",
+		      -err);
+}
+
+int start_uml_tt(void)
+{
+	void *sp;
+	int pages;
+
+	pages = (1 << CONFIG_KERNEL_STACK_ORDER);
+	sp = (void *) ((unsigned long) init_task.thread_info) +
+		pages * PAGE_SIZE - sizeof(unsigned long);
+	return(tracer(start_kernel_proc, sp));
+}
+
+int external_pid_tt(struct task_struct *task)
+{
+	return(task->thread.mode.tt.extern_pid);
+}
+
+int thread_pid_tt(struct task_struct *task)
+{
+	return(task->thread.mode.tt.extern_pid);
+}
+
+int is_valid_pid(int pid)
+{
+	struct task_struct *task;
+
+        read_lock(&tasklist_lock);
+        for_each_process(task){
+                if(task->thread.mode.tt.extern_pid == pid){
+			read_unlock(&tasklist_lock);
+			return(1);
+                }
+        }
+	read_unlock(&tasklist_lock);
+	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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/Makefile b/arch/um/kernel/tt/ptproxy/Makefile
new file mode 100644
index 0000000..3ad5b77
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/Makefile
@@ -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
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
new file mode 100644
index 0000000..58800c5
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/ptproxy.h b/arch/um/kernel/tt/ptproxy/ptproxy.h
new file mode 100644
index 0000000..5eb0285
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/ptproxy.h
@@ -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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
new file mode 100644
index 0000000..528a5fc
--- /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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
new file mode 100644
index 0000000..a5f0e01
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.h b/arch/um/kernel/tt/ptproxy/sysdep.h
new file mode 100644
index 0000000..735f488
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/sysdep.h
@@ -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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
new file mode 100644
index 0000000..12f6319
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -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:
+ */
diff --git a/arch/um/kernel/tt/ptproxy/wait.h b/arch/um/kernel/tt/ptproxy/wait.h
new file mode 100644
index 0000000..542e73e
--- /dev/null
+++ b/arch/um/kernel/tt/ptproxy/wait.h
@@ -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
diff --git a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
new file mode 100644
index 0000000..2650a62
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_kern.c
@@ -0,0 +1,47 @@
+/* 
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/types.h"
+#include "linux/utime.h"
+#include "linux/sys.h"
+#include "linux/ptrace.h"
+#include "asm/unistd.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/stat.h"
+#include "sysdep/syscalls.h"
+#include "kern_util.h"
+
+extern syscall_handler_t *sys_call_table[];
+
+long execute_syscall_tt(void *r)
+{
+	struct pt_regs *regs = r;
+	long res;
+	int syscall;
+
+#ifdef CONFIG_SYSCALL_DEBUG
+	current->thread.nsyscalls++;
+	nsyscalls++;
+#endif
+	syscall = UPT_SYSCALL_NR(&regs->regs);
+
+	if((syscall >= NR_syscalls) || (syscall < 0))
+		res = -ENOSYS;
+	else res = EXECUTE_SYSCALL(syscall, regs);
+
+	return(res);
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
new file mode 100644
index 0000000..e4e7e9c
--- /dev/null
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -0,0 +1,90 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "ptrace_user.h"
+#include "task.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "syscall_user.h"
+#include "tt.h"
+
+
+void syscall_handler_tt(int sig, union uml_pt_regs *regs)
+{
+	void *sc;
+	long result;
+	int syscall;
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+	int index;
+#endif
+
+	syscall = UPT_SYSCALL_NR(regs);
+	sc = UPT_SC(regs);
+	SC_START_SYSCALL(sc);
+
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+  	index = record_syscall_start(syscall);
+#endif
+	syscall_trace(regs, 0);
+	result = execute_syscall_tt(regs);
+
+	/* regs->sc may have changed while the system call ran (there may
+	 * have been an interrupt or segfault), so it needs to be refreshed.
+	 */
+	UPT_SC(regs) = sc;
+
+	SC_SET_SYSCALL_RETURN(sc, result);
+
+	syscall_trace(regs, 1);
+#ifdef UML_CONFIG_DEBUG_SYSCALL
+  	record_syscall_end(index, result);
+#endif
+}
+
+void do_sigtrap(void *task)
+{
+	UPT_SYSCALL_NR(TASK_REGS(task)) = -1;
+}
+
+void do_syscall(void *task, int pid, int local_using_sysemu)
+{
+	unsigned long proc_regs[FRAME_SIZE];
+
+	if(ptrace_getregs(pid, proc_regs) < 0)
+		tracer_panic("Couldn't read registers");
+
+	UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs);
+
+	if(((unsigned long *) PT_IP(proc_regs) >= &_stext) &&
+	   ((unsigned long *) PT_IP(proc_regs) <= &_etext))
+		tracer_panic("I'm tracing myself and I can't get out");
+
+	/* advanced sysemu mode set syscall number to -1 automatically */
+	if (local_using_sysemu==2)
+		return;
+
+	/* syscall number -1 in sysemu skips syscall restarting in host */
+	if(ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET,
+		  local_using_sysemu ? -1 : __NR_getpid) < 0)
+		tracer_panic("do_syscall : Nullifying syscall failed, "
+			     "errno = %d", errno);
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
new file mode 100644
index 0000000..8565b71
--- /dev/null
+++ b/arch/um/kernel/tt/time.c
@@ -0,0 +1,28 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <sys/time.h>
+#include <time_user.h>
+#include "process.h"
+#include "user.h"
+
+void user_time_init_tt(void)
+{
+	if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
+		panic("Couldn't set SIGVTALRM handler");
+	set_interval(ITIMER_VIRTUAL);
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
new file mode 100644
index 0000000..203216a
--- /dev/null
+++ b/arch/um/kernel/tt/tlb.c
@@ -0,0 +1,149 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright 2003 PathScale, Inc.
+ * Licensed under the GPL
+ */
+
+#include "linux/stddef.h"
+#include "linux/kernel.h"
+#include "linux/sched.h"
+#include "linux/mm.h"
+#include "asm/page.h"
+#include "asm/pgtable.h"
+#include "asm/uaccess.h"
+#include "asm/tlbflush.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "os.h"
+#include "tlb.h"
+
+static void do_ops(int unused, struct host_vm_op *ops, int last)
+{
+	struct host_vm_op *op;
+	int i;
+
+	for(i = 0; i <= last; i++){
+		op = &ops[i];
+		switch(op->type){
+		case MMAP:
+                        os_map_memory((void *) op->u.mmap.addr, op->u.mmap.fd,
+				      op->u.mmap.offset, op->u.mmap.len,
+				      op->u.mmap.r, op->u.mmap.w,
+				      op->u.mmap.x);
+			break;
+		case MUNMAP:
+			os_unmap_memory((void *) op->u.munmap.addr,
+					op->u.munmap.len);
+			break;
+		case MPROTECT:
+			protect_memory(op->u.mprotect.addr, op->u.munmap.len,
+				       op->u.mprotect.r, op->u.mprotect.w,
+				       op->u.mprotect.x, 1);
+			break;
+		default:
+			printk("Unknown op type %d in do_ops\n", op->type);
+			break;
+		}
+	}
+}
+
+static void fix_range(struct mm_struct *mm, unsigned long start_addr, 
+		      unsigned long end_addr, int force)
+{
+        if((current->thread.mode.tt.extern_pid != -1) &&
+           (current->thread.mode.tt.extern_pid != os_getpid()))
+                panic("fix_range fixing wrong address space, current = 0x%p",
+                      current);
+
+        fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+}
+
+atomic_t vmchange_seq = ATOMIC_INIT(1);
+
+void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end)
+{
+        if(flush_tlb_kernel_range_common(start, end))
+                atomic_inc(&vmchange_seq);
+}
+
+static void protect_vm_page(unsigned long addr, int w, int must_succeed)
+{
+	int err;
+
+	err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed);
+	if(err == 0) return;
+	else if((err == -EFAULT) || (err == -ENOMEM)){
+		flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+		protect_vm_page(addr, w, 1);
+	}
+	else panic("protect_vm_page : protect failed, errno = %d\n", err);
+}
+
+void mprotect_kernel_vm(int w)
+{
+	struct mm_struct *mm;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long addr;
+	
+	mm = &init_mm;
+	for(addr = start_vm; addr < end_vm;){
+		pgd = pgd_offset(mm, addr);
+		pud = pud_offset(pgd, addr);
+		pmd = pmd_offset(pud, addr);
+		if(pmd_present(*pmd)){
+			pte = pte_offset_kernel(pmd, addr);
+			if(pte_present(*pte)) protect_vm_page(addr, w, 0);
+			addr += PAGE_SIZE;
+		}
+		else addr += PMD_SIZE;
+	}
+}
+
+void flush_tlb_kernel_vm_tt(void)
+{
+        flush_tlb_kernel_range(start_vm, end_vm);
+}
+
+void __flush_tlb_one_tt(unsigned long addr)
+{
+        flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+}
+  
+void flush_tlb_range_tt(struct vm_area_struct *vma, unsigned long start, 
+		     unsigned long end)
+{
+	if(vma->vm_mm != current->mm) return;
+
+	/* Assumes that the range start ... end is entirely within
+	 * either process memory or kernel vm
+	 */
+	if((start >= start_vm) && (start < end_vm)){
+		if(flush_tlb_kernel_range_common(start, end))
+			atomic_inc(&vmchange_seq);
+	}
+	else fix_range(vma->vm_mm, start, end, 0);
+}
+
+void flush_tlb_mm_tt(struct mm_struct *mm)
+{
+	unsigned long seq;
+
+	if(mm != current->mm) return;
+
+	fix_range(mm, 0, STACK_TOP, 0);
+
+	seq = atomic_read(&vmchange_seq);
+	if(current->thread.mode.tt.vm_seq == seq)
+		return;
+	current->thread.mode.tt.vm_seq = seq;
+	flush_tlb_kernel_range_common(start_vm, end_vm);
+}
+
+void force_flush_all_tt(void)
+{
+	fix_range(current->mm, 0, STACK_TOP, 1);
+	flush_tlb_kernel_range_common(start_vm, end_vm);
+}
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
new file mode 100644
index 0000000..7b5d937
--- /dev/null
+++ b/arch/um/kernel/tt/tracer.c
@@ -0,0 +1,480 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include "user.h"
+#include "sysdep/ptrace.h"
+#include "sigcontext.h"
+#include "sysdep/sigcontext.h"
+#include "os.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "mem_user.h"
+#include "process.h"
+#include "kern_util.h"
+#include "chan_user.h"
+#include "ptrace_user.h"
+#include "mode.h"
+#include "tt.h"
+
+static int tracer_winch[2];
+
+int is_tracer_winch(int pid, int fd, void *data)
+{
+	if(pid != tracing_pid)
+		return(0);
+
+	register_winch_irq(tracer_winch[0], fd, -1, data);
+	return(1);
+}
+
+static void tracer_winch_handler(int sig)
+{
+	int n;
+	char c = 1;
+
+	n = os_write_file(tracer_winch[1], &c, sizeof(c));
+	if(n != sizeof(c))
+		printk("tracer_winch_handler - write failed, err = %d\n", -n);
+}
+
+/* Called only by the tracing thread during initialization */
+
+static void setup_tracer_winch(void)
+{
+	int err;
+
+	err = os_pipe(tracer_winch, 1, 1);
+	if(err < 0){
+		printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
+		return;
+	}
+	signal(SIGWINCH, tracer_winch_handler);
+}
+
+void attach_process(int pid)
+{
+	if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) ||
+	   (ptrace(PTRACE_CONT, pid, 0, 0) < 0))
+		tracer_panic("OP_FORK failed to attach pid");
+	wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
+		tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno);
+	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+		tracer_panic("OP_FORK failed to continue process");
+}
+
+void tracer_panic(char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vprintf(format, ap);
+	va_end(ap);
+	printf("\n");
+	while(1) pause();
+}
+
+static void tracer_segv(int sig, struct sigcontext sc)
+{
+	printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n",
+	       SC_FAULT_ADDR(&sc), SC_IP(&sc));
+	while(1)
+		pause();
+}
+
+/* Changed early in boot, and then only read */
+int debug = 0;
+int debug_stop = 1;
+int debug_parent = 0;
+int honeypot = 0;
+
+static int signal_tramp(void *arg)
+{
+	int (*proc)(void *);
+
+	if(honeypot && munmap((void *) (host_task_size - 0x10000000),
+			      0x10000000)) 
+		panic("Unmapping stack failed");
+	if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0)
+		panic("ptrace PTRACE_TRACEME failed");
+	os_stop_process(os_getpid());
+	change_sig(SIGWINCH, 0);
+	signal(SIGUSR1, SIG_IGN);
+	change_sig(SIGCHLD, 0);
+	signal(SIGSEGV, (__sighandler_t) sig_handler);
+	set_cmdline("(idle thread)");
+	set_init_pid(os_getpid());
+	proc = arg;
+	return((*proc)(NULL));
+}
+
+static void sleeping_process_signal(int pid, int sig)
+{
+	switch(sig){
+	/* These two result from UML being ^Z-ed and bg-ed.  PTRACE_CONT is
+	 * right because the process must be in the kernel already.
+	 */
+	case SIGCONT:
+	case SIGTSTP:
+		if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "continue pid %d, signal = %d, "
+				     "errno = %d\n", pid, sig, errno);
+		break;
+
+	/* This happens when the debugger (e.g. strace) is doing system call 
+	 * tracing on the kernel.  During a context switch, the current task
+	 * will be set to the incoming process and the outgoing process will
+	 * hop into write and then read.  Since it's not the current process
+	 * any more, the trace of those will land here.  So, we need to just 
+	 * PTRACE_SYSCALL it.
+	 */
+	case (SIGTRAP + 0x80):
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			tracer_panic("sleeping_process_signal : Failed to "
+				     "PTRACE_SYSCALL pid %d, errno = %d\n",
+				     pid, errno);
+		break;
+	case SIGSTOP:
+		break;
+	default:
+		tracer_panic("sleeping process %d got unexpected "
+			     "signal : %d\n", pid, sig);
+		break;
+	}
+}
+
+/* Accessed only by the tracing thread */
+int debugger_pid = -1;
+int debugger_parent = -1;
+int debugger_fd = -1;
+int gdb_pid = -1;
+
+struct {
+	int pid;
+	int signal;
+	unsigned long addr;
+	struct timeval time;
+} signal_record[1024][32];
+
+int signal_index[32];
+int nsignals = 0;
+int debug_trace = 0;
+extern int io_nsignals, io_count, intr_count;
+
+extern void signal_usr1(int sig);
+
+int tracing_pid = -1;
+
+int tracer(int (*init_proc)(void *), void *sp)
+{
+	void *task = NULL;
+	int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0;
+	int proc_id = 0, n, err, old_tracing = 0, strace = 0;
+	int local_using_sysemu = 0;
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+	unsigned long eip = 0;
+	int last_index;
+#endif
+	signal(SIGPIPE, SIG_IGN);
+	setup_tracer_winch();
+	tracing_pid = os_getpid();
+	printf("tracing thread pid = %d\n", tracing_pid);
+
+	pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
+	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+	if(n < 0){
+		printf("waitpid on idle thread failed, errno = %d\n", errno);
+		exit(1);
+	}
+	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) {
+		printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno);
+		exit(1);
+	}
+	if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){
+		printf("Failed to continue idle thread, errno = %d\n", errno);
+		exit(1);
+	}
+
+	signal(SIGSEGV, (sighandler_t) tracer_segv);
+	signal(SIGUSR1, signal_usr1);
+	if(debug_trace){
+		printf("Tracing thread pausing to be attached\n");
+		stop();
+	}
+	if(debug){
+		if(gdb_pid != -1) 
+			debugger_pid = attach_debugger(pid, gdb_pid, 1);
+		else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop);
+		if(debug_parent){
+			debugger_parent = os_process_parent(debugger_pid);
+			init_parent_proxy(debugger_parent);
+			err = attach(debugger_parent);
+			if(err){
+				printf("Failed to attach debugger parent %d, "
+				       "errno = %d\n", debugger_parent, -err);
+				debugger_parent = -1;
+			}
+			else {
+				if(ptrace(PTRACE_SYSCALL, debugger_parent, 
+					  0, 0) < 0){
+					printf("Failed to continue debugger "
+					       "parent, errno = %d\n", errno);
+					debugger_parent = -1;
+				}
+			}
+		}
+	}
+	set_cmdline("(tracing thread)");
+	while(1){
+		CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
+		if(pid <= 0){
+			if(errno != ECHILD){
+				printf("wait failed - errno = %d\n", errno);
+			}
+			continue;
+		}
+		if(pid == debugger_pid){
+			int cont = 0;
+
+			if(WIFEXITED(status) || WIFSIGNALED(status))
+				debugger_pid = -1;
+			/* XXX Figure out how to deal with gdb and SMP */
+			else cont = debugger_signal(status, cpu_tasks[0].pid);
+			if(cont == PTRACE_SYSCALL) strace = 1;
+			continue;
+		}
+		else if(pid == debugger_parent){
+			debugger_parent_signal(status, pid);
+			continue;
+		}
+		nsignals++;
+		if(WIFEXITED(status)) ;
+#ifdef notdef
+		{
+			printf("Child %d exited with status %d\n", pid, 
+			       WEXITSTATUS(status));
+		}
+#endif
+		else if(WIFSIGNALED(status)){
+			sig = WTERMSIG(status);
+			if(sig != 9){
+				printf("Child %d exited with signal %d\n", pid,
+				       sig);
+			}
+		}
+		else if(WIFSTOPPED(status)){
+			proc_id = pid_to_processor_id(pid);
+			sig = WSTOPSIG(status);
+#ifdef UML_CONFIG_SYSCALL_DEBUG
+			if(signal_index[proc_id] == 1024){
+				signal_index[proc_id] = 0;
+				last_index = 1023;
+			}
+			else last_index = signal_index[proc_id] - 1;
+			if(((sig == SIGPROF) || (sig == SIGVTALRM) ||
+			    (sig == SIGALRM)) &&
+			   (signal_record[proc_id][last_index].signal == sig)&&
+			   (signal_record[proc_id][last_index].pid == pid))
+				signal_index[proc_id] = last_index;
+			signal_record[proc_id][signal_index[proc_id]].pid = pid;
+			gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
+			eip = ptrace(PTRACE_PEEKUSR, pid, PT_IP_OFFSET, 0);
+			signal_record[proc_id][signal_index[proc_id]].addr = eip;
+			signal_record[proc_id][signal_index[proc_id]++].signal = sig;
+#endif
+			if(proc_id == -1){
+				sleeping_process_signal(pid, sig);
+				continue;
+			}
+
+			task = cpu_tasks[proc_id].task;
+			tracing = is_tracing(task);
+			old_tracing = tracing;
+
+			/* Assume: no syscall, when coming from user */
+			if ( tracing )
+				do_sigtrap(task);
+
+			switch(sig){
+			case SIGUSR1:
+				sig = 0;
+				op = do_proc_op(task, proc_id);
+				switch(op){
+				/*
+				 * This is called when entering user mode; after
+				 * this, we start intercepting syscalls.
+				 *
+				 * In fact, a process is started in kernel mode,
+				 * so with is_tracing() == 0 (and that is reset
+				 * when executing syscalls, since UML kernel has
+				 * the right to do syscalls);
+				 */
+				case OP_TRACE_ON:
+					arch_leave_kernel(task, pid);
+					tracing = 1;
+					break;
+				case OP_REBOOT:
+				case OP_HALT:
+					unmap_physmem();
+					kmalloc_ok = 0;
+					os_kill_ptraced_process(pid, 0);
+					/* Now let's reap remaining zombies */
+					errno = 0;
+					do {
+						waitpid(-1, &status,
+							WUNTRACED);
+					} while (errno != ECHILD);
+					return(op == OP_REBOOT);
+				case OP_NONE:
+					printf("Detaching pid %d\n", pid);
+					detach(pid, SIGSTOP);
+					continue;
+				default:
+					break;
+				}
+				/* OP_EXEC switches host processes on us,
+				 * we want to continue the new one.
+				 */
+				pid = cpu_tasks[proc_id].pid;
+				break;
+			case (SIGTRAP + 0x80):
+				if(!tracing && (debugger_pid != -1)){
+					child_signal(pid, status & 0x7fff);
+					continue;
+				}
+				tracing = 0;
+				/* local_using_sysemu has been already set
+				 * below, since if we are here, is_tracing() on
+				 * the traced task was 1, i.e. the process had
+				 * already run through one iteration of the
+				 * loop which executed a OP_TRACE_ON request.*/
+				do_syscall(task, pid, local_using_sysemu);
+				sig = SIGUSR2;
+				break;
+			case SIGTRAP:
+				if(!tracing && (debugger_pid != -1)){
+					child_signal(pid, status);
+					continue;
+				}
+				tracing = 0;
+				break;
+			case SIGPROF:
+				if(tracing) sig = 0;
+				break;
+			case SIGCHLD:
+			case SIGHUP:
+				sig = 0;
+				break;
+			case SIGSEGV:
+			case SIGIO:
+			case SIGALRM:
+			case SIGVTALRM:
+			case SIGFPE:
+			case SIGBUS:
+			case SIGILL:
+			case SIGWINCH:
+
+			default:
+				tracing = 0;
+				break;
+			}
+			set_tracing(task, tracing);
+
+			if(!tracing && old_tracing)
+				arch_enter_kernel(task, pid);
+
+			if(!tracing && (debugger_pid != -1) && (sig != 0) &&
+				(sig != SIGALRM) && (sig != SIGVTALRM) &&
+				(sig != SIGSEGV) && (sig != SIGTRAP) &&
+				(sig != SIGUSR2) && (sig != SIGIO) &&
+				(sig != SIGFPE)){
+				child_signal(pid, status);
+				continue;
+			}
+
+			local_using_sysemu = get_using_sysemu();
+
+			if(tracing)
+				cont_type = SELECT_PTRACE_OPERATION(local_using_sysemu,
+				                                    singlestepping(task));
+			else if((debugger_pid != -1) && strace)
+				cont_type = PTRACE_SYSCALL;
+			else
+				cont_type = PTRACE_CONT;
+
+			if(ptrace(cont_type, pid, 0, sig) != 0){
+				tracer_panic("ptrace failed to continue "
+					     "process - errno = %d\n", 
+					     errno);
+			}
+		}
+	}
+	return(0);
+}
+
+static int __init uml_debug_setup(char *line, int *add)
+{
+	char *next;
+
+	debug = 1;
+	*add = 0;
+	if(*line != '=') return(0);
+	line++;
+
+	while(line != NULL){
+		next = strchr(line, ',');
+		if(next) *next++ = '\0';
+		
+		if(!strcmp(line, "go"))	debug_stop = 0;
+		else if(!strcmp(line, "parent")) debug_parent = 1;
+		else printf("Unknown debug option : '%s'\n", line);
+
+		line = next;
+	}
+	return(0);
+}
+
+__uml_setup("debug", uml_debug_setup,
+"debug\n"
+"    Starts up the kernel under the control of gdb. See the \n"
+"    kernel debugging tutorial and the debugging session pages\n"
+"    at http://user-mode-linux.sourceforge.net/ for more information.\n\n"
+);
+
+static int __init uml_debugtrace_setup(char *line, int *add)
+{
+	debug_trace = 1;
+	return 0;
+}
+__uml_setup("debugtrace", uml_debugtrace_setup,
+"debugtrace\n"
+"    Causes the tracing thread to pause until it is attached by a\n"
+"    debugger and continued.  This is mostly for debugging crashes\n"
+"    early during boot, and should be pretty much obsoleted by\n"
+"    the debug switch.\n\n"
+);
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
new file mode 100644
index 0000000..92a3820
--- /dev/null
+++ b/arch/um/kernel/tt/trap_user.c
@@ -0,0 +1,60 @@
+/* 
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include "sysdep/ptrace.h"
+#include "signal_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "tt.h"
+
+void sig_handler_common_tt(int sig, void *sc_ptr)
+{
+	struct sigcontext *sc = sc_ptr;
+	struct tt_regs save_regs, *r;
+	struct signal_info *info;
+	int save_errno = errno, is_user;
+
+	/* This is done because to allow SIGSEGV to be delivered inside a SEGV
+	 * handler.  This can happen in copy_user, and if SEGV is disabled,
+	 * the process will die.
+	 */
+	if(sig == SIGSEGV)
+		change_sig(SIGSEGV, 1);
+
+	r = &TASK_REGS(get_current())->tt;
+	save_regs = *r;
+	is_user = user_context(SC_SP(sc));
+	r->sc = sc;
+	if(sig != SIGUSR2) 
+		r->syscall = -1;
+
+	info = &sig_info[sig];
+	if(!info->is_irq) unblock_signals();
+
+	(*info->handler)(sig, (union uml_pt_regs *) r);
+
+	if(is_user){
+		interrupt_end();
+		block_signals();
+		set_user_mode(NULL);
+	}
+	*r = save_regs;
+	errno = save_errno;
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
new file mode 100644
index 0000000..a72aa63
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/uaccess.h"
+
+int copy_from_user_tt(void *to, const void __user *from, int n)
+{
+	if(!access_ok_tt(VERIFY_READ, from, n))
+		return(n);
+
+	return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
+				   &current->thread.fault_catcher));
+}
+
+int copy_to_user_tt(void __user *to, const void *from, int n)
+{
+	if(!access_ok_tt(VERIFY_WRITE, to, n))
+		return(n);
+
+	return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
+				 &current->thread.fault_catcher));
+}
+
+int strncpy_from_user_tt(char *dst, const char __user *src, int count)
+{
+	int n;
+
+	if(!access_ok_tt(VERIFY_READ, src, 1))
+		return(-EFAULT);
+
+	n = __do_strncpy_from_user(dst, src, count,
+				   &current->thread.fault_addr,
+				   &current->thread.fault_catcher);
+	if(n < 0) return(-EFAULT);
+	return(n);
+}
+
+int __clear_user_tt(void __user *mem, int len)
+{
+	return(__do_clear_user(mem, len,
+			       &current->thread.fault_addr,
+			       &current->thread.fault_catcher));
+}
+
+int clear_user_tt(void __user *mem, int len)
+{
+	if(!access_ok_tt(VERIFY_WRITE, mem, len))
+		return(len);
+
+	return(__do_clear_user(mem, len, &current->thread.fault_addr,
+			       &current->thread.fault_catcher));
+}
+
+int strnlen_user_tt(const void __user *str, int len)
+{
+	return(__do_strnlen_user(str, len,
+				 &current->thread.fault_addr,
+				 &current->thread.fault_catcher));
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
new file mode 100644
index 0000000..f014755
--- /dev/null
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -0,0 +1,98 @@
+/* 
+ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk)
+ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <setjmp.h>
+#include <string.h>
+#include "user_util.h"
+#include "uml_uaccess.h"
+#include "task.h"
+#include "kern_util.h"
+
+int __do_copy_from_user(void *to, const void *from, int n,
+			void **fault_addr, void **fault_catcher)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+			       __do_copy, &faulted);
+	TASK_REGS(get_current())->tt = save;
+
+	if(!faulted) return(0);
+	else return(n - (fault - (unsigned long) from));
+}
+
+static void __do_strncpy(void *dst, const void *src, int count)
+{
+	strncpy(dst, src, count);
+}	
+
+int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
+			   void **fault_addr, void **fault_catcher)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
+			       __do_strncpy, &faulted);
+	TASK_REGS(get_current())->tt = save;
+
+	if(!faulted) return(strlen(dst));
+	else return(-1);
+}
+
+static void __do_clear(void *to, const void *from, int n)
+{
+	memset(to, 0, n);
+}	
+
+int __do_clear_user(void *mem, unsigned long len,
+		    void **fault_addr, void **fault_catcher)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	unsigned long fault;
+	int faulted;
+
+	fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
+			       __do_clear, &faulted);
+	TASK_REGS(get_current())->tt = save;
+
+	if(!faulted) return(0);
+	else return(len - (fault - (unsigned long) mem));
+}
+
+int __do_strnlen_user(const char *str, unsigned long n,
+		      void **fault_addr, void **fault_catcher)
+{
+	struct tt_regs save = TASK_REGS(get_current())->tt;
+	int ret;
+	unsigned long *faddrp = (unsigned long *)fault_addr;
+	sigjmp_buf jbuf;
+
+	*fault_catcher = &jbuf;
+	if(sigsetjmp(jbuf, 1) == 0)
+		ret = strlen(str) + 1;
+	else ret = *faddrp - (unsigned long) str;
+
+	*fault_addr = NULL;
+	*fault_catcher = NULL;
+
+	TASK_REGS(get_current())->tt = save;
+	return ret;
+}
+
+/*
+ * 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:
+ */
diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c
new file mode 100644
index 0000000..3f7aecd
--- /dev/null
+++ b/arch/um/kernel/tt/unmap.c
@@ -0,0 +1,31 @@
+/* 
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <sys/mman.h>
+
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+	if(munmap(to, size) < 0){
+		return(-1);
+	}
+	if(mmap(to, size, prot,	MAP_SHARED | MAP_FIXED, fd, 0) != to){
+		return(-1);
+	}
+	if(munmap(from, size) < 0){
+		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:
+ */