Title: [8234] trunk/arch/blackfin: initial Blackfin tracehook support

Diff

Modified: trunk/arch/blackfin/Kconfig (8233 => 8234)


--- trunk/arch/blackfin/Kconfig	2010-01-26 04:17:02 UTC (rev 8233)
+++ trunk/arch/blackfin/Kconfig	2010-01-26 07:33:53 UTC (rev 8234)
@@ -20,6 +20,7 @@
 config BLACKFIN
 	def_bool y
 	select HAVE_ARCH_KGDB
+	select HAVE_ARCH_TRACEHOOK
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST

Modified: trunk/arch/blackfin/include/asm/ptrace.h (8233 => 8234)


--- trunk/arch/blackfin/include/asm/ptrace.h	2010-01-26 04:17:02 UTC (rev 8233)
+++ trunk/arch/blackfin/include/asm/ptrace.h	2010-01-26 07:33:53 UTC (rev 8234)
@@ -24,6 +24,8 @@
 
 #ifndef __ASSEMBLY__
 
+struct task_struct;
+
 /* this struct defines the way the registers are stored on the
    stack during a system call. */
 
@@ -101,9 +103,29 @@
    master interrupt enable.  */
 #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
 #define instruction_pointer(regs) ((regs)->pc)
+#define user_stack_pointer(regs)  ((regs)->usp)
 #define profile_pc(regs) instruction_pointer(regs)
 extern void show_regs(struct pt_regs *);
 
+#define arch_has_single_step()	(1)
+extern void user_enable_single_step(struct task_struct *);
+/* see arch/blackfin/kernel/ptrace.c about this redirect */
+#define user_disable_single_step(child) ptrace_disable(child)
+
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
+ */
+#define task_pt_regs(task) \
+	(struct pt_regs *) \
+	    ((unsigned long)task_stack_page(task) + \
+	     (THREAD_SIZE - sizeof(struct pt_regs)))
+
 #endif  /*  __KERNEL__  */
 
 #endif				/* __ASSEMBLY__ */

Added: trunk/arch/blackfin/include/asm/syscall.h (0 => 8234)


--- trunk/arch/blackfin/include/asm/syscall.h	                        (rev 0)
+++ trunk/arch/blackfin/include/asm/syscall.h	2010-01-26 07:33:53 UTC (rev 8234)
@@ -0,0 +1,96 @@
+/*
+ * Magic syscall break down functions
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BLACKFIN_SYSCALL_H__
+#define __ASM_BLACKFIN_SYSCALL_H__
+
+/*
+ * Blackfin syscalls are simple:
+ *	enter:
+ *		p0: syscall number
+ *		r{0,1,2,3,4,5}: syscall args 0,1,2,3,4,5
+ *	exit:
+ *		r0: return/error value
+ */
+
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+
+static inline long
+syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+	return regs->p0;
+}
+
+static inline void
+syscall_rollback(struct task_struct *task, struct pt_regs *regs)
+{
+	/* was zu tun !? */
+}
+
+static inline long
+syscall_get_error(struct task_struct *task, struct pt_regs *regs)
+{
+	return IS_ERR_VALUE(regs->r0) ? regs->r0 : 0;
+}
+
+static inline long
+syscall_get_return_value(struct task_struct *task, struct pt_regs *regs)
+{
+	return regs->r0;
+}
+
+static inline void
+syscall_set_return_value(struct task_struct *task, struct pt_regs *regs,
+                         int error, long val)
+{
+	regs->r0 = error ? -error : val;
+}
+
+static inline void
+syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
+                      unsigned int i, unsigned int n, unsigned long *args)
+{
+	/* wtf is "i" ? */
+	BUG_ON(i);
+
+	switch (n) {
+	case 6: args[5] = regs->r5;
+	case 5: args[4] = regs->r4;
+	case 4: args[3] = regs->r3;
+	case 3: args[2] = regs->r2;
+	case 2: args[1] = regs->r1;
+	case 1: args[0] = regs->r0;
+		break;
+	default:
+		BUG();
+	}
+}
+
+static inline void
+syscall_set_arguments(struct task_struct *task, struct pt_regs *regs,
+                      unsigned int i, unsigned int n, const unsigned long *args)
+{
+	/* wtf is "i" ? */
+	BUG_ON(i);
+
+	switch (n) {
+	case 6: regs->r5 = args[5];
+	case 5: regs->r4 = args[4];
+	case 4: regs->r3 = args[3];
+	case 3: regs->r2 = args[2];
+	case 2: regs->r1 = args[1];
+	case 1: regs->r0 = args[0];
+		break;
+	default:
+		BUG();
+	}
+}
+
+#endif

Modified: trunk/arch/blackfin/kernel/ptrace.c (8233 => 8234)


--- trunk/arch/blackfin/kernel/ptrace.c	2010-01-26 04:17:02 UTC (rev 8233)
+++ trunk/arch/blackfin/kernel/ptrace.c	2010-01-26 07:33:53 UTC (rev 8234)
@@ -13,6 +13,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/signal.h>
+#include <linux/tracehook.h>
 #include <linux/uaccess.h>
 
 #include <asm/page.h>
@@ -37,32 +38,13 @@
 /* sets the trace bits. */
 #define TRACE_BITS 0x0001
 
-/* Find the stack offset for a register, relative to thread.esp0. */
-#define PT_REG(reg)	((long)&((struct pt_regs *)0)->reg)
-
 /*
- * Get the address of the live pt_regs for the specified task.
- * These are saved onto the top kernel stack when the process
- * is not running.
- *
- * Note: if a user thread is execve'd from kernel space, the
- * kernel stack will not be empty on entry to the kernel, so
- * ptracing these tasks will fail.
- */
-static inline struct pt_regs *get_user_regs(struct task_struct *task)
-{
-	return (struct pt_regs *)
-	    ((unsigned long)task_stack_page(task) +
-	     (THREAD_SIZE - sizeof(struct pt_regs)));
-}
-
-/*
  * Get all user integer registers.
  */
 static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
 {
 	struct pt_regs regs;
-	memcpy(&regs, get_user_regs(tsk), sizeof(regs));
+	memcpy(&regs, task_pt_regs(tsk), sizeof(regs));
 	regs.usp = tsk->thread.usp;
 	return copy_to_user(uregs, &regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
 }
@@ -78,10 +60,8 @@
 static inline long get_reg(struct task_struct *task, int regno)
 {
 	unsigned char *reg_ptr;
+	struct pt_regs *regs = task_pt_regs(task);
 
-	struct pt_regs *regs =
-	    (struct pt_regs *)((unsigned long)task_stack_page(task) +
-			       (THREAD_SIZE - sizeof(struct pt_regs)));
 	reg_ptr = (char *)regs;
 
 	switch (regno) {
@@ -104,10 +84,8 @@
 put_reg(struct task_struct *task, int regno, unsigned long data)
 {
 	char *reg_ptr;
+	struct pt_regs *regs = task_pt_regs(task);
 
-	struct pt_regs *regs =
-	    (struct pt_regs *)((unsigned long)task_stack_page(task) +
-			       (THREAD_SIZE - sizeof(struct pt_regs)));
 	reg_ptr = (char *)regs;
 
 	switch (regno) {
@@ -160,7 +138,7 @@
 	return -EIO;
 }
 
-void ptrace_enable(struct task_struct *child)
+void user_enable_single_step(struct task_struct *child)
 {
 	unsigned long tmp;
 	tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
@@ -168,6 +146,10 @@
 }
 
 /*
+ * This would be named user_disable_single_step(), but common code calls
+ * ptrace_disable() directly, so for now we redirect the former to the
+ * latter in our asm/ptrace.h.
+ *
  * Called by kernel/ptrace.c when detaching..
  *
  * Make sure the single step bit is not set.
@@ -366,7 +348,7 @@
 		else
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
-		ptrace_disable(child);
+		user_disable_single_step(child);
 		pr_debug("ptrace: before wake_up_process\n");
 		wake_up_process(child);
 		ret = 0;
@@ -382,7 +364,7 @@
 		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
 			break;
 		child->exit_code = SIGKILL;
-		ptrace_disable(child);
+		user_disable_single_step(child);
 		wake_up_process(child);
 		break;
 
@@ -392,7 +374,7 @@
 		if (!valid_signal(data))
 			break;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-		ptrace_enable(child);
+		user_enable_single_step(child);
 		child->exit_code = data;
 		wake_up_process(child);
 		ret = 0;
@@ -417,27 +399,18 @@
 	return ret;
 }
 
-asmlinkage void syscall_trace(void)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
+	int ret = 0;
 
-	if (!(current->ptrace & PT_PTRACED))
-		return;
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		ret = tracehook_report_syscall_entry(regs);
 
-	/* the 0x80 provides a way for the tracing parent to distinguish
-	 * between a syscall stop and SIGTRAP delivery
-	 */
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				 ? 0x80 : 0));
+	return ret;
+}
 
-	/*
-	 * 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;
-	}
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(regs, 0);
 }

Modified: trunk/arch/blackfin/kernel/signal.c (8233 => 8234)


--- trunk/arch/blackfin/kernel/signal.c	2010-01-26 04:17:02 UTC (rev 8233)
+++ trunk/arch/blackfin/kernel/signal.c	2010-01-26 07:33:53 UTC (rev 8234)
@@ -213,7 +213,7 @@
 	 */
 	if (regs->syscfg & TRACE_BITS) {
 		regs->syscfg &= ~TRACE_BITS;
-		ptrace_notify(SIGTRAP);
+		tracehook_signal_handler(sig, info, ka, regs, 0);
 	}
 
 	return 0;

Modified: trunk/arch/blackfin/mach-common/entry.S (8233 => 8234)


--- trunk/arch/blackfin/mach-common/entry.S	2010-01-26 04:17:02 UTC (rev 8233)
+++ trunk/arch/blackfin/mach-common/entry.S	2010-01-26 07:33:53 UTC (rev 8234)
@@ -736,7 +736,8 @@
  * this symbol need not be global anyways, so ...
  */
 _sys_trace:
-	pseudo_long_call _syscall_trace, p5;
+	r0 = sp;
+	pseudo_long_call _syscall_trace_enter, p5;
 
 	/* Execute the appropriate system call */
 
@@ -760,7 +761,8 @@
 	SP += 24;
 	[sp + PT_R0] = r0;
 
-	pseudo_long_call _syscall_trace, p5;
+	r0 = sp;
+	pseudo_long_call _syscall_trace_leave, p5;
 	jump .Lresume_userspace;
 ENDPROC(_sys_trace)
 
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to