From e61d708aa6cd6179fde3204358d2c36983952027 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Tue, 30 Aug 2011 23:28:03 -0400 Subject: [PATCH] dtrace: syscall entry/return probes. Makes the sys call table writable, and replaces the function pointer for select syscalls with the address of a wrapper function to enable entry and return probe firing. Fix for address range checking for copyin(str) operations and relatives. It was using an incorrect boundary address, causing problems for some cases. Signed-off-by: Kris Van Hees --- arch/x86/include/asm/syscall.h | 4 +++ arch/x86/kernel/syscall_64.c | 4 +++ kernel/dtrace/dtrace_os.c | 61 ++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h index d6a756ae04c8..41e85edc3348 100644 --- a/arch/x86/include/asm/syscall.h +++ b/arch/x86/include/asm/syscall.h @@ -21,7 +21,11 @@ #include typedef void (*sys_call_ptr_t)(void); +#if defined(CONFIG_DT_SYSTRACE) || defined(CONFIG_DT_SYSTRACE_MODULE) +extern sys_call_ptr_t sys_call_table[]; +#else extern const sys_call_ptr_t sys_call_table[]; +#endif /* * Only the low 32 bits of orig_ax are meaningful, so we return int. diff --git a/arch/x86/kernel/syscall_64.c b/arch/x86/kernel/syscall_64.c index 4ac730b37f0b..2593443ee3e5 100644 --- a/arch/x86/kernel/syscall_64.c +++ b/arch/x86/kernel/syscall_64.c @@ -22,7 +22,11 @@ extern void sys_ni_syscall(void); +#if defined(CONFIG_DT_SYSTRACE) || defined(CONFIG_DT_SYSTRACE_MODULE) +asmlinkage sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { +#else asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { +#endif /* CONFIG_DT_SYSTRACE || CONFIG_DT_SYSTRACE_MODULE */ /* * Smells like a compiler bug -- it doesn't work * when the & below is removed. diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index 07d5a8a5a4c9..fdb36a9deb1c 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -8,8 +8,10 @@ #include #include #include +#include #include "cyclic.h" +#include "systrace.h" /* * Very basic implementation of cyclics, merely enough to support dtrace. @@ -132,3 +134,62 @@ void cyclic_remove(cyclic_id_t id) mutex_unlock(&cyclic_lock); } EXPORT_SYMBOL(cyclic_remove); + +static systrace_info_t systrace_info; + +void (*systrace_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, + uintptr_t, uintptr_t); + +void systrace_stub(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, + uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, + uintptr_t arg5) +{ +} + +asmlinkage long systrace_syscall(uintptr_t arg0, uintptr_t arg1, + uintptr_t arg2, uintptr_t arg3, + uintptr_t arg4, uintptr_t arg5) +{ + long rc; + unsigned long sysnum; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + asm volatile("movq %%rax,%0" : "=m"(sysnum)); + + sc = &systrace_info.sysent[sysnum]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, arg0, arg1, arg2, arg3, arg4, arg5); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + if (sc->stsy_underlying != NULL) + rc = (*sc->stsy_underlying)(arg0, arg1, arg2, arg3, arg4, + arg5); + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, arg0, arg1, arg2, arg3, arg4, arg5); + + return rc; +} + +systrace_info_t *dtrace_syscalls_init() { + int i; + extern sys_call_ptr_t sys_call_table[NR_syscalls]; + + systrace_info.probep = &systrace_probe; + systrace_info.stub = systrace_stub; + systrace_info.syscall = systrace_syscall; + + for (i = 0; i < NR_syscalls; i++) { + systrace_info.sysent[i].stsy_tblent = &sys_call_table[i]; + systrace_info.sysent[i].stsy_underlying = + (dt_sys_call_t)sys_call_table[i]; + } + + return &systrace_info; +} +EXPORT_SYMBOL(dtrace_syscalls_init); -- 2.50.1