diff -uwr linux-source-2.6.14/arch/i386/kernel/ptrace.c linux-source-2.6.14viewos/arch/i386/kernel/ptrace.c
--- linux-source-2.6.14/arch/i386/kernel/ptrace.c	2005-10-28 02:02:08.000000000 +0200
+++ linux-source-2.6.14viewos/arch/i386/kernel/ptrace.c	2006-01-07 11:33:29.000000000 +0100
@@ -354,49 +355,11 @@
 	return 0;
 }
 
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+static int sys_ptrace_reqprocess(struct task_struct *child, long request, long addr, long data)
 {
-	struct task_struct *child;
-	struct user * dummy = NULL;
 	int i, ret;
+	struct user * dummy = NULL;
 	unsigned long __user *datap = (unsigned long __user *)data;
-
-	lock_kernel();
-	ret = -EPERM;
-	if (request == PTRACE_TRACEME) {
-		/* are we already being traced? */
-		if (current->ptrace & PT_PTRACED)
-			goto out;
-		ret = security_ptrace(current->parent, current);
-		if (ret)
-			goto out;
-		/* set the ptrace bit in the process flags. */
-		current->ptrace |= PT_PTRACED;
-		ret = 0;
-		goto out;
-	}
-	ret = -ESRCH;
-	read_lock(&tasklist_lock);
-	child = find_task_by_pid(pid);
-	if (child)
-		get_task_struct(child);
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-
-	ret = -EPERM;
-	if (pid == 1)		/* you may not mess with init */
-		goto out_tsk;
-
-	if (request == PTRACE_ATTACH) {
-		ret = ptrace_attach(child);
-		goto out_tsk;
-	}
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out_tsk;
-
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -659,11 +622,191 @@
 					(struct user_desc __user *) data);
 		break;
 
+#ifdef CONFIG_PROC_MM
+	case PTRACE_EX_FAULTINFO: {
+		struct ptrace_ex_faultinfo fault;
+
+		fault = ((struct ptrace_ex_faultinfo)
+			{ .is_write	= child->thread.error_code,
+			  .addr		= child->thread.cr2,
+			  .trap_no	= child->thread.trap_no });
+		ret = copy_to_user((unsigned long *) data, &fault,
+				   sizeof(fault));
+		if(ret)
+			break;
+		break;
+	}
+
+	case PTRACE_FAULTINFO: {
+		struct ptrace_faultinfo fault;
+
+		fault = ((struct ptrace_faultinfo)
+			{ .is_write	= child->thread.error_code,
+			  .addr		= child->thread.cr2 });
+		ret = copy_to_user((unsigned long *) data, &fault,
+				   sizeof(fault));
+		if(ret)
+			break;
+		break;
+	}
+
+	case PTRACE_LDT: {
+		struct ptrace_ldt ldt;
+
+		if(copy_from_user(&ldt, (unsigned long *) data,
+				  sizeof(ldt))){
+			ret = -EIO;
+			break;
+		}
+		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
+		break;
+	}
+
+	case PTRACE_SWITCH_MM: {
+		struct mm_struct *old = child->mm;
+		struct mm_struct *new = proc_mm_get_mm(data);
+
+		if(IS_ERR(new)){
+			ret = PTR_ERR(new);
+			break;
+		}
+
+		atomic_inc(&new->mm_users);
+
+		lock_fix_dumpable_setting(child, new);
+
+		child->mm = new;
+		child->active_mm = new;
+
+		task_unlock(child);
+
+		mmput(old);
+		ret = 0;
+		break;
+	}
+#endif
+
+	case PTRACE_MULTI:
+		{
+			long size=data;
+			long j;
+			ret=0;
+			if (!access_ok(VERIFY_READ, addr,size*sizeof(struct ptrace_multi))) {
+				ret = -EIO;
+				break;
+			}
+			for (i=0; i<size && ret==0; i++, addr+=sizeof(struct ptrace_multi)) {
+				unsigned long len;
+				struct ptrace_multi __user pm ;
+				__copy_from_user(&pm, (struct ptrace_multi __user *)addr, sizeof(struct ptrace_multi));
+				len = pm.length;
+				switch ( pm.request){
+					case PTRACE_PEEKTEXT:
+					case PTRACE_PEEKDATA:
+					case PTRACE_PEEKUSR:
+						if (len <= 0) len=1;
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len*sizeof(long))) {
+							  ret = -EIO;
+							  break;
+						}
+						for (j=0; j<len && ret==0; j++)
+							ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr) + j*sizeof(long), (long) (pm.localaddr) + j*sizeof(long));
+						break;
+					case PTRACE_POKETEXT:
+					case PTRACE_POKEDATA:
+					case PTRACE_POKEUSR:
+						if (len <= 0) len=1;
+						if (!access_ok(VERIFY_READ, pm.localaddr,len*sizeof(long))) {
+							  ret = -EIO;
+							  break;
+						}
+						for (j=0; j<len && ret==0; j++)
+							ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr) + j*sizeof(long), *(((long *) (pm.localaddr)) + j));
+						break;
+					case PTRACE_PEEKCHARDATA:
+#if 0
+						  if (!access_ok(VERIFY_WRITE, pm.localaddr,len)) {
+							  ret = -EIO;
+							  break;
+						  }
+#endif
+						  ret = ptrace_readdata(child, pm.addr, pm.localaddr, len);
+						break;
+					case PTRACE_POKECHARDATA:
+#if 0
+						  if (!access_ok(VERIFY_READ, pm.localaddr,len)) {
+							  ret = -EIO;
+							  break;
+						  }
+#endif
+						  ret = ptrace_writedata(child, pm.localaddr, pm.addr, len);
+						break;
+					case PTRACE_PEEKSTRINGDATA:
+#if 0
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len)) {
+							ret = -EIO;
+							break;
+						}
+#endif
+						ret = ptrace_readstringdata(child, pm.addr, pm.localaddr, len);
+						break;
+					default:
+						ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr), (long) (pm.localaddr));
+						break;
+				}
+			}
+			break;
+		}
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
 out_tsk:
