[PATCH] UML utrace support, step 1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Below is the first step in your Fix-Your-Broken-Arch-HOWTO for UML.

Do you want incremental patches as I go along, or replacement ones?

BTW, UML runs on the utrace in -mm (i.e. utrace on the host), which it
didn't with several Fedora kernels.

				Jeff

-- 
Work email - jdike at linux dot intel dot com



The first step in making the utrace arch changes for UML.  It builds
and runs now, but ptrace is broken.

Signed-off-by: Jeff Dike <[email protected]>
--
 arch/um/kernel/exec.c           |    1 
 arch/um/kernel/process.c        |    6 
 arch/um/kernel/ptrace.c         |  333 +++++-----------------------------------
 arch/um/kernel/signal.c         |    5 
 arch/um/kernel/skas/syscall.c   |    4 
 arch/um/sys-i386/signal.c       |    4 
 include/asm-um/ptrace-generic.h |    3 
 include/asm-um/tracehook.h      |   66 +++++++
 8 files changed, 115 insertions(+), 307 deletions(-)

Index: linux-2.6.18-mm/arch/um/kernel/exec.c
===================================================================
--- linux-2.6.18-mm.orig/arch/um/kernel/exec.c	2007-02-20 16:18:07.000000000 -0500
+++ linux-2.6.18-mm/arch/um/kernel/exec.c	2007-02-20 16:18:50.000000000 -0500
@@ -51,7 +51,6 @@ static long execve1(char *file, char __u
         error = do_execve(file, argv, env, &current->thread.regs);
         if (error == 0){
 		task_lock(current);
-                current->ptrace &= ~PT_DTRACE;
 #ifdef SUBARCH_EXECVE1
 		SUBARCH_EXECVE1(&current->thread.regs.regs);
 #endif
Index: linux-2.6.18-mm/arch/um/kernel/process.c
===================================================================
--- linux-2.6.18-mm.orig/arch/um/kernel/process.c	2007-02-20 16:18:07.000000000 -0500
+++ linux-2.6.18-mm/arch/um/kernel/process.c	2007-02-20 16:18:50.000000000 -0500
@@ -458,11 +458,11 @@ int singlestepping(void * t)
 {
 	struct task_struct *task = t ? t : current;
 
-	if ( ! (task->ptrace & PT_DTRACE) )
-		return(0);
+	if (!test_thread_flag(TIF_SINGLESTEP))
+		return 0;
 
 	if (task->thread.singlestep_syscall)
-		return(1);
+		return 1;
 
 	return 2;
 }
Index: linux-2.6.18-mm/arch/um/kernel/ptrace.c
===================================================================
--- linux-2.6.18-mm.orig/arch/um/kernel/ptrace.c	2007-02-20 16:18:07.000000000 -0500
+++ linux-2.6.18-mm/arch/um/kernel/ptrace.c	2007-02-20 16:18:50.000000000 -0500
@@ -3,261 +3,29 @@
  * Licensed under the GPL
  */
 
-#include "linux/sched.h"
-#include "linux/mm.h"
-#include "linux/errno.h"
-#include "linux/smp_lock.h"
-#include "linux/security.h"
-#include "linux/ptrace.h"
-#include "linux/audit.h"
-#ifdef CONFIG_PROC_MM
-#include "linux/proc_mm.h"
-#endif
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-#include "kern_util.h"
-#include "skas_ptrace.h"
-#include "sysdep/ptrace.h"
-#include "os.h"
-
-static inline void set_singlestepping(struct task_struct *child, int on)
+#include <linux/audit.h>
+#include <linux/elf.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/tracehook.h>
+
+const struct utrace_regset_view utrace_um_native = {
+	.name		= "um",
+	.e_machine	= ELF_ARCH,
+	.regsets	= NULL,
+	.n		= 0,
+};
+EXPORT_SYMBOL_GPL(utrace_um_native);
+
+int arch_ptrace(long *req, struct task_struct *child,
+		struct utrace_attached_engine *engine,
+		unsigned long addr, unsigned long data, long *val)
 {
-        if (on)
-                child->ptrace |= PT_DTRACE;
-        else
-                child->ptrace &= ~PT_DTRACE;
-        child->thread.singlestep_syscall = 0;
-
-#ifdef SUBARCH_SET_SINGLESTEPPING
-        SUBARCH_SET_SINGLESTEPPING(child, on);
-#endif
+	return -ENOSYS;
 }
 
-/*
- * Called by kernel/ptrace.c when detaching..
- */
-void ptrace_disable(struct task_struct *child)
-{ 
-        set_singlestepping(child,0);
-}
-
-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 arch_ptrace(struct task_struct *child, long request, long addr, long data)
-{
-	int i, ret;
-	unsigned long __user *p = (void __user *)(unsigned long)data;
-
-	switch (request) {
-		/* when I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-	case PTRACE_PEEKDATA: {
-		unsigned long tmp;
-		int copied;
-
-		ret = -EIO;
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		if (copied != sizeof(tmp))
-			break;
-		ret = put_user(tmp, p);
-		break;
-	}
-
-	/* read the word at location addr in the USER area. */
-        case PTRACE_PEEKUSR:
-                ret = peek_user(child, addr, data);
-                break;
-
-	/* when I and D space are separate, this will have to be fixed. */
-	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		ret = -EIO;
-		if (access_process_vm(child, addr, &data, sizeof(data), 
-				      1) != sizeof(data))
-			break;
-		ret = 0;
-		break;
-
-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-                ret = poke_user(child, addr, data);
-                break;
-
-	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-	case PTRACE_CONT: { /* restart after signal. */
-		ret = -EIO;
-		if (!valid_signal(data))
-			break;
-
-                set_singlestepping(child, 0);
-		if (request == PTRACE_SYSCALL) {
-			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		}
-		else {
-			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		}
-		child->exit_code = data;
-		wake_up_process(child);
-		ret = 0;
-		break;
-	}
-
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
-	case PTRACE_KILL: {
-		ret = 0;
-		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
-			break;
-
-                set_singlestepping(child, 0);
-		child->exit_code = SIGKILL;
-		wake_up_process(child);
-		break;
-	}
-
-	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
-		ret = -EIO;
-		if (!valid_signal(data))
-			break;
-		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-                set_singlestepping(child, 1);
-		child->exit_code = data;
-		/* give it a chance to run. */
-		wake_up_process(child);
-		ret = 0;
-		break;
-	}
-
-	case PTRACE_DETACH:
-		/* detach a process that was attached. */
-		ret = ptrace_detach(child, data);
- 		break;
-
-#ifdef PTRACE_GETREGS
-	case PTRACE_GETREGS: { /* Get all gp regs from the child. */
-		if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) {
-			ret = -EIO;
-			break;
-		}
-		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
-			__put_user(getreg(child, i), p);
-			p++;
-		}
-		ret = 0;
-		break;
-	}
-#endif
-#ifdef PTRACE_SETREGS
-	case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-		unsigned long tmp = 0;
-		if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) {
-			ret = -EIO;
-			break;
-		}
-		for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) {
-			__get_user(tmp, p);
-			putreg(child, i, tmp);
-			p++;
-		}
-		ret = 0;
-		break;
-	}
-#endif
-#ifdef PTRACE_GETFPREGS
-	case PTRACE_GETFPREGS: /* Get the child FPU state. */
-		ret = get_fpregs(data, child);
-		break;
-#endif
-#ifdef PTRACE_SETFPREGS
-	case PTRACE_SETFPREGS: /* Set the child FPU state. */
-	        ret = set_fpregs(data, child);
-		break;
-#endif
-#ifdef PTRACE_GETFPXREGS
-	case PTRACE_GETFPXREGS: /* Get the child FPU state. */
-		ret = get_fpxregs(data, child);
-		break;
-#endif
-#ifdef PTRACE_SETFPXREGS
-	case PTRACE_SETFPXREGS: /* Set the child FPU state. */
-		ret = set_fpxregs(data, child);
-		break;
-#endif
-	case PTRACE_GET_THREAD_AREA:
-		ret = ptrace_get_thread_area(child, addr,
-					     (struct user_desc __user *) data);
-		break;
-
-	case PTRACE_SET_THREAD_AREA:
-		ret = ptrace_set_thread_area(child, addr,
-					     (struct user_desc __user *) data);
-		break;
-
-	case PTRACE_FAULTINFO: {
-		/* Take the info from thread->arch->faultinfo,
-		 * but transfer max. sizeof(struct ptrace_faultinfo).
-		 * On i386, ptrace_faultinfo is smaller!
-		 */
-		ret = copy_to_user(p, &child->thread.arch.faultinfo,
-				   sizeof(struct ptrace_faultinfo));
-		if(ret)
-			break;
-		break;
-	}
-
-#ifdef PTRACE_LDT
-	case PTRACE_LDT: {
-		struct ptrace_ldt ldt;
-
-		if(copy_from_user(&ldt, p, sizeof(ldt))){
-			ret = -EIO;
-			break;
-		}
-
-		/* This one is confusing, so just punt and return -EIO for 
-		 * now
-		 */
-		ret = -EIO;
-		break;
-	}
-#endif
-#ifdef CONFIG_PROC_MM
-	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);
-		child->mm = new;
-		child->active_mm = new;
-		mmput(old);
-		ret = 0;
-		break;
-	}
-#endif
-#ifdef PTRACE_ARCH_PRCTL
-        case PTRACE_ARCH_PRCTL:
-                /* XXX Calls ptrace on the host - needs some SMP thinking */
-                ret = arch_prctl_skas(child, data, (void *) addr);
-                break;
-#endif
-	default:
-		ret = ptrace_request(child, request, addr, data);
-		break;
-	}
-
-	return ret;
-}
-
-void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
-		  int error_code)
+static void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+			 int error_code)
 {
 	struct siginfo info;
 
@@ -266,56 +34,39 @@ void send_sigtrap(struct task_struct *ts
 	info.si_code = TRAP_BRKPT;
 
 	/* User-mode eip? */
-	info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL;
+	info.si_addr = UPT_IS_USER(&regs->regs) ?
+		(void __user *) UPT_IP(&regs->regs) : NULL;
 
 	/* Send us the fakey SIGTRAP */
 	force_sig_info(SIGTRAP, &info, tsk);
 }
 
-/* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
- * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
+/* notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
  */
-void syscall_trace(union uml_pt_regs *regs, int entryexit)
+void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
-	int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
-	int tracesysgood;
+	/* do the secure computing check first */
+	if (!entryexit)
+		secure_computing(PT_REGS_SYSCALL_NR(regs));
+
+	if (unlikely(current->audit_context) && entryexit)
+		audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
+				   UPT_SYSCALL_RET(regs));
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall(regs, entryexit);
+
+	if (test_thread_flag(TIF_SINGLESTEP) && entryexit) {
+		send_sigtrap(current, regs, 0);	/* XXX */
+		tracehook_report_syscall_step(regs);
+	}
 
-	if (unlikely(current->audit_context)) {
-		if (!entryexit)
-			audit_syscall_entry(HOST_AUDIT_ARCH,
+	if (unlikely(current->audit_context) && !entryexit)
+		audit_syscall_entry(HOST_AUDIT_ARCH,
 					    UPT_SYSCALL_NR(regs),
 					    UPT_SYSCALL_ARG1(regs),
 					    UPT_SYSCALL_ARG2(regs),
 					    UPT_SYSCALL_ARG3(regs),
 					    UPT_SYSCALL_ARG4(regs));
-		else audit_syscall_exit(AUDITSC_RESULT(UPT_SYSCALL_RET(regs)),
-                                        UPT_SYSCALL_RET(regs));
-	}
-
-	/* Fake a debug trap */
-	if (is_singlestep)
-		send_sigtrap(current, regs, 0);
-
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
-
-	if (!(current->ptrace & PT_PTRACED))
-		return;
-
-	/* the 0x80 provides a way for the tracing parent to distinguish
-	   between a syscall stop and SIGTRAP delivery */
-	tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
-	ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
-
-	if (entryexit) /* force do_signal() --> is_syscall() */
-		set_thread_flag(TIF_SIGPENDING);
-
-	/* this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
 }
Index: linux-2.6.18-mm/include/asm-um/tracehook.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.18-mm/include/asm-um/tracehook.h	2007-02-20 16:18:50.000000000 -0500
@@ -0,0 +1,66 @@
+/*
+ * Tracing hooks, i386 CPU support
+ *
+ * Copyright (C) 2006, 2007 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * Red Hat Author: Roland McGrath.
+ *
+ * Munged for UML - jdike@{addtoit,linux.intel}.com
+ */
+
+#ifndef _ASM_TRACEHOOK_H
+#define _ASM_TRACEHOOK_H	1
+
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+
+/*
+ * See linux/tracehook.h for the descriptions of what these need to do.
+ */
+
+#define ARCH_HAS_SINGLE_STEP	(1)
+
+static inline void tracehook_enable_single_step(struct task_struct *tsk)
+{
+	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline void tracehook_disable_single_step(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline int tracehook_single_step_enabled(struct task_struct *tsk)
+{
+	return test_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+}
+
+static inline void tracehook_enable_syscall_trace(struct task_struct *tsk)
+{
+	set_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_disable_syscall_trace(struct task_struct *tsk)
+{
+	clear_tsk_thread_flag(tsk, TIF_SYSCALL_TRACE);
+}
+
+static inline void tracehook_abort_syscall(struct pt_regs *regs)
+{
+	PT_REGS_SYSCALL_NR(regs) = -1;
+}
+
+extern const struct utrace_regset_view utrace_um_native;
+static inline const struct utrace_regset_view *
+utrace_native_view(struct task_struct *tsk)
+{
+	return &utrace_um_native;
+}
+
+
+#endif
Index: linux-2.6.18-mm/arch/um/kernel/signal.c
===================================================================
--- linux-2.6.18-mm.orig/arch/um/kernel/signal.c	2007-02-20 16:18:37.000000000 -0500
+++ linux-2.6.18-mm/arch/um/kernel/signal.c	2007-02-20 16:18:50.000000000 -0500
@@ -14,6 +14,7 @@
 #include "linux/tty.h"
 #include "linux/binfmts.h"
 #include "linux/ptrace.h"
+#include "linux/tracehook.h"
 #include "asm/signal.h"
 #include "asm/uaccess.h"
 #include "asm/unistd.h"
@@ -93,6 +94,8 @@ static int handle_signal(struct pt_regs 
 			sigaddset(&current->blocked, signr);
 		recalc_sigpending();
 		spin_unlock_irq(&current->sighand->siglock);
+
+		tracehook_report_handle_signal(signr, ka, oldset, regs);
 	}
 
 	return err;
@@ -148,7 +151,7 @@ static int kern_do_signal(struct pt_regs
 	 * on the host.  The tracing thread will check this flag and
 	 * PTRACE_SYSCALL if necessary.
 	 */
-	if(current->ptrace & PT_DTRACE)
+	if(test_thread_flag(TIF_SYSCALL_TRACE))
 		current->thread.singlestep_syscall =
 			is_syscall(PT_REGS_IP(&current->thread.regs));
 
Index: linux-2.6.18-mm/arch/um/kernel/skas/syscall.c
===================================================================
--- linux-2.6.18-mm.orig/arch/um/kernel/skas/syscall.c	2007-02-20 16:18:07.000000000 -0500
+++ linux-2.6.18-mm/arch/um/kernel/skas/syscall.c	2007-02-20 16:18:50.000000000 -0500
@@ -19,8 +19,6 @@ void handle_syscall(union uml_pt_regs *r
 	long result;
 	int syscall;
 
-	syscall_trace(r, 0);
-
 	current->thread.nsyscalls++;
 	nsyscalls++;
 
@@ -38,6 +36,4 @@ void handle_syscall(union uml_pt_regs *r
 	else result = EXECUTE_SYSCALL(syscall, regs);
 
 	REGS_SET_SYSCALL_RETURN(r->skas.regs, result);
-
-	syscall_trace(r, 1);
 }
Index: linux-2.6.18-mm/arch/um/sys-i386/signal.c
===================================================================
--- linux-2.6.18-mm.orig/arch/um/sys-i386/signal.c	2007-02-20 16:18:07.000000000 -0500
+++ linux-2.6.18-mm/arch/um/sys-i386/signal.c	2007-02-20 16:18:50.000000000 -0500
@@ -267,8 +267,6 @@ int setup_signal_stack_sc(unsigned long 
 	PT_REGS_EDX(regs) = (unsigned long) 0;
 	PT_REGS_ECX(regs) = (unsigned long) 0;
 
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
-		ptrace_notify(SIGTRAP);
 	return 0;
 
 err:
@@ -324,8 +322,6 @@ int setup_signal_stack_si(unsigned long 
 	PT_REGS_EDX(regs) = (unsigned long) &frame->info;
 	PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
 
-	if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
-		ptrace_notify(SIGTRAP);
 	return 0;
 
 err:
Index: linux-2.6.18-mm/include/asm-um/ptrace-generic.h
===================================================================
--- linux-2.6.18-mm.orig/include/asm-um/ptrace-generic.h	2007-02-20 16:18:07.000000000 -0500
+++ linux-2.6.18-mm/include/asm-um/ptrace-generic.h	2007-02-20 16:18:50.000000000 -0500
@@ -44,9 +44,6 @@ extern int set_fpxregs(unsigned long buf
 
 extern void show_regs(struct pt_regs *regs);
 
-extern void send_sigtrap(struct task_struct *tsk, union uml_pt_regs *regs,
-			 int error_code);
-
 extern int arch_copy_tls(struct task_struct *new);
 extern void clear_flushed_tls(struct task_struct *task);
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux