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(®s, get_user_regs(tsk), sizeof(regs));
+ memcpy(®s, task_pt_regs(tsk), sizeof(regs));
regs.usp = tsk->thread.usp;
return copy_to_user(uregs, ®s, 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)