Commit c652d780 authored by Matt Fleming's avatar Matt Fleming Committed by Paul Mundt

sh: Add ftrace syscall tracing support

Now that I've added TIF_SYSCALL_FTRACE the thread flags do not fit into
a single byte any more. Code testing them now needs to be aware of the
upper and lower bytes.
Signed-off-by: default avatarMatt Fleming <matt@console-pimps.org>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent c1340c05
...@@ -32,6 +32,7 @@ config SUPERH32 ...@@ -32,6 +32,7 @@ config SUPERH32
select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_FTRACE_SYSCALLS
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select ARCH_HIBERNATION_POSSIBLE if MMU select ARCH_HIBERNATION_POSSIBLE if MMU
......
...@@ -65,6 +65,7 @@ static inline void syscall_get_arguments(struct task_struct *task, ...@@ -65,6 +65,7 @@ static inline void syscall_get_arguments(struct task_struct *task,
case 3: args[2] = regs->regs[6]; case 3: args[2] = regs->regs[6];
case 2: args[1] = regs->regs[5]; case 2: args[1] = regs->regs[5];
case 1: args[0] = regs->regs[4]; case 1: args[0] = regs->regs[4];
case 0:
break; break;
default: default:
BUG(); BUG();
......
...@@ -116,6 +116,7 @@ extern void free_thread_info(struct thread_info *ti); ...@@ -116,6 +116,7 @@ extern void free_thread_info(struct thread_info *ti);
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */ #define TIF_SECCOMP 6 /* secure computing */
#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ #define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
#define TIF_SYSCALL_FTRACE 8 /* for ftrace syscall instrumentation */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18 #define TIF_MEMDIE 18
...@@ -129,25 +130,27 @@ extern void free_thread_info(struct thread_info *ti); ...@@ -129,25 +130,27 @@ extern void free_thread_info(struct thread_info *ti);
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP) #define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_FTRACE (1 << TIF_SYSCALL_FTRACE)
#define _TIF_USEDFPU (1 << TIF_USEDFPU) #define _TIF_USEDFPU (1 << TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_FREEZE (1 << TIF_FREEZE) #define _TIF_FREEZE (1 << TIF_FREEZE)
/* /*
* _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within a byte, or we * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or we
* blow the tst immediate size constraints and need to fix up * blow the tst immediate size constraints and need to fix up
* arch/sh/kernel/entry-common.S. * arch/sh/kernel/entry-common.S.
*/ */
/* work to do in syscall trace */ /* work to do in syscall trace */
#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ #define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
_TIF_SYSCALL_AUDIT | _TIF_SECCOMP) _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_FTRACE)
/* work to do on any return to u-space */ /* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \ #define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \
_TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \ _TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \
_TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \ _TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \
_TIF_NOTIFY_RESUME) _TIF_NOTIFY_RESUME | _TIF_SYSCALL_FTRACE)
/* work to do on interrupt/exception return */ /* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \ #define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
......
...@@ -29,6 +29,7 @@ obj-$(CONFIG_IO_TRAPPED) += io_trapped.o ...@@ -29,6 +29,7 @@ obj-$(CONFIG_IO_TRAPPED) += io_trapped.o
obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_GENERIC_GPIO) += gpio.o obj-$(CONFIG_GENERIC_GPIO) += gpio.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_HIBERNATION) += swsusp.o
......
...@@ -131,7 +131,7 @@ ENTRY(resume_userspace) ...@@ -131,7 +131,7 @@ ENTRY(resume_userspace)
nop nop
#endif #endif
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
tst #_TIF_WORK_MASK, r0 tst #(_TIF_WORK_MASK & 0xff), r0
bt/s __restore_all bt/s __restore_all
tst #_TIF_NEED_RESCHED, r0 tst #_TIF_NEED_RESCHED, r0
...@@ -163,7 +163,7 @@ work_resched: ...@@ -163,7 +163,7 @@ work_resched:
#endif #endif
! !
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
tst #_TIF_WORK_MASK, r0 tst #(_TIF_WORK_MASK & 0xff), r0
bt __restore_all bt __restore_all
bra work_pending bra work_pending
tst #_TIF_NEED_RESCHED, r0 tst #_TIF_NEED_RESCHED, r0
...@@ -181,7 +181,7 @@ work_resched: ...@@ -181,7 +181,7 @@ work_resched:
syscall_exit_work: syscall_exit_work:
! r0: current_thread_info->flags ! r0: current_thread_info->flags
! r8: current_thread_info ! r8: current_thread_info
tst #_TIF_WORK_SYSCALL_MASK, r0 tst #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
bt/s work_pending bt/s work_pending
tst #_TIF_NEED_RESCHED, r0 tst #_TIF_NEED_RESCHED, r0
#ifdef CONFIG_TRACE_IRQFLAGS #ifdef CONFIG_TRACE_IRQFLAGS
...@@ -331,8 +331,12 @@ ENTRY(system_call) ...@@ -331,8 +331,12 @@ ENTRY(system_call)
! !
get_current_thread_info r8, r10 get_current_thread_info r8, r10
mov.l @(TI_FLAGS,r8), r8 mov.l @(TI_FLAGS,r8), r8
mov #_TIF_WORK_SYSCALL_MASK, r10 mov #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
mov #(_TIF_WORK_SYSCALL_MASK >> 8), r9
tst r10, r8 tst r10, r8
shll8 r9
bf syscall_trace_entry
tst r9, r8
bf syscall_trace_entry bf syscall_trace_entry
! !
mov.l 2f, r8 ! Number of syscalls mov.l 2f, r8 ! Number of syscalls
...@@ -359,7 +363,11 @@ syscall_exit: ...@@ -359,7 +363,11 @@ syscall_exit:
! !
get_current_thread_info r8, r0 get_current_thread_info r8, r0
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
tst #_TIF_ALLWORK_MASK, r0 tst #(_TIF_ALLWORK_MASK & 0xff), r0
mov #(_TIF_ALLWORK_MASK >> 8), r1
bf syscall_exit_work
shlr8 r0
tst r0, r1
bf syscall_exit_work bf syscall_exit_work
bra __restore_all bra __restore_all
nop nop
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <asm/ftrace.h> #include <asm/ftrace.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/unistd.h>
#include <trace/syscall.h>
static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
...@@ -131,3 +133,69 @@ int __init ftrace_dyn_arch_init(void *data) ...@@ -131,3 +133,69 @@ int __init ftrace_dyn_arch_init(void *data)
return 0; return 0;
} }
#ifdef CONFIG_FTRACE_SYSCALLS
extern unsigned long __start_syscalls_metadata[];
extern unsigned long __stop_syscalls_metadata[];
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;
}
#define FTRACE_SYSCALL_MAX (NR_syscalls - 1)
struct syscall_metadata *syscall_nr_to_meta(int nr)
{
if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || 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) *
FTRACE_SYSCALL_MAX, GFP_KERNEL);
if (!syscalls_metadata) {
WARN_ON(1);
return;
}
for (i = 0; i < FTRACE_SYSCALL_MAX; 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 */
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <asm/syscalls.h> #include <asm/syscalls.h>
#include <asm/fpu.h> #include <asm/fpu.h>
#include <trace/syscall.h>
/* /*
* This routine will get a word off of the process kernel stack. * This routine will get a word off of the process kernel stack.
*/ */
...@@ -459,6 +461,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) ...@@ -459,6 +461,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
*/ */
ret = -1L; ret = -1L;
if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
ftrace_syscall_enter(regs);
if (unlikely(current->audit_context)) if (unlikely(current->audit_context))
audit_syscall_entry(audit_arch(), regs->regs[3], audit_syscall_entry(audit_arch(), regs->regs[3],
regs->regs[4], regs->regs[5], regs->regs[4], regs->regs[5],
...@@ -475,6 +480,9 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) ...@@ -475,6 +480,9 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]),
regs->regs[0]); regs->regs[0]);
if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
ftrace_syscall_exit(regs);
step = test_thread_flag(TIF_SINGLESTEP); step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE)) if (step || test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall_exit(regs, step); tracehook_report_syscall_exit(regs, step);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment