ARM support for syscall tracing
Subsystems (2)
cover ARM support for syscall tracing
This is a rework of Steven Walter's syscall tracing patches first posted here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074454.html
I've rebased the patches against the current mainline master branch, as well as implemented several changes based on feedback from Will Deacon and Russel King.
Wade Farnsworth (3):
ARM: add support for the generic syscall.h interface
ARM: add TRACEHOOK support
ARM: support syscall tracing
arch/arm/Kconfig | 2 + arch/arm/include/asm/ptrace.h | 5 ++ arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/thread_info.h | 2 + arch/arm/include/asm/unistd.h | 12 +++++ arch/arm/kernel/entry-common.S | 16 +++++- arch/arm/kernel/ptrace.c | 34 +++++++------ arch/arm/kernel/signal.c | 2 + 8 files changed, 149 insertions(+), 17 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
PATCH 1/3 ARM: add support for the generic syscall.h interface
Supplying the asm-generic/syscall.h interface is a pre-requisite for HAVE_ARCH_TRACEHOOK
--- arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
arch/arm/include/asm/syscall.h new file +93 -0
@@ -0,0 +1,93 @@ +/* +* Access to user system call parameters and results +* +* See asm-generic/syscall.h for descriptions of what we must do here. +*/ + +#ifndef _ASM_ARM_SYSCALL_H +#define _ASM_ARM_SYSCALL_H + +#include <linux/err.h> + +extern const unsigned long sys_call_table[]; + +static inline int syscall_get_nr (struct task_struct *task, +struct pt_regs *regs) +{ +return task_thread_info (task)->syscall; +} + +static inline void syscall_rollback (struct task_struct *task, +struct pt_regs *regs) +{ + regs->ARM_r0 = regs->ARM_ORIG_r0; +} + +static inline long syscall_get_error (struct task_struct *task, +struct pt_regs *regs) +{ +unsigned long error = regs->ARM_r0; +return IS_ERR_VALUE (error) ? error :0 ; +} + +static inline long syscall_get_return_value (struct task_struct *task, +struct pt_regs *regs) +{ +return regs->ARM_r0; +} + +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->ARM_r0 = (long ) error ?: val; +} + +#define SYSCALL_MAX_ARGS 7 + +static inline void syscall_get_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned int i,unsigned int n, +unsigned long *args) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +unsigned long *args_bad = args +SYSCALL_MAX_ARGS - i; +unsigned int n_bad = n + i -SYSCALL_MAX_ARGS ; +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); +memset (args_bad,0 , n_bad *sizeof (args[0 ])); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + args[0 ] = regs->ARM_ORIG_r0; + args++; + i++; + n--; + } + +memcpy (args, ®s->ARM_r0 + 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) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + regs->ARM_ORIG_r0 = args[0 ]; + args++; + i++; + n--; + } + +memcpy (®s->ARM_r0 + i, args, n *sizeof (args[0 ])); +} + +#endif /* _ASM_ARM_SYSCALL_H */
Signature · 1 line
1.7.0.4
PATCH v2 1/3 ARM: add support for the generic syscall.h interface
Hi Wade,
Quoted 9 lines · Wade Farnsworth
Supplying the
asm-generic/syscall.hinterface is a pre-requisite forHAVE_ARCH_TRACEHOOKSigned-off-by Steven Walter <[email protected]>Signed-off-by Wade Farnsworth <[email protected]>--- arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
[...]
arch/arm/include/asm/syscall.h line 44
Quoted 7 lines
arch/arm/include/asm/syscall.h new file +7
-0+ +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->ARM_r0 = (long ) error ?: val; +}
This looks like far too much fun for kernel code, although I see that '?:' does appear elsewhere in the kernel. Usually in perl regexs though :)
Will
PATCH 1/3 ARM: add support for the generic syscall.h interface
Quoted 15 lines · Will Deacon
Hi Wade,
Quoted 9 lines · Wade Farnsworth
Supplying the
asm-generic/syscall.hinterface is a pre-requisite forHAVE_ARCH_TRACEHOOKSigned-off-by Steven Walter<[email protected]>Signed-off-by Wade Farnsworth<[email protected]>--- arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-)create mode 100644
arch/arm/include/asm/syscall.h[...]
Quoted 11 lines
arch/arm/include/asm/syscall.h line 44
Quoted 7 lines
arch/arm/include/asm/syscall.h new file +7
-0+ +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->ARM_r0 = (long ) error ?: val; +}This looks like far too much fun for kernel code, although I see that '?:' does appear elsewhere in the kernel. Usually in perl regexs though :)
OK, I'll change this to
regs->ARM_r0 = (long) error ? error : val;
That better? :)
Thanks,
-Wade
PATCH 2/3 ARM: add TRACEHOOK support
In reply to Wade FarnsworthAdd calls to tracehook_report_syscall_{entry,exit} and tracehook_signal_handler
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/ptrace.h | 5 +++++ arch/arm/kernel/ptrace.c | 21 ++++++--------------- arch/arm/kernel/signal.c | 2 ++ 4 files changed, 14 insertions(+), 15 deletions(-)
arch/arm/Kconfig +1 -0
@@ -10,6 +10,7 @@ config ARM select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/ptrace.h +5 -0
@@ -249,6 +249,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)return regs->ARM_sp; } +static inline unsigned long user_stack_pointer (struct pt_regs *regs) +{ +return regs->ARM_sp; +} +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */
arch/arm/kernel/ptrace.c +6 -15
@@ -23,6 +23,7 @@#include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <linux/regset.h> +#include <linux/tracehook.h> #include <asm/pgtable.h> #include <asm/system.h>
@@ -923,24 +924,14 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)if (!test_thread_flag (TIF_SYSCALL_TRACE ))return scno; -if (!(current->ptrace &PT_PTRACED )) -return scno;current_thread_info ()->syscall = scno; -/* 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 )); -/* -* 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 ; - } +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + regs->ARM_ip = ip;return current_thread_info ()->syscall;
arch/arm/kernel/signal.c +2 -0
@@ -644,6 +644,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,recalc_sigpending ();spin_unlock_irq (&tsk->sighand->siglock); +tracehook_signal_handler (sig, info, ka, regs,0 ); +return 0 ; }
Signature · 1 line
1.7.0.4
PATCH 3/3 ARM: support syscall tracing
In reply to Wade FarnsworthAs specified by ftrace-design.txt, TIF_SYSCALL_TRACEPOINT was added, as well as NR_syscalls in asm/unistd.h. Additionally, __sys_trace was modified to call trace_sys_enter and trace_sys_exit when appropriate.
Tests #2 - #4 of "perf test" now complete successfully.
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/thread_info.h | 2 ++ arch/arm/include/asm/unistd.h | 12 ++++++++++++ arch/arm/kernel/entry-common.S | 16 ++++++++++++++-- arch/arm/kernel/ptrace.c | 23 ++++++++++++++++++----- 5 files changed, 47 insertions(+), 7 deletions(-)
arch/arm/Kconfig +1 -0
@@ -11,6 +11,7 @@ config ARM select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK + select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/thread_info.h +2 -0
@@ -146,6 +146,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define TIF_MEMDIE 18/* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20#define TIF_SECCOMP 21 +#define TIF_SYSCALL_TRACEPOINT 22#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -156,6 +157,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)/* Checks for any syscall work in entry-common.S */ #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
arch/arm/include/asm/unistd.h +12 -0
@@ -405,6 +405,18 @@#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) +#ifdef __KERNEL__ + +/* This may need to be greater than __NR_last_syscall+1 in order to +* account for the padding in the syscall table */ +#define __NR_syscalls (380) + +#ifndef __ASSEMBLY__ +#define NR_syscalls (__NR_syscalls) +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ +/* * The following SWIs are ARM private. */
arch/arm/kernel/entry-common.S +14 -2
@@ -79,6 +79,11 @@ no_work_pending: ENDPROC(ret_to_user_from_irq) ENDPROC(ret_to_user) +.macro test_syscall_tracing reg + tst \reg, #_TIF_SYSCALL_WORK + tsteq \reg, #_TIF_SYSCALL_TRACEPOINT +.endm + /* * This is how we return from a fork. */
@@ -87,7 +92,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r1 beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1]
@@ -98,6 +103,13 @@ ENDPROC(ret_from_fork) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" + +/* Ensure that the system call table is not larger than __NR_syscalls, + * which is the value the rest of the system sees */ +.ifgt NR_syscalls - __NR_syscalls +.error "__NR_syscalls is less than the size of the syscall table" +.endif + #undef CALL #define CALL(x) .long x
@@ -446,7 +458,7 @@ ENTRY(vector_swi) 1: #endif - tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r10 bne __sys_trace cmp scno, #NR_syscalls @ check upper syscall limit
arch/arm/kernel/ptrace.c +18 -5
@@ -29,6 +29,9 @@#include <asm/system.h> #include <asm/traps.h> +#define CREATE_TRACE_POINTS +#include <trace/events/syscalls.h> +#define REG_PC 15#define REG_PSR 16/*
@@ -922,15 +925,25 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)audit_syscall_entry (AUDIT_ARCH_ARMEB , scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); -if (!test_thread_flag (TIF_SYSCALL_TRACE )) +if (!test_thread_flag (TIF_SYSCALL_TRACE ) && + !test_thread_flag (TIF_SYSCALL_TRACEPOINT ))return scno;current_thread_info ()->syscall = scno; -if (why) -tracehook_report_syscall_exit (regs,0 ); -else if (tracehook_report_syscall_entry (regs)) -current_thread_info ()->syscall =-1 ; +if (test_thread_flag (TIF_SYSCALL_TRACE )) { +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + } + +if (test_thread_flag (TIF_SYSCALL_TRACEPOINT )) { +if (why) +trace_sys_exit (regs, scno); +else +trace_sys_enter (regs, scno); + } regs->ARM_ip = ip;
Signature · 1 line
1.7.0.4
PATCH v2 3/3 ARM: support syscall tracing
Quoted 10 lines · Wade Farnsworth
As specified by ftrace-design.txt,
TIF_SYSCALL_TRACEPOINTwas added, as well asNR_syscallsinasm/unistd.h. Additionally,__sys_tracewas modified to calltrace_sys_enterandtrace_sys_exitwhen appropriate.Tests #2 - #4 of "perf test" now complete successfully.
Signed-off-by Steven Walter <[email protected]>Signed-off-by Wade Farnsworth <[email protected]>---
[...]
arch/arm/include/asm/unistd.h line 412
Quoted 13 lines
arch/arm/include/asm/unistd.h +5
-0@@ -405,6 +405,18 @@#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) +#ifdef __KERNEL__ + +/* This may need to be greater than __NR_last_syscall+1 in order to +* account for the padding in the syscall table */ +#define __NR_syscalls (380)
Do we actually have padding in the syscall table? It looks like a list of .long to me. I'd rather put the correct number in if possible.
arch/arm/include/asm/unistd.h line 416
Quoted 3 lines
arch/arm/include/asm/unistd.h +3
-0+#ifndef __ASSEMBLY__ +#define NR_syscalls (__NR_syscalls) +#endif /* __ASSEMBLY__ */
Hmm, these guards feel like a hack. Would moving the define into syscall.h help?
Quoted 26 lines
arch/arm/kernel/entry-common.S +6
-1@@ -79,6 +79,11 @@ no_work_pending: ENDPROC(ret_to_user_from_irq) ENDPROC(ret_to_user) +.macro test_syscall_tracing reg + tst \reg, #_TIF_SYSCALL_WORK + tsteq \reg, #_TIF_SYSCALL_TRACEPOINT +.endm + /* * This is how we return from a fork. */@@ -87,7 +92,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r1 beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1]
arch/arm/kernel/entry-common.S ENDPROC(ret_from_fork) · line 111
Quoted 9 lines
arch/arm/kernel/entry-common.S +6
-0@@ -98,6 +103,13 @@ ENDPROC(ret_from_fork) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" + +/* Ensure that the system call table is not larger than __NR_syscalls, + * which is the value the rest of the system sees */ +.ifgt NR_syscalls - __NR_syscalls +.error "__NR_syscalls is less than the size of the syscall table" +.endif
I think it would also be nice to check for equality here if we can.
Rest of the code looks alright, but it should be tested with OABI if it hasn't been already.
Will
PATCH 3/3 ARM: support syscall tracing
Quoted 22 lines · Will Deacon
Quoted 10 lines · Wade Farnsworth
As specified by ftrace-design.txt,
TIF_SYSCALL_TRACEPOINTwas added, as well asNR_syscallsinasm/unistd.h. Additionally,__sys_tracewas modified to calltrace_sys_enterandtrace_sys_exitwhen appropriate.Tests #2 - #4 of "perf test" now complete successfully.
Signed-off-by Steven Walter<[email protected]>Signed-off-by Wade Farnsworth<[email protected]>---
[...]
Quoted 8 lines
arch/arm/include/asm/unistd.h +0
-0@@ -405,6 +405,18 @@#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
Quoted 8 lines
arch/arm/include/asm/unistd.h line 412
Quoted 5 lines
arch/arm/include/asm/unistd.h +5
-0+#ifdef __KERNEL__ + +/* This may need to be greater than __NR_last_syscall+1 in order to +* account for the padding in the syscall table */ +#define __NR_syscalls (380)Do we actually have padding in the syscall table? It looks like a list of .long to me. I'd rather put the correct number in if possible.
This patch will calculate NR_syscalls by counting the number of entries in calls.S. calls.S may add up to three entries of padding at the end of that file that __NR_syscalls needs to account for.
Quoted 7 lines
arch/arm/include/asm/unistd.h line 416
Quoted 4 lines
arch/arm/include/asm/unistd.h +3
-0+#ifndef __ASSEMBLY__ +#define NR_syscalls (__NR_syscalls) +#endif /* __ASSEMBLY__ */ Hmm, these guards feel like a hack. Would moving the define into
syscall.hhelp?
I'll give this a shot, though I'll also note that adding the guards on !__ASSEMBLY__ was suggested by Russel:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074506.html
Quoted 30 lines
Quoted 30 lines
arch/arm/kernel/entry-common.S +6
-1@@ -79,6 +79,11 @@ no_work_pending: ENDPROC(ret_to_user_from_irq) ENDPROC(ret_to_user) +.macro test_syscall_tracing reg + tst \reg, #_TIF_SYSCALL_WORK + tsteq \reg, #_TIF_SYSCALL_TRACEPOINT +.endm + /* * This is how we return from a fork. */@@ -87,7 +92,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r1 beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1]@@ -98,6 +103,13 @@ ENDPROC(ret_from_fork) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S"
Quoted 8 lines
arch/arm/kernel/entry-common.S ENDPROC(ret_from_fork) · line 111
Quoted 6 lines
arch/arm/kernel/entry-common.S +6
-0+ +/* Ensure that the system call table is not larger than __NR_syscalls, + * which is the value the rest of the system sees */ +.ifgt NR_syscalls - __NR_syscalls +.error "__NR_syscalls is less than the size of the syscall table" +.endifI think it would also be nice to check for equality here if we can.
Should be doable.
Quoted 4 lines
Rest of the code looks alright, but it should be tested with OABI if it hasn't been already.
I might be able to build my userspace against OABI. I'll see what I can dig up.
Thanks for the review!
-Wade
v2 cover ARM support for syscall tracing
In reply to Wade FarnsworthThis is a rework of Steven Walter's syscall tracing patches first posted here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074454.html
I've rebased the patches against the current mainline master branch, as well as implemented several changes based on feedback from Will Deacon and Russel King.
v2: - Tested on EABI and OABI.
- Removed an instance of the ?: operator in syscall_set_return_value()
- Moved #define of NR_syscalls to syscall.h
- Changed the test of NR_syscalls vs __NR_syscalls in entry-common.S to .ifne
Wade Farnsworth (3):
ARM: add support for the generic syscall.h interface
ARM: add TRACEHOOK support
ARM: support syscall tracing
arch/arm/Kconfig | 2 + arch/arm/include/asm/ptrace.h | 5 ++ arch/arm/include/asm/syscall.h | 97 ++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/thread_info.h | 2 + arch/arm/include/asm/unistd.h | 8 +++ arch/arm/kernel/entry-common.S | 16 +++++- arch/arm/kernel/ptrace.c | 34 +++++++------ arch/arm/kernel/signal.c | 2 + 8 files changed, 149 insertions(+), 17 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
PATCH v2 1/3 ARM: add support for the generic syscall.h interface
Supplying the asm-generic/syscall.h interface is a pre-requisite for HAVE_ARCH_TRACEHOOK
--- arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
arch/arm/include/asm/syscall.h new file +93 -0
@@ -0,0 +1,93 @@ +/* +* Access to user system call parameters and results +* +* See asm-generic/syscall.h for descriptions of what we must do here. +*/ + +#ifndef _ASM_ARM_SYSCALL_H +#define _ASM_ARM_SYSCALL_H + +#include <linux/err.h> + +extern const unsigned long sys_call_table[]; + +static inline int syscall_get_nr (struct task_struct *task, +struct pt_regs *regs) +{ +return task_thread_info (task)->syscall; +} + +static inline void syscall_rollback (struct task_struct *task, +struct pt_regs *regs) +{ + regs->ARM_r0 = regs->ARM_ORIG_r0; +} + +static inline long syscall_get_error (struct task_struct *task, +struct pt_regs *regs) +{ +unsigned long error = regs->ARM_r0; +return IS_ERR_VALUE (error) ? error :0 ; +} + +static inline long syscall_get_return_value (struct task_struct *task, +struct pt_regs *regs) +{ +return regs->ARM_r0; +} + +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->ARM_r0 = (long ) error ? error : val; +} + +#define SYSCALL_MAX_ARGS 7 + +static inline void syscall_get_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned int i,unsigned int n, +unsigned long *args) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +unsigned long *args_bad = args +SYSCALL_MAX_ARGS - i; +unsigned int n_bad = n + i -SYSCALL_MAX_ARGS ; +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); +memset (args_bad,0 , n_bad *sizeof (args[0 ])); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + args[0 ] = regs->ARM_ORIG_r0; + args++; + i++; + n--; + } + +memcpy (args, ®s->ARM_r0 + 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) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + regs->ARM_ORIG_r0 = args[0 ]; + args++; + i++; + n--; + } + +memcpy (®s->ARM_r0 + i, args, n *sizeof (args[0 ])); +} + +#endif /* _ASM_ARM_SYSCALL_H */
Signature · 1 line
1.7.0.4
PATCH v2 2/3 ARM: add TRACEHOOK support
In reply to Wade FarnsworthAdd calls to tracehook_report_syscall_{entry,exit} and tracehook_signal_handler
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/ptrace.h | 5 +++++ arch/arm/kernel/ptrace.c | 21 ++++++--------------- arch/arm/kernel/signal.c | 2 ++ 4 files changed, 14 insertions(+), 15 deletions(-)
arch/arm/Kconfig +1 -0
@@ -10,6 +10,7 @@ config ARM select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/ptrace.h +5 -0
@@ -249,6 +249,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)return regs->ARM_sp; } +static inline unsigned long user_stack_pointer (struct pt_regs *regs) +{ +return regs->ARM_sp; +} +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */
arch/arm/kernel/ptrace.c +6 -15
@@ -24,6 +24,7 @@#include <linux/hw_breakpoint.h> #include <linux/regset.h> #include <linux/audit.h> +#include <linux/tracehook.h> #include <asm/pgtable.h> #include <asm/system.h>
@@ -930,24 +931,14 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)if (!test_thread_flag (TIF_SYSCALL_TRACE ))return scno; -if (!(current->ptrace &PT_PTRACED )) -return scno;current_thread_info ()->syscall = scno; -/* 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 )); -/* -* 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 ; - } +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + regs->ARM_ip = ip;return current_thread_info ()->syscall;
arch/arm/kernel/signal.c +2 -0
@@ -644,6 +644,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,recalc_sigpending ();spin_unlock_irq (&tsk->sighand->siglock); +tracehook_signal_handler (sig, info, ka, regs,0 ); +return 0 ; }
Signature · 1 line
1.7.0.4
PATCH v2 3/3 ARM: support syscall tracing
In reply to Wade FarnsworthAs specified by ftrace-design.txt, TIF_SYSCALL_TRACEPOINT was added, as well as NR_syscalls in asm/unistd.h. Additionally, __sys_trace was modified to call trace_sys_enter and trace_sys_exit when appropriate.
Tests #2 - #4 of "perf test" now complete successfully.
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/syscall.h | 4 ++++ arch/arm/include/asm/thread_info.h | 2 ++ arch/arm/include/asm/unistd.h | 8 ++++++++ arch/arm/kernel/entry-common.S | 16 ++++++++++++++-- arch/arm/kernel/ptrace.c | 23 ++++++++++++++++++----- 6 files changed, 47 insertions(+), 7 deletions(-)
arch/arm/Kconfig +1 -0
@@ -11,6 +11,7 @@ config ARM select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK + select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/syscall.h +4 -0
@@ -9,6 +9,10 @@#include <linux/err.h> +#include <asm/unistd.h> + +#define NR_syscalls (__NR_syscalls) +extern const unsigned long sys_call_table[]; static inline int syscall_get_nr(struct task_struct *task,
arch/arm/include/asm/thread_info.h +2 -0
@@ -146,6 +146,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define TIF_MEMDIE 18/* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20#define TIF_SECCOMP 21 +#define TIF_SYSCALL_TRACEPOINT 22#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -156,6 +157,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)/* Checks for any syscall work in entry-common.S */ #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
arch/arm/include/asm/unistd.h +8 -0
@@ -406,6 +406,14 @@#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)/* +* This may need to be greater than __NR_last_syscall+1 in order to +* account for the padding in the syscall table +*/ +#ifdef __KERNEL__ +#define __NR_syscalls (380) +#endif /* __KERNEL__ */ + +/* * The following SWIs are ARM private. */ #define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
arch/arm/kernel/entry-common.S +14 -2
@@ -79,6 +79,11 @@ no_work_pending: ENDPROC(ret_to_user_from_irq) ENDPROC(ret_to_user) +.macro test_syscall_tracing reg + tst \reg, #_TIF_SYSCALL_WORK + tsteq \reg, #_TIF_SYSCALL_TRACEPOINT +.endm + /* * This is how we return from a fork. */
@@ -87,7 +92,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r1 beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1]
@@ -98,6 +103,13 @@ ENDPROC(ret_from_fork) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" + +/* Ensure that the system call table is not larger than __NR_syscalls, + * which is the value the rest of the system sees */ +.ifne NR_syscalls - __NR_syscalls +.error "__NR_syscalls is less than the size of the syscall table" +.endif + #undef CALL #define CALL(x) .long x
@@ -446,7 +458,7 @@ ENTRY(vector_swi) 1: #endif - tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r10 bne __sys_trace cmp scno, #NR_syscalls @ check upper syscall limit
arch/arm/kernel/ptrace.c +18 -5
@@ -30,6 +30,9 @@#include <asm/system.h> #include <asm/traps.h> +#define CREATE_TRACE_POINTS +#include <trace/events/syscalls.h> +#define REG_PC 15#define REG_PSR 16/*
@@ -929,15 +932,25 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)audit_syscall_entry (AUDIT_ARCH_NR , scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); -if (!test_thread_flag (TIF_SYSCALL_TRACE )) +if (!test_thread_flag (TIF_SYSCALL_TRACE ) && + !test_thread_flag (TIF_SYSCALL_TRACEPOINT ))return scno;current_thread_info ()->syscall = scno; -if (why) -tracehook_report_syscall_exit (regs,0 ); -else if (tracehook_report_syscall_entry (regs)) -current_thread_info ()->syscall =-1 ; +if (test_thread_flag (TIF_SYSCALL_TRACE )) { +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + } + +if (test_thread_flag (TIF_SYSCALL_TRACEPOINT )) { +if (why) +trace_sys_exit (regs, scno); +else +trace_sys_enter (regs, scno); + } regs->ARM_ip = ip;
Signature · 1 line
1.7.0.4
v2 cover ARM support for syscall tracing
In reply to Wade FarnsworthHi Wade,
Quoted 15 lines · Wade Farnsworth
This is a rework of Steven Walter's syscall tracing patches first posted here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074454.html
I've rebased the patches against the current mainline master branch, as well as implemented several changes based on feedback from Will Deacon and Russel King.
v2: - Tested on EABI and OABI.
- Removed an instance of the ?: operator insyscall_set_return_value()
- Moved #define ofNR_syscallstosyscall.h
- Changed the test ofNR_syscallsvs__NR_syscallsinentry-common.Sto .ifne
Quoted 4 lines
Wade Farnsworth (3):
ARM: add support for the genericsyscall.hinterface
ARM: add TRACEHOOK support
ARM: support syscall tracing
I'm pretty happy with these three patches now, so feel free to add:
Once Russell is ok with them you can put them in the patch system.
Cheers,
Will
v3 cover ARM support for syscall tracing
In reply to Wade FarnsworthThis is a rework of Steven Walter's syscall tracing patches first posted here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074454.html
I've rebased the patches against the current mainline master branch, as well as implemented several changes based on feedback from Will Deacon and Russell King.
v2: - Tested on EABI and OABI.
- Removed an instance of the ?: operator in syscall_set_return_value()
- Moved #define of NR_syscalls to syscall.h
- Changed the test of NR_syscalls vs __NR_syscalls in entry-common.S to .ifne
v3: - Added Will Deacon's Reviewed-by line. Code is identical to v2.
Wade Farnsworth (3):
ARM: add support for the generic syscall.h interface
ARM: add TRACEHOOK support
ARM: support syscall tracing
arch/arm/Kconfig | 2 + arch/arm/include/asm/ptrace.h | 5 ++ arch/arm/include/asm/syscall.h | 97 ++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/thread_info.h | 2 + arch/arm/include/asm/unistd.h | 8 +++ arch/arm/kernel/entry-common.S | 16 +++++- arch/arm/kernel/ptrace.c | 34 +++++++------ arch/arm/kernel/signal.c | 2 + 8 files changed, 149 insertions(+), 17 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
PATCH v3 1/3 ARM: add support for the generic syscall.h interface
Supplying the asm-generic/syscall.h interface is a pre-requisite for HAVE_ARCH_TRACEHOOK
--- arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
arch/arm/include/asm/syscall.h new file +93 -0
@@ -0,0 +1,93 @@ +/* +* Access to user system call parameters and results +* +* See asm-generic/syscall.h for descriptions of what we must do here. +*/ + +#ifndef _ASM_ARM_SYSCALL_H +#define _ASM_ARM_SYSCALL_H + +#include <linux/err.h> + +extern const unsigned long sys_call_table[]; + +static inline int syscall_get_nr (struct task_struct *task, +struct pt_regs *regs) +{ +return task_thread_info (task)->syscall; +} + +static inline void syscall_rollback (struct task_struct *task, +struct pt_regs *regs) +{ + regs->ARM_r0 = regs->ARM_ORIG_r0; +} + +static inline long syscall_get_error (struct task_struct *task, +struct pt_regs *regs) +{ +unsigned long error = regs->ARM_r0; +return IS_ERR_VALUE (error) ? error :0 ; +} + +static inline long syscall_get_return_value (struct task_struct *task, +struct pt_regs *regs) +{ +return regs->ARM_r0; +} + +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->ARM_r0 = (long ) error ? error : val; +} + +#define SYSCALL_MAX_ARGS 7 + +static inline void syscall_get_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned int i,unsigned int n, +unsigned long *args) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +unsigned long *args_bad = args +SYSCALL_MAX_ARGS - i; +unsigned int n_bad = n + i -SYSCALL_MAX_ARGS ; +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); +memset (args_bad,0 , n_bad *sizeof (args[0 ])); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + args[0 ] = regs->ARM_ORIG_r0; + args++; + i++; + n--; + } + +memcpy (args, ®s->ARM_r0 + 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) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + regs->ARM_ORIG_r0 = args[0 ]; + args++; + i++; + n--; + } + +memcpy (®s->ARM_r0 + i, args, n *sizeof (args[0 ])); +} + +#endif /* _ASM_ARM_SYSCALL_H */
Signature · 1 line
1.7.0.4
PATCH v3 2/3 ARM: add TRACEHOOK support
In reply to Wade FarnsworthAdd calls to tracehook_report_syscall_{entry,exit} and tracehook_signal_handler
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/ptrace.h | 5 +++++ arch/arm/kernel/ptrace.c | 21 ++++++--------------- arch/arm/kernel/signal.c | 2 ++ 4 files changed, 14 insertions(+), 15 deletions(-)
arch/arm/Kconfig +1 -0
@@ -10,6 +10,7 @@ config ARM select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/ptrace.h +5 -0
@@ -249,6 +249,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)return regs->ARM_sp; } +static inline unsigned long user_stack_pointer (struct pt_regs *regs) +{ +return regs->ARM_sp; +} +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */
arch/arm/kernel/ptrace.c +6 -15
@@ -24,6 +24,7 @@#include <linux/hw_breakpoint.h> #include <linux/regset.h> #include <linux/audit.h> +#include <linux/tracehook.h> #include <asm/pgtable.h> #include <asm/system.h>
@@ -930,24 +931,14 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)if (!test_thread_flag (TIF_SYSCALL_TRACE ))return scno; -if (!(current->ptrace &PT_PTRACED )) -return scno;current_thread_info ()->syscall = scno; -/* 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 )); -/* -* 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 ; - } +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + regs->ARM_ip = ip;return current_thread_info ()->syscall;
arch/arm/kernel/signal.c +2 -0
@@ -644,6 +644,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,recalc_sigpending ();spin_unlock_irq (&tsk->sighand->siglock); +tracehook_signal_handler (sig, info, ka, regs,0 ); +return 0 ; }
Signature · 1 line
1.7.0.4
PATCH v3 3/3 ARM: support syscall tracing
In reply to Wade FarnsworthAs specified by ftrace-design.txt, TIF_SYSCALL_TRACEPOINT was added, as well as NR_syscalls in asm/unistd.h. Additionally, __sys_trace was modified to call trace_sys_enter and trace_sys_exit when appropriate.
Tests #2 - #4 of "perf test" now complete successfully.
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/syscall.h | 4 ++++ arch/arm/include/asm/thread_info.h | 2 ++ arch/arm/include/asm/unistd.h | 8 ++++++++ arch/arm/kernel/entry-common.S | 16 ++++++++++++++-- arch/arm/kernel/ptrace.c | 23 ++++++++++++++++++----- 6 files changed, 47 insertions(+), 7 deletions(-)
arch/arm/Kconfig +1 -0
@@ -11,6 +11,7 @@ config ARM select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK + select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/syscall.h +4 -0
@@ -9,6 +9,10 @@#include <linux/err.h> +#include <asm/unistd.h> + +#define NR_syscalls (__NR_syscalls) +extern const unsigned long sys_call_table[]; static inline int syscall_get_nr(struct task_struct *task,
arch/arm/include/asm/thread_info.h +2 -0
@@ -146,6 +146,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define TIF_MEMDIE 18/* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20#define TIF_SECCOMP 21 +#define TIF_SYSCALL_TRACEPOINT 22#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -156,6 +157,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)/* Checks for any syscall work in entry-common.S */ #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
arch/arm/include/asm/unistd.h +8 -0
@@ -406,6 +406,14 @@#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)/* +* This may need to be greater than __NR_last_syscall+1 in order to +* account for the padding in the syscall table +*/ +#ifdef __KERNEL__ +#define __NR_syscalls (380) +#endif /* __KERNEL__ */ + +/* * The following SWIs are ARM private. */ #define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
arch/arm/kernel/entry-common.S +14 -2
@@ -79,6 +79,11 @@ no_work_pending: ENDPROC(ret_to_user_from_irq) ENDPROC(ret_to_user) +.macro test_syscall_tracing reg + tst \reg, #_TIF_SYSCALL_WORK + tsteq \reg, #_TIF_SYSCALL_TRACEPOINT +.endm + /* * This is how we return from a fork. */
@@ -87,7 +92,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r1 beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1]
@@ -98,6 +103,13 @@ ENDPROC(ret_from_fork) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" + +/* Ensure that the system call table is not larger than __NR_syscalls, + * which is the value the rest of the system sees */ +.ifne NR_syscalls - __NR_syscalls +.error "__NR_syscalls is less than the size of the syscall table" +.endif + #undef CALL #define CALL(x) .long x
@@ -446,7 +458,7 @@ ENTRY(vector_swi) 1: #endif - tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r10 bne __sys_trace cmp scno, #NR_syscalls @ check upper syscall limit
arch/arm/kernel/ptrace.c +18 -5
@@ -30,6 +30,9 @@#include <asm/system.h> #include <asm/traps.h> +#define CREATE_TRACE_POINTS +#include <trace/events/syscalls.h> +#define REG_PC 15#define REG_PSR 16/*
@@ -929,15 +932,25 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)audit_syscall_entry (AUDIT_ARCH_NR , scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); -if (!test_thread_flag (TIF_SYSCALL_TRACE )) +if (!test_thread_flag (TIF_SYSCALL_TRACE ) && + !test_thread_flag (TIF_SYSCALL_TRACEPOINT ))return scno;current_thread_info ()->syscall = scno; -if (why) -tracehook_report_syscall_exit (regs,0 ); -else if (tracehook_report_syscall_entry (regs)) -current_thread_info ()->syscall =-1 ; +if (test_thread_flag (TIF_SYSCALL_TRACE )) { +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + } + +if (test_thread_flag (TIF_SYSCALL_TRACEPOINT )) { +if (why) +trace_sys_exit (regs, scno); +else +trace_sys_enter (regs, scno); + } regs->ARM_ip = ip;
Signature · 1 line
1.7.0.4
v4 cover ARM support for syscall tracing
In reply to Wade FarnsworthThis is a rework of Steven Walter's syscall tracing patches first posted here:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074454.html
I've rebased the patches against the current mainline master branch, as well as implemented several changes based on feedback from Will Deacon and Russel King.
v2: - Tested on EABI and OABI.
- Removed an instance of the ?: operator in syscall_set_return_value()
- Moved #define of NR_syscalls to syscall.h
- Changed the test of NR_syscalls vs __NR_syscalls in entry-common.S to .ifne
v3: - Added Will Deacon's Reviewed-by line. Code is identical to v2.
v4: - Updated comment and error string for the NR_syscalls test to
reflect that it's now testing for inequality.
Russell, now that this has been reviewed by Will and tested with both ABIs, is this okay to submit to your patch tracker?
Wade Farnsworth (3):
ARM: add support for the generic syscall.h interface
ARM: add TRACEHOOK support
ARM: support syscall tracing
arch/arm/Kconfig | 2 + arch/arm/include/asm/ptrace.h | 5 ++ arch/arm/include/asm/syscall.h | 97 ++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/thread_info.h | 2 + arch/arm/include/asm/unistd.h | 8 +++ arch/arm/kernel/entry-common.S | 18 ++++++- arch/arm/kernel/ptrace.c | 34 +++++++------ arch/arm/kernel/signal.c | 2 + 8 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
PATCH v4 1/3 ARM: add support for the generic syscall.h interface
Supplying the asm-generic/syscall.h interface is a pre-requisite for HAVE_ARCH_TRACEHOOK
--- arch/arm/include/asm/syscall.h | 93 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 93 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/syscall.h
arch/arm/include/asm/syscall.h new file +93 -0
@@ -0,0 +1,93 @@ +/* +* Access to user system call parameters and results +* +* See asm-generic/syscall.h for descriptions of what we must do here. +*/ + +#ifndef _ASM_ARM_SYSCALL_H +#define _ASM_ARM_SYSCALL_H + +#include <linux/err.h> + +extern const unsigned long sys_call_table[]; + +static inline int syscall_get_nr (struct task_struct *task, +struct pt_regs *regs) +{ +return task_thread_info (task)->syscall; +} + +static inline void syscall_rollback (struct task_struct *task, +struct pt_regs *regs) +{ + regs->ARM_r0 = regs->ARM_ORIG_r0; +} + +static inline long syscall_get_error (struct task_struct *task, +struct pt_regs *regs) +{ +unsigned long error = regs->ARM_r0; +return IS_ERR_VALUE (error) ? error :0 ; +} + +static inline long syscall_get_return_value (struct task_struct *task, +struct pt_regs *regs) +{ +return regs->ARM_r0; +} + +static inline void syscall_set_return_value (struct task_struct *task, +struct pt_regs *regs, +int error,long val) +{ + regs->ARM_r0 = (long ) error ? error : val; +} + +#define SYSCALL_MAX_ARGS 7 + +static inline void syscall_get_arguments (struct task_struct *task, +struct pt_regs *regs, +unsigned int i,unsigned int n, +unsigned long *args) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +unsigned long *args_bad = args +SYSCALL_MAX_ARGS - i; +unsigned int n_bad = n + i -SYSCALL_MAX_ARGS ; +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); +memset (args_bad,0 , n_bad *sizeof (args[0 ])); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + args[0 ] = regs->ARM_ORIG_r0; + args++; + i++; + n--; + } + +memcpy (args, ®s->ARM_r0 + 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) +{ +if (i + n >SYSCALL_MAX_ARGS ) { +pr_warning ("%s called with max args %d, handling only %d\n" , + __func__, i + n,SYSCALL_MAX_ARGS ); + n =SYSCALL_MAX_ARGS - i; + } + +if (i ==0 ) { + regs->ARM_ORIG_r0 = args[0 ]; + args++; + i++; + n--; + } + +memcpy (®s->ARM_r0 + i, args, n *sizeof (args[0 ])); +} + +#endif /* _ASM_ARM_SYSCALL_H */
Signature · 1 line
1.7.0.4
PATCH v4 2/3 ARM: add TRACEHOOK support
In reply to Wade FarnsworthAdd calls to tracehook_report_syscall_{entry,exit} and tracehook_signal_handler
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/ptrace.h | 5 +++++ arch/arm/kernel/ptrace.c | 21 ++++++--------------- arch/arm/kernel/signal.c | 2 ++ 4 files changed, 14 insertions(+), 15 deletions(-)
arch/arm/Kconfig +1 -0
@@ -10,6 +10,7 @@ config ARM select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/ptrace.h +5 -0
@@ -249,6 +249,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)return regs->ARM_sp; } +static inline unsigned long user_stack_pointer (struct pt_regs *regs) +{ +return regs->ARM_sp; +} +#endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */
arch/arm/kernel/ptrace.c +6 -15
@@ -24,6 +24,7 @@#include <linux/hw_breakpoint.h> #include <linux/regset.h> #include <linux/audit.h> +#include <linux/tracehook.h> #include <asm/pgtable.h> #include <asm/system.h>
@@ -930,24 +931,14 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)if (!test_thread_flag (TIF_SYSCALL_TRACE ))return scno; -if (!(current->ptrace &PT_PTRACED )) -return scno;current_thread_info ()->syscall = scno; -/* 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 )); -/* -* 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 ; - } +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + regs->ARM_ip = ip;return current_thread_info ()->syscall;
arch/arm/kernel/signal.c +2 -0
@@ -644,6 +644,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,recalc_sigpending ();spin_unlock_irq (&tsk->sighand->siglock); +tracehook_signal_handler (sig, info, ka, regs,0 ); +return 0 ; }
Signature · 1 line
1.7.0.4
PATCH v4 3/3 ARM: support syscall tracing
In reply to Wade FarnsworthAs specified by ftrace-design.txt, TIF_SYSCALL_TRACEPOINT was added, as well as NR_syscalls in asm/unistd.h. Additionally, __sys_trace was modified to call trace_sys_enter and trace_sys_exit when appropriate.
Tests #2 - #4 of "perf test" now complete successfully.
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/syscall.h | 4 ++++ arch/arm/include/asm/thread_info.h | 2 ++ arch/arm/include/asm/unistd.h | 8 ++++++++ arch/arm/kernel/entry-common.S | 18 ++++++++++++++++-- arch/arm/kernel/ptrace.c | 23 ++++++++++++++++++----- 6 files changed, 49 insertions(+), 7 deletions(-)
arch/arm/Kconfig +1 -0
@@ -11,6 +11,7 @@ config ARM select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK + select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
arch/arm/include/asm/syscall.h +4 -0
@@ -9,6 +9,10 @@#include <linux/err.h> +#include <asm/unistd.h> + +#define NR_syscalls (__NR_syscalls) +extern const unsigned long sys_call_table[]; static inline int syscall_get_nr(struct task_struct *task,
arch/arm/include/asm/thread_info.h +2 -0
@@ -146,6 +146,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define TIF_MEMDIE 18/* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20#define TIF_SECCOMP 21 +#define TIF_SYSCALL_TRACEPOINT 22#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -156,6 +157,7 @@ extern void vfp_flush_hwstate(struct thread_info *);#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)/* Checks for any syscall work in entry-common.S */ #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
arch/arm/include/asm/unistd.h +8 -0
@@ -406,6 +406,14 @@#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)/* +* This may need to be greater than __NR_last_syscall+1 in order to +* account for the padding in the syscall table +*/ +#ifdef __KERNEL__ +#define __NR_syscalls (380) +#endif /* __KERNEL__ */ + +/* * The following SWIs are ARM private. */ #define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
arch/arm/kernel/entry-common.S +16 -2
@@ -79,6 +79,11 @@ no_work_pending: ENDPROC(ret_to_user_from_irq) ENDPROC(ret_to_user) +.macro test_syscall_tracing reg + tst \reg, #_TIF_SYSCALL_WORK + tsteq \reg, #_TIF_SYSCALL_TRACEPOINT +.endm + /* * This is how we return from a fork. */
@@ -87,7 +92,7 @@ ENTRY(ret_from_fork) get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing mov why, #1 - tst r1, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r1 beq ret_slow_syscall mov r1, sp mov r0, #1 @ trace exit [IP = 1]
@@ -98,6 +103,15 @@ ENDPROC(ret_from_fork) .equ NR_syscalls,0 #define CALL(x) .equ NR_syscalls,NR_syscalls+1 #include "calls.S" + +/* + * Ensure that the system call table is equal to __NR_syscalls, + * which is the value the rest of the system sees + */ +.ifne NR_syscalls - __NR_syscalls +.error "__NR_syscalls is not equal to the size of the syscall table" +.endif + #undef CALL #define CALL(x) .long x
@@ -446,7 +460,7 @@ ENTRY(vector_swi) 1: #endif - tst r10, #_TIF_SYSCALL_WORK @ are we tracing syscalls? + test_syscall_tracing r10 bne __sys_trace cmp scno, #NR_syscalls @ check upper syscall limit
arch/arm/kernel/ptrace.c +18 -5
@@ -30,6 +30,9 @@#include <asm/system.h> #include <asm/traps.h> +#define CREATE_TRACE_POINTS +#include <trace/events/syscalls.h> +#define REG_PC 15#define REG_PSR 16/*
@@ -929,15 +932,25 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)audit_syscall_entry (AUDIT_ARCH_NR , scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); -if (!test_thread_flag (TIF_SYSCALL_TRACE )) +if (!test_thread_flag (TIF_SYSCALL_TRACE ) && + !test_thread_flag (TIF_SYSCALL_TRACEPOINT ))return scno;current_thread_info ()->syscall = scno; -if (why) -tracehook_report_syscall_exit (regs,0 ); -else if (tracehook_report_syscall_entry (regs)) -current_thread_info ()->syscall =-1 ; +if (test_thread_flag (TIF_SYSCALL_TRACE )) { +if (why) +tracehook_report_syscall_exit (regs,0 ); +else if (tracehook_report_syscall_entry (regs)) +current_thread_info ()->syscall =-1 ; + } + +if (test_thread_flag (TIF_SYSCALL_TRACEPOINT )) { +if (why) +trace_sys_exit (regs, scno); +else +trace_sys_enter (regs, scno); + } regs->ARM_ip = ip;
Signature · 1 line
1.7.0.4
v4 cover ARM support for syscall tracing
In reply to Wade FarnsworthHi Wade,
Quoted 2 lines · Wade Farnsworth
Russell, now that this has been reviewed by Will and tested with both ABIs, is this okay to submit to your patch tracker?
I'd recommend putting this into the patch system once -rc1 has landed. Any conflicts after that are fairly unlikely and Russell can decide what to do with the patches then.
Cheers,
Will