Since Frederic did the x86 version, I just added him to the Cc here. -- Steve On Fri, 29 May 2009, wuzhangjin@xxxxxxxxx wrote: > From: Wu Zhangjin <wuzj@xxxxxxxxxx> > > FIXME: there are several different sys_call_entry in mips64, but > currently, i only use the the one in arch/mips/kernel/scall64-o32.S > so,if people not use o32 standard, it will not compiled normally. > > the system call tracing demo in a debian system on > qemu-system-mipsel/malta: > > debian-mips-malta:~# mount -t debugfs nodev /debug > debian-mips-malta:~# echo 20000 > /debug/tracing/buffer_size_kb > debian-mips-malta:~# cat /debug/tracing/available_tracers > syscall nop > debian-mips-malta:~# echo syscall > /debug/tracing/current_tracer > debian-mips-malta:~# echo 1 > /debug/tracing/tracing_enabled > debian-mips-malta:~# sleep 1 > debian-mips-malta:~# echo 0 > /debug/tracing/tracing_enabled > debian-mips-malta:~# cat /debug/tracing/trace | head -20 > <...>-533 [000] 60.458291: sys_write(fd: 1, buf: 4fc408, count: 8) > <...>-533 [000] 64.325614: sys_getrlimit(resource: 3, rlim: 530020) > <...>-533 [000] 64.327089: sys_read(fd: 2, buf: 4fc008, count: 6) > <...>-533 [000] 64.969663: sys_exit(error_code: 2) > <...>-533 [000] 65.608794: sys_exit(error_code: 2) > <...>-533 [000] 66.231796: sys_read(fd: 2, buf: 4fc008, count: 6) > <...>-533 [000] 66.913687: sys_open(filename: 1, flags: 0, mode: a) > <...>-533 [000] 66.914617: sys_exit(error_code: 1) > <...>-533 [000] 70.797507: sys_exit(error_code: 503be8) > <...>-536 [000] 70.833108: sys_exit(error_code: 2aac6cfc) > <...>-536 [000] 70.833897: sys_exit(error_code: 2aac6540) > <...>-536 [000] 70.835711: sys_exit(error_code: 2aac6cfc) > <...>-536 [000] 70.840609: sys_lchown(filename: 3, user: 7fb08b38, group: 20) > <...>-533 [000] 71.877785: sys_open(filename: ffffffff, flags: 7fcf08c8, mode: b) > <...>-533 [000] 75.531122: sys_open(filename: 1, flags: 0, mode: a) > > Signed-off-by: Wu Zhangjin <wuzj@xxxxxxxxxx> > --- > arch/mips/Kconfig | 1 + > arch/mips/include/asm/ptrace.h | 2 + > arch/mips/include/asm/reg.h | 5 ++ > arch/mips/include/asm/syscall.h | 84 +++++++++++++++++++++++++++++++++++ > arch/mips/include/asm/thread_info.h | 5 ++- > arch/mips/kernel/Makefile | 1 + > arch/mips/kernel/entry.S | 2 +- > arch/mips/kernel/ftrace.c | 71 +++++++++++++++++++++++++++++ > arch/mips/kernel/ptrace.c | 14 +++++- > arch/mips/kernel/scall64-o32.S | 2 +- > 10 files changed, 182 insertions(+), 5 deletions(-) > create mode 100644 arch/mips/include/asm/syscall.h > > diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig > index ac1437e..f488027 100644 > --- a/arch/mips/Kconfig > +++ b/arch/mips/Kconfig > @@ -10,6 +10,7 @@ config MIPS > select HAVE_FTRACE_MCOUNT_RECORD > select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE > select HAVE_FUNCTION_GRAPH_TRACER > + select HAVE_FTRACE_SYSCALLS > # Horrible source of confusion. Die, die, die ... > select EMBEDDED > select RTC_LIB > diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h > index ce47118..32e5b62 100644 > --- a/arch/mips/include/asm/ptrace.h > +++ b/arch/mips/include/asm/ptrace.h > @@ -45,6 +45,8 @@ struct pt_regs { > unsigned long cp0_badvaddr; > unsigned long cp0_cause; > unsigned long cp0_epc; > + /* Used for restarting system calls */ > + unsigned long orig_v0; > #ifdef CONFIG_MIPS_MT_SMTC > unsigned long cp0_tcstatus; > #endif /* CONFIG_MIPS_MT_SMTC */ > diff --git a/arch/mips/include/asm/reg.h b/arch/mips/include/asm/reg.h > index 634b55d..93d66bc 100644 > --- a/arch/mips/include/asm/reg.h > +++ b/arch/mips/include/asm/reg.h > @@ -65,6 +65,8 @@ > #define EF_CP0_CAUSE 43 > #define EF_UNUSED0 44 > > +#define EF_ORIG_V0 45 > + > #define EF_SIZE 180 > > #endif > @@ -121,6 +123,9 @@ > #define EF_CP0_STATUS 36 > #define EF_CP0_CAUSE 37 > > + > +#define EF_ORIG_V0 38 > + > #define EF_SIZE 304 /* size in bytes */ > > #endif /* CONFIG_64BIT */ > diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h > new file mode 100644 > index 0000000..b785098 > --- /dev/null > +++ b/arch/mips/include/asm/syscall.h > @@ -0,0 +1,84 @@ > +/* > + * Access to user system call parameters and results > + * > + * Copyright (C) 2008 Red Hat, Inc. All rights reserved. > + * Copyright (C) 2009 DSLab, Lanzhou University, China > + * Author: Wu Zhangjin <wuzj@xxxxxxxxxx> > + * > + * 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. > + * > + * See asm-generic/syscall.h for descriptions of what we must do here. > + */ > + > +#ifndef _ASM_SYSCALL_H > +#define _ASM_SYSCALL_H 1 > + > +#include <linux/sched.h> > + > +static inline long syscall_get_nr(struct task_struct *task, > + struct pt_regs *regs) > +{ > + /* syscall Exc-Code: 0 1000 00 v0 */ > + return ((regs->cp0_cause&0xff) == 0x20) ? regs->regs[2] : -1L; > +} > + > +static inline void syscall_rollback(struct task_struct *task, > + struct pt_regs *regs) > +{ > + regs->regs[2] = regs->orig_v0; > +} > + > +static inline long syscall_get_error(struct task_struct *task, > + struct pt_regs *regs) > +{ > + return regs->regs[2] ? -regs->regs[2] : 0; > +} > + > +static inline long syscall_get_return_value(struct task_struct *task, > + struct pt_regs *regs) > +{ > + return regs->regs[2]; > +} > + > +static inline void syscall_set_return_value(struct task_struct *task, > + struct pt_regs *regs, > + int error, long val) > +{ > + if (error) > + regs->regs[2] = -error; > + else > + regs->regs[2] = val; > +} > + > +static inline void syscall_get_arguments(struct task_struct *task, > + struct pt_regs *regs, > + unsigned int i, unsigned int n, > + unsigned long *args) > +{ > +#ifdef CONFIG_32BIT > + /* fixme: only 4 argument register available in mip32, so, how to handle > + * others? > + */ > + BUG_ON(i + n > 4); > +#else > + BUG_ON(i + n > 6); > +#endif > + memcpy(args, ®s->regs[4 + i], n * sizeof(args[0])); > +} > + > +static inline void syscall_set_arguments(struct task_struct *task, > + struct pt_regs *regs, > + unsigned int i, unsigned int n, > + const unsigned long *args) > +{ > +#ifdef CONFIG_32BIT > + BUG_ON(i + n > 4); > +#else > + BUG_ON(i + n > 6); > +#endif > + memcpy(®s->regs[4 + i], args, n * sizeof(args[0])); > +} > + > +#endif /* _ASM_SYSCALL_H */ > diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h > index 143a481..1d55dc0 100644 > --- a/arch/mips/include/asm/thread_info.h > +++ b/arch/mips/include/asm/thread_info.h > @@ -128,6 +128,7 @@ register struct thread_info *__current_thread_info __asm__("$28"); > #define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */ > #define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */ > #define TIF_LOAD_WATCH 25 /* If set, load watch registers */ > +#define TIF_SYSCALL_FTRACE 27 /* for ftrace syscall instrumentation */ > #define TIF_SYSCALL_TRACE 31 /* syscall trace active */ > > #ifdef CONFIG_MIPS32_O32 > @@ -151,11 +152,13 @@ register struct thread_info *__current_thread_info __asm__("$28"); > #define _TIF_32BIT_ADDR (1<<TIF_32BIT_ADDR) > #define _TIF_FPUBOUND (1<<TIF_FPUBOUND) > #define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH) > +#define _TIF_SYSCALL_FTRACE (1<<TIF_SYSCALL_FTRACE) > > /* work to do on interrupt/exception return */ > #define _TIF_WORK_MASK (0x0000ffef & ~_TIF_SECCOMP) > /* work to do on any return to u-space */ > -#define _TIF_ALLWORK_MASK (0x8000ffff & ~_TIF_SECCOMP) > +#define _TIF_ALLWORK_MASK \ > + ((0x8000ffff & ~_TIF_SECCOMP) | _TIF_SYSCALL_FTRACE) > > #endif /* __KERNEL__ */ > > diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile > index 5dec76f..8b4fafa 100644 > --- a/arch/mips/kernel/Makefile > +++ b/arch/mips/kernel/Makefile > @@ -34,6 +34,7 @@ obj-$(CONFIG_MODULES) += mips_ksyms.o module.o > > obj-$(CONFIG_FUNCTION_TRACER) += mcount.o > obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o > +obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o > obj-$(CONFIG_NOP_TRACER) += ftrace_clock.o > > obj-$(CONFIG_CPU_LOONGSON2) += r4k_fpu.o r4k_switch.o > diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S > index ffa3310..786e4ef 100644 > --- a/arch/mips/kernel/entry.S > +++ b/arch/mips/kernel/entry.S > @@ -167,7 +167,7 @@ work_notifysig: # deal with pending signals and > FEXPORT(syscall_exit_work_partial) > SAVE_STATIC > syscall_exit_work: > - li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT > + li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SYSCALL_FTRACE > and t0, a2 # a2 is preloaded with TI_FLAGS > beqz t0, work_pending # trace bit set? > local_irq_enable # could let do_syscall_trace() > diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c > index e7f15f7..5967998 100644 > --- a/arch/mips/kernel/ftrace.c > +++ b/arch/mips/kernel/ftrace.c > @@ -22,6 +22,8 @@ > #include <asm/asm.h> > #include <asm/unistd.h> > > +#include <trace/syscall.h> > + > #ifdef CONFIG_DYNAMIC_FTRACE > > #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ > @@ -287,3 +289,72 @@ out: > return parent_ip; > } > #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ > + > +#ifdef CONFIG_FTRACE_SYSCALLS > + > +extern unsigned long __start_syscalls_metadata[]; > +extern unsigned long __stop_syscalls_metadata[]; > + > +/* fixme: in mips64, there are different entries of sys_call_table when using > + * different standards, in loongson2f based machines: Fuloong & Yeeloong, the > + * system use o32 standard, so here, we only use the sys_call_table in > + * arch/mips/kernel/scall64-o32.S */ > + > +extern unsigned long *sys_call_table; > + > +static struct syscall_metadata **syscalls_metadata; > + > +static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) > +{ > + struct syscall_metadata *start; > + struct syscall_metadata *stop; > + char str[KSYM_SYMBOL_LEN]; > + > + > + start = (struct syscall_metadata *)__start_syscalls_metadata; > + stop = (struct syscall_metadata *)__stop_syscalls_metadata; > + kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str); > + > + for ( ; start < stop; start++) { > + if (start->name && !strcmp(start->name, str)) > + return start; > + } > + return NULL; > +} > + > +struct syscall_metadata *syscall_nr_to_meta(int nr) > +{ > + if (!syscalls_metadata || nr >= __NR_Linux_syscalls || nr < 0) > + return NULL; > + > + return syscalls_metadata[nr]; > +} > + > +void arch_init_ftrace_syscalls(void) > +{ > + int i; > + struct syscall_metadata *meta; > + unsigned long **psys_syscall_table = &sys_call_table; > + static atomic_t refs; > + > + if (atomic_inc_return(&refs) != 1) > + goto end; > + > + syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * > + __NR_Linux_syscalls, GFP_KERNEL); > + if (!syscalls_metadata) { > + WARN_ON(1); > + return; > + } > + > + for (i = 0; i < __NR_Linux_syscalls; i++) { > + meta = find_syscall_meta(psys_syscall_table[i]); > + syscalls_metadata[i] = meta; > + } > + return; > + > + /* Paranoid: avoid overflow */ > +end: > + atomic_dec(&refs); > +} > +#endif /* CONFIG_FTRACE_SYSCALLS */ > diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c > index 054861c..fa762dc 100644 > --- a/arch/mips/kernel/ptrace.c > +++ b/arch/mips/kernel/ptrace.c > @@ -25,6 +25,7 @@ > #include <linux/security.h> > #include <linux/audit.h> > #include <linux/seccomp.h> > +#include <linux/ftrace.h> > > #include <asm/byteorder.h> > #include <asm/cpu.h> > @@ -39,6 +40,7 @@ > #include <asm/bootinfo.h> > #include <asm/reg.h> > > +#include <trace/syscall.h> > /* > * Called by kernel/ptrace.c when detaching.. > * > @@ -60,7 +62,7 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data) > struct pt_regs *regs; > int i; > > - if (!access_ok(VERIFY_WRITE, data, 38 * 8)) > + if (!access_ok(VERIFY_WRITE, data, 39 * 8)) > return -EIO; > > regs = task_pt_regs(child); > @@ -73,6 +75,7 @@ int ptrace_getregs(struct task_struct *child, __s64 __user *data) > __put_user((long)regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); > __put_user((long)regs->cp0_status, data + EF_CP0_STATUS - EF_R0); > __put_user((long)regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); > + __put_user((long)regs->orig_v0, data + EF_ORIG_V0 - EF_R0); > > return 0; > } > @@ -87,7 +90,7 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data) > struct pt_regs *regs; > int i; > > - if (!access_ok(VERIFY_READ, data, 38 * 8)) > + if (!access_ok(VERIFY_READ, data, 39 * 8)) > return -EIO; > > regs = task_pt_regs(child); > @@ -97,6 +100,7 @@ int ptrace_setregs(struct task_struct *child, __s64 __user *data) > __get_user(regs->lo, data + EF_LO - EF_R0); > __get_user(regs->hi, data + EF_HI - EF_R0); > __get_user(regs->cp0_epc, data + EF_CP0_EPC - EF_R0); > + __get_user(regs->orig_v0, data + EF_ORIG_V0 - EF_R0); > > /* badvaddr, status, and cause may not be written. */ > > @@ -575,6 +579,9 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) > if (!(current->ptrace & PT_PTRACED)) > goto out; > > + if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) > + ftrace_syscall_exit(regs); > + > if (!test_thread_flag(TIF_SYSCALL_TRACE)) > goto out; > > @@ -594,6 +601,9 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) > } > > out: > + if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) > + ftrace_syscall_enter(regs); > + > if (unlikely(current->audit_context) && !entryexit) > audit_syscall_entry(audit_arch(), regs->regs[0], > regs->regs[4], regs->regs[5], > diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S > index a5598b2..dd1f13a 100644 > --- a/arch/mips/kernel/scall64-o32.S > +++ b/arch/mips/kernel/scall64-o32.S > @@ -202,7 +202,7 @@ einval: li v0, -ENOSYS > > .align 3 > .type sys_call_table,@object > -sys_call_table: > +EXPORT(sys_call_table) > PTR sys32_syscall /* 4000 */ > PTR sys_exit > PTR sys_fork > -- > 1.6.0.4 > >