+	return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		ret = security_ptrace(current->parent, current);
+		if (ret)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+	ret=sys_ptrace_reqprocess(child,request,addr,data);
+out_tsk:
 	put_task_struct(child);
 out:
 	unlock_kernel();
diff -uwr linux-source-2.6.14/arch/ppc/kernel/ptrace.c linux-source-2.6.14viewos/arch/ppc/kernel/ptrace.c
--- linux-source-2.6.14/arch/ppc/kernel/ptrace.c	2005-10-28 02:02:08.000000000 +0200
+++ linux-source-2.6.14viewos/arch/ppc/kernel/ptrace.c	2006-01-07 11:33:30.000000000 +0100
@@ -240,45 +240,9 @@
 	clear_single_step(child);
 }
 
-int sys_ptrace(long request, long pid, long addr, long data)
+static int sys_ptrace_reqprocess(struct task_struct *child, long request, long addr, long data)
 {
-	struct task_struct *child;
-	int ret = -EPERM;
-
-	lock_kernel();
-	if (request == PTRACE_TRACEME) {
-		/* are we already being traced? */
-		if (current->ptrace & PT_PTRACED)
-			goto out;
-		ret = security_ptrace(current->parent, current);
-		if (ret)
-			goto out;
-		/* set the ptrace bit in the process flags. */
-		current->ptrace |= PT_PTRACED;
-		ret = 0;
-		goto out;
-	}
-	ret = -ESRCH;
-	read_lock(&tasklist_lock);
-	child = find_task_by_pid(pid);
-	if (child)
-		get_task_struct(child);
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-
-	ret = -EPERM;
-	if (pid == 1)		/* you may not mess with init */
-		goto out_tsk;
-
-	if (request == PTRACE_ATTACH) {
-		ret = ptrace_attach(child);
-		goto out_tsk;
-	}
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out_tsk;
+	int i, ret=-EPERM;
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
@@ -447,10 +411,124 @@
 		break;
 #endif
 
+	case PTRACE_MULTI:
+		{
+			long size=data;
+			long j;
+			ret=0;
+			if (!access_ok(VERIFY_READ, addr,size*sizeof(struct ptrace_multi))) {
+				ret = -EIO;
+				break;
+			}
+			for (i=0; i<size && ret==0; i++, addr+=sizeof(struct ptrace_multi)) {
+				struct ptrace_multi __user pm;
+				unsigned long len;
+				__copy_from_user(&pm, (struct ptrace_multi __user *)addr, sizeof(struct ptrace_multi));
+				len = pm.length;
+				switch ( pm.request){
+					case PTRACE_PEEKTEXT:
+					case PTRACE_PEEKDATA:
+					case PTRACE_PEEKUSR:
+						if (len <= 0) len=1;
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len*sizeof(long))) {
+							ret = -EIO;
+							break;
+						}
+						for (j=0; j<len && ret==0; j++)
+							ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr) + j*sizeof(long), (long) (pm.localaddr) + j*sizeof(long));
+						break;
+					case PTRACE_POKETEXT:
+					case PTRACE_POKEDATA:
+					case PTRACE_POKEUSR:
+						if (len <= 0) len=1;
+						if (!access_ok(VERIFY_READ, pm.localaddr,len*sizeof(long))) {
+							ret = -EIO;
+							break;
+						}
+						for (j=0; j<len && ret==0; j++)
+							ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr) + j*sizeof(long), *(((long *) (pm.localaddr)) + j));
+						break;
+					case PTRACE_PEEKCHARDATA:
+#if 0
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len)) {
+							ret = -EIO;
+							break;
+						}
+#endif
+						ret = ptrace_readdata(child, pm.addr, pm.localaddr, len);
+						break;
+					case PTRACE_POKECHARDATA:
+						if (!access_ok(VERIFY_READ, pm.localaddr,len)) {
+
+							ret = -EIO;
+							break;
+						}
+						ret = ptrace_writedata(child, pm.localaddr, pm.addr, len);
+						break;
+					case PTRACE_PEEKSTRINGDATA:
+#if 0
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len)) {
+							ret = -EIO;
+							break;
+						}
+#endif
+						ret = ptrace_readstringdata(child, pm.addr, pm.localaddr, len);
+						break;
+					default:
+						ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr), (long) (pm.localaddr));
+						break;
+				}
+			}
+			break;
+		}
+
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
+	return ret;
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret = -EPERM;
+
+	lock_kernel();
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		ret = security_ptrace(current->parent, current);
+		if (ret)
+			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+	ret=sys_ptrace_reqprocess(child,request,addr,data);
 out_tsk:
 	put_task_struct(child);
 out:
diff -uwr linux-source-2.6.14/arch/um/kernel/ptrace.c linux-source-2.6.14viewos/arch/um/kernel/ptrace.c
--- linux-source-2.6.14/arch/um/kernel/ptrace.c	2005-10-28 02:02:08.000000000 +0200
+++ linux-source-2.6.14viewos/arch/um/kernel/ptrace.c	2006-01-07 11:33:32.000000000 +0100
@@ -43,53 +43,10 @@
 extern int peek_user(struct task_struct * child, long addr, long data);
 extern int poke_user(struct task_struct * child, long addr, long data);
 
-long sys_ptrace(long request, long pid, long addr, long data)
+static long sys_ptrace_reqprocess(struct task_struct *child, long request, long addr, long data)
 {
-	struct task_struct *child;
 	int i, ret;
 
-	lock_kernel();
-	ret = -EPERM;
-	if (request == PTRACE_TRACEME) {
-		/* are we already being traced? */
-		if (current->ptrace & PT_PTRACED)
-			goto out;
-
-		ret = security_ptrace(current->parent, current);
-		if (ret)
- 			goto out;
-
-		/* set the ptrace bit in the process flags. */
-		current->ptrace |= PT_PTRACED;
-		ret = 0;
-		goto out;
-	}
-	ret = -ESRCH;
-	read_lock(&tasklist_lock);
-	child = find_task_by_pid(pid);
-	if (child)
-		get_task_struct(child);
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-
-	ret = -EPERM;
-	if (pid == 1)		/* you may not mess with init */
-		goto out_tsk;
-
-	if (request == PTRACE_ATTACH) {
-		ret = ptrace_attach(child);
-		goto out_tsk;
-	}
-
-#ifdef SUBACH_PTRACE_SPECIAL
-        SUBARCH_PTRACE_SPECIAL(child,request,addr,data);
-#endif
-
-	ret = ptrace_check_attach(child, request == PTRACE_KILL);
-	if (ret < 0)
-		goto out_tsk;
-
 	switch (request) {
 		/* when I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
@@ -278,10 +235,132 @@
 		break;
 	}
 #endif
+	case PTRACE_MULTI:
+		{
+			unsigned long size=data;
+			unsigned long j;
+			ret=0;
+			if (!access_ok(VERIFY_READ, addr,size*sizeof(struct ptrace_multi))) {
+				ret = -EIO;
+				break;
+			}
+			for (i=0; i<size && ret==0; i++, addr+=sizeof(struct ptrace_multi)) {
+				struct ptrace_multi __user pm;
+				unsigned long len;
+				
+				__copy_from_user(&pm, (struct ptrace_multi __user *)addr, sizeof(struct ptrace_multi));
+				len = pm.length;
+				switch ( pm.request){
+					case PTRACE_PEEKTEXT:
+					case PTRACE_PEEKDATA:
+					case PTRACE_PEEKUSR:
+						if (len <= 0) len=1;
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len*sizeof(long))) {
+							ret = -EIO;
+							break;
+						}
+						for (j=0; j<len && ret==0; j++)
+							ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr) + j*sizeof(long), (long) (pm.localaddr) + j*sizeof(long));
+						break;
+					case PTRACE_POKETEXT:
+					case PTRACE_POKEDATA:
+					case PTRACE_POKEUSR:
+						if (len <= 0) len=1;
+						if (!access_ok(VERIFY_READ, pm.localaddr,len*sizeof(long))) {
+							ret = -EIO;
+							break;
+						}
+						for (j=0; j<len && ret==0; j++)
+							ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr) + j*sizeof(long), *(((long *) (pm.localaddr)) + j));
+						break;
+					case PTRACE_PEEKCHARDATA:
+#if 0
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len)) {
+							ret = -EIO;
+							break;
+						}
+#endif
+						ret = ptrace_readdata(child, pm.addr, pm.localaddr, len);
+						break;
+					case PTRACE_POKECHARDATA:
+#if 0
+						if (!access_ok(VERIFY_READ, pm.localaddr,len)) {
+							ret = -EIO;
+							break;
+						}
+#endif
+						ret = ptrace_writedata(child, pm.localaddr, pm.addr, len);
+						break;
+					case PTRACE_PEEKSTRINGDATA:
+#if 0
+						if (!access_ok(VERIFY_WRITE, pm.localaddr,len)) {
+							ret = -EIO;
+							break;
+						}
+#endif
+						ret = ptrace_readstringdata(child, pm.addr, pm.localaddr, len);
+						break;
+					default:
+						ret=sys_ptrace_reqprocess(child, pm.request, (long) (pm.addr), (long) (pm.localaddr));
+						break;
+				}
+			}
+			break;
+		}
 	default:
 		ret = ptrace_request(child, request, addr, data);
 		break;
 	}
+	return ret;
+}
+
+long sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+
+		ret = security_ptrace(current->parent, current);
+		if (ret)
+ 			goto out;
+
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+#ifdef SUBACH_PTRACE_SPECIAL
+        SUBARCH_PTRACE_SPECIAL(child,request,addr,data);
+#endif
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0)
+		goto out_tsk;
+  ret=sys_ptrace_reqprocess(child,request,addr,data);
  out_tsk:
 	put_task_struct(child);
  out:
diff -uwr linux-source-2.6.14/include/linux/ptrace.h linux-source-2.6.14viewos/include/linux/ptrace.h
--- linux-source-2.6.14/include/linux/ptrace.h	2005-10-28 02:02:08.000000000 +0200
+++ linux-source-2.6.14viewos/include/linux/ptrace.h	2006-01-07 11:33:51.000000000 +0100
@@ -29,6 +29,18 @@
 #define PTRACE_GETSIGINFO	0x4202
 #define PTRACE_SETSIGINFO	0x4203
 
+#define PTRACE_MULTI 0x4300
+#define PTRACE_PEEKCHARDATA 0x4301
+#define PTRACE_POKECHARDATA 0x4302
+#define PTRACE_PEEKSTRINGDATA 0x4303
+
+struct ptrace_multi {
+	long request;
+	long addr;
+	void *localaddr;
+	long length;
+};
+
 /* options set using PTRACE_SETOPTIONS */
 #define PTRACE_O_TRACESYSGOOD	0x00000001
 #define PTRACE_O_TRACEFORK	0x00000002
@@ -80,6 +92,7 @@
 
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
+extern int ptrace_readstringdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
 extern int ptrace_attach(struct task_struct *tsk);
 extern int ptrace_detach(struct task_struct *, unsigned int);
 extern void ptrace_disable(struct task_struct *);
diff -uwr linux-source-2.6.14/kernel/ptrace.c linux-source-2.6.14um2/kernel/ptrace.c
--- linux-source-2.6.14/kernel/ptrace.c	2005-12-08 21:52:47.000000000 +0100
+++ linux-source-2.6.14viewos/kernel/ptrace.c	2006-01-07 13:32:29.000000000 +0100
@@ -255,8 +255,73 @@
 	return buf - old_buf;
 }
 
+/*
+ * Access another process' address space to/from user space
+ * Do not walk the page table directly, use get_user_pages
+ */
+static int access_process_vm_user(struct task_struct *tsk, unsigned long addr, char __user *ubuf, int len, int write, int string)
+{
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	struct page *page;
+	char *buf;
+	unsigned long old_addr = addr;
+
+	mm = get_task_mm(tsk);
+	if (!mm)
+		return 0;
+	
+	buf=kmalloc(PAGE_SIZE, GFP_KERNEL);
+	down_read(&mm->mmap_sem);
+	/* ignore errors, just check how much was sucessfully transfered */
+	while (len) {
+		int bytes, ret, offset;
+		void *maddr;
+
+		ret = get_user_pages(tsk, mm, addr, 1,
+				write, 1, &page, &vma);
+		if (ret <= 0)
+			break;
+
+		bytes = len;
+		offset = addr & (PAGE_SIZE-1);
+		if (bytes > PAGE_SIZE-offset)
+			bytes = PAGE_SIZE-offset;
+
+		maddr = kmap(page);
+		if (write) {
+			__copy_from_user(buf,ubuf,bytes);
+			copy_to_user_page(vma, page, addr,
+					maddr + offset, buf, bytes);
+			set_page_dirty_lock(page);
+		} else {
+			copy_from_user_page(vma, page, addr,
+					buf, maddr + offset, bytes);
+			if (string) {
+				for (offset=0;offset<bytes;offset++)
+					if (buf[offset]==0)
+						break;
+				if (offset < bytes)
+					bytes=len=offset+1;
+			}
+			__copy_to_user(ubuf,buf,bytes);
+		}
+		kunmap(page);
+		page_cache_release(page);
+		len -= bytes;
+		ubuf += bytes;
+		addr += bytes;
+	}
+	up_read(&mm->mmap_sem);
+	mmput(mm);
+	
+	kfree(buf);
+	return addr - old_addr;
+}
+
 int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
 {
+#if 0
 	int copied = 0;
 
 	while (len > 0) {
@@ -277,11 +342,22 @@
 		dst += retval;
 		len -= retval;			
 	}
-	return copied;
+#endif
+	if (!access_ok(VERIFY_WRITE, dst ,len)) 
+		return -EIO;
+	return access_process_vm_user(tsk, src, dst, len, 0, 0);
+}
+
+int ptrace_readstringdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
+{
+	if (!access_ok(VERIFY_WRITE, dst ,len))
+		return -EIO;
+	return access_process_vm_user(tsk, src, dst, len, 0, 1);
 }
 
 int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len)
 {
+#if 0
 	int copied = 0;
 
 	while (len > 0) {
@@ -303,6 +379,10 @@
 		len -= retval;			
 	}
 	return copied;
+#endif
+	if (!access_ok(VERIFY_READ, dst ,len))
+		return -EIO;
+	return access_process_vm_user(tsk, dst, src, len, 1, 0);
 }
 
 static int ptrace_setoptions(struct task_struct *child, long data)
