From: Kris Van Hees Date: Mon, 22 Dec 2014 21:56:13 +0000 (-0500) Subject: dtrace: add support for sparc64 3of3 X-Git-Tag: v4.1.12-92~313^2~27 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=da8922d33b98f5f968299562334613d3ac2d3538;p=users%2Fjedix%2Flinux-maple.git dtrace: add support for sparc64 3of3 This commit is the 3rd of 3 commits to add DTrace support to the sparc64 kernel. This particular commit covers the DTrace implementation code changes. It provides an implementation of the DTrace core for sparc64, SDT, and syscall tracing. Note that the sparc64 implementation for SDT probe points utilizes a call to a trampoline function that in turn calls dtrace_probe() rather than using a trap-based mechanism. This requires an additional data item to be associated with each module. In order to facilitate this in a manner that is arch-dependent, DTrace specific data other than the list of SDT probes has been moved to a structure that is maintained by the DTrace module code and the module struct merely has a generic void *pdata member that can be populated with a pointer to the actual data. This commit renames the num_dtrace_probes member of the module struct to be sdt_probec, since that is more consistent. Orabug: 19005031 Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- diff --git a/arch/sparc/include/asm/dtrace_cpuinfo.h b/arch/sparc/include/asm/dtrace_cpuinfo.h new file mode 100644 index 000000000000..fdc2d0a11b6d --- /dev/null +++ b/arch/sparc/include/asm/dtrace_cpuinfo.h @@ -0,0 +1,15 @@ +/* Copyright (C) 2013,2014 Oracle, Inc. */ + +#ifndef _ASM_SPARC_DTRACE_CPUINFO_H_ +#define _ASM_SPARC_DTRACE_CPUINFO_H_ + +#include + +typedef cpuinfo_sparc cpuinfo_arch_t; + +#define dtrace_cpuinfo_chip(ci) ((ci)->proc_id) + +#define TSTATE_CCR_SHIFT 32 +#define TSTATE_ASI_SHIFT 24 + +#endif /* _ASM_SPARC_DTRACE_CPUINFO_H_ */ diff --git a/arch/sparc/include/asm/dtrace_sdt.h b/arch/sparc/include/asm/dtrace_sdt.h new file mode 100644 index 000000000000..105d07cb4929 --- /dev/null +++ b/arch/sparc/include/asm/dtrace_sdt.h @@ -0,0 +1,10 @@ +/* Copyright (C) 2013,2014 Oracle, Inc. */ + +#ifndef _SPARC_DTRACE_SDT_H +#define _SPARC_DTRACE_SDT_H + +typedef uint32_t sdt_instr_t; + +#define SDT_TRAMP_SIZE 11 + +#endif /* _SPARC_DTRACE_SDT_H */ diff --git a/arch/sparc/include/asm/dtrace_syscall.h b/arch/sparc/include/asm/dtrace_syscall.h new file mode 100644 index 000000000000..538f2c15ef88 --- /dev/null +++ b/arch/sparc/include/asm/dtrace_syscall.h @@ -0,0 +1,12 @@ +/* Copyright (C) 2011-2014 Oracle, Inc. */ + +DTRACE_SYSCALL_STUB(EXECVE, execve) +DTRACE_SYSCALL_STUB(PIPE, pipe) +DTRACE_SYSCALL_STUB(MEMORY_ORDERING, memory_ordering) +DTRACE_SYSCALL_STUB(SIGALTSTACK, sigaltstack) +DTRACE_SYSCALL_STUB(RT_SIGRETURN, rt_sigreturn) +DTRACE_SYSCALL_STUB(VFORK, vfork) +DTRACE_SYSCALL_STUB(FORK, fork) +DTRACE_SYSCALL_STUB(CLONE, clone) +DTRACE_SYSCALL_STUB(EXIT_GROUP, exit_group) +DTRACE_SYSCALL_STUB(EXIT, exit) diff --git a/arch/sparc/include/asm/dtrace_util.h b/arch/sparc/include/asm/dtrace_util.h new file mode 100644 index 000000000000..9dd517add3c2 --- /dev/null +++ b/arch/sparc/include/asm/dtrace_util.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2013,2014 Oracle, Inc. */ + +#ifndef _SPARC_DTRACE_UTIL_H +#define _SPARC_DTRACE_UTIL_H + +/* Nothing for now */ + +#endif /* _SPARC_DTRACE_UTIL_H */ diff --git a/arch/sparc/kernel/dtrace_sdt.c b/arch/sparc/kernel/dtrace_sdt.c new file mode 100644 index 000000000000..e8b70ab467dd --- /dev/null +++ b/arch/sparc/kernel/dtrace_sdt.c @@ -0,0 +1,36 @@ +/* + * FILE: dtrace_sdt.c + * DESCRIPTION: Dynamic Tracing: SDT registration code (arch-specific) + * + * Copyright (C) 2010-2014 Oracle Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void __init_or_module dtrace_sdt_nop_multi(sdt_instr_t **addrs, int cnt) +{ + int i; + sdt_instr_t *addr; + + for (i = 0; i < cnt; i++) { + addr = addrs[i]; + *addr = 0x01000000; + flushi(addr); + } +} + +/* + * Perform architecture dependent initialization for SDT. On sparc64, we need + * not do anything. + */ +void dtrace_sdt_init_arch(void) +{ +} diff --git a/arch/sparc/kernel/dtrace_syscall.c b/arch/sparc/kernel/dtrace_syscall.c new file mode 100644 index 000000000000..18ebb06bf7f5 --- /dev/null +++ b/arch/sparc/kernel/dtrace_syscall.c @@ -0,0 +1,349 @@ +/* + * FILE: dtrace_syscall.c + * DESCRIPTION: Dynamic Tracing: system call tracing support (arch-specific) + * + * Copyright (C) 2010-2014 Oracle Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "systbls.h" + +/*---------------------------------------------------------------------------*\ +(* SYSTEM CALL TRACING SUPPORT *) +\*---------------------------------------------------------------------------*/ +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, uintptr_t, + uintptr_t, uintptr_t, + uintptr_t, uintptr_t); + +static systrace_info_t systrace_info = + { + &systrace_probe, + &systrace_stub, + &systrace_syscall, + { +#define DTRACE_SYSCALL_STUB(t, n) \ + [SCE_##t] dtrace_stub_##n, +#include +#undef DTRACE_SYSCALL_STUB + }, + { + } + }; + + +long systrace_syscall(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, uintptr_t arg5) +{ + long rc = 0; + unsigned long sysnum; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sysnum = syscall_get_nr(current, current_pt_regs()); + 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, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +systrace_info_t *dtrace_syscalls_init() { + int i; + + /* + * Only initialize this stuff once... + */ + if (systrace_info.sysent[0].stsy_tblent != NULL) + return &systrace_info; + + for (i = 0; i < NR_syscalls; i++) { + char sym[KSYM_SYMBOL_LEN]; + char *p = sym; + + /* + * We (ab)use the knowledge that the perfctr system call is + * not implemented, and is directed to sys_nis_syscall. We'd + * rather refer to that function directly, but it is not a + * global symbol. + */ + if (sys_call_table[i] == (uintptr_t)sys_ni_syscall || + sys_call_table[i] == sys_call_table[__NR_perfctr]) + continue; + + lookup_symbol_name(sys_call_table[i], sym); + p = strchr(sym, '_'); + if (p == NULL) + continue; + p++; + + systrace_info.sysent[i].name = kstrdup(p, GFP_KERNEL); + systrace_info.sysent[i].stsy_tblent = + (dt_sys_call_t *)&sys_call_table[i]; + systrace_info.sysent[i].stsy_underlying = + (dt_sys_call_t)(uintptr_t)sys_call_table[i]; + } + + return &systrace_info; +} +EXPORT_SYMBOL(dtrace_syscalls_init); + +asmlinkage long dtrace_sys_clone(unsigned long clone_flags, + unsigned long newsp, struct pt_regs *regs, + unsigned long stack_size) +{ + int __user *parent_tidptr, *child_tidptr; + long rc = 0; + unsigned long orig_i1 = regs->u_regs[UREG_I1]; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_clone]; + +#ifdef CONFIG_COMPAT + if (test_thread_flag(TIF_32BIT)) { + parent_tidptr = compat_ptr(regs->u_regs[UREG_I2]); + child_tidptr = compat_ptr(regs->u_regs[UREG_I4]); + } else +#endif + { + parent_tidptr = (int __user *) regs->u_regs[UREG_I2]; + child_tidptr = (int __user *) regs->u_regs[UREG_I4]; + } + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, clone_flags, newsp, + (uintptr_t)parent_tidptr, + (uintptr_t)child_tidptr, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + rc = do_fork(clone_flags, newsp, stack_size, parent_tidptr, + child_tidptr); + + if ((unsigned long)rc >= -ERESTART_RESTARTBLOCK) + regs->u_regs[UREG_I1] = orig_i1; + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) +{ + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_execve]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)name, (uintptr_t)argv, + (uintptr_t)envp, 0, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + rc = do_execve(getname(name), argv, envp); + +out: + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_exit(int error_code) +{ + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_exit]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, error_code, 0, 0, 0, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + do_exit((error_code&0xff)<<8); + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_exit_group(int error_code) +{ + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_exit_group]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, error_code, 0, 0, 0, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + do_group_exit((error_code & 0xff) << 8); + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_memory_ordering(unsigned long model, + struct pt_regs *regs) +{ + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_memory_ordering]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)regs, 0, 0, 0, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + if (model >= 3) + rc = -EINVAL; + else + regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14); + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_pipe(struct pt_regs *regs) +{ + int fd[2]; + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_pipe]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, 0, 0, 0, 0, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + rc = do_pipe_flags(fd, 0); + if (rc) + goto out; + + regs->u_regs[UREG_I1] = fd[1]; + rc = fd[0]; + +out: + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_rt_sigreturn(struct pt_regs *regs) +{ + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_rt_sigreturn]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)regs, 0, 0, 0, 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + do_rt_sigreturn(regs); + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} + +asmlinkage long dtrace_sys_sigaltstack(const stack_t __user *uss, + stack_t __user *uoss, unsigned long sp) +{ + long rc = 0; + dtrace_id_t id; + dtrace_syscalls_t *sc; + + sc = &systrace_info.sysent[__NR_sigaltstack]; + + if ((id = sc->stsy_entry) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)uss, (uintptr_t)uoss, sp, 0, + 0, 0); + + /* + * FIXME: Add stop functionality for DTrace. + */ + + rc = do_sigaltstack(uss, uoss, sp); + + if ((id = sc->stsy_return) != DTRACE_IDNONE) + (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, + (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0); + + return rc; +} diff --git a/arch/sparc/kernel/dtrace_syscall_stubs.S b/arch/sparc/kernel/dtrace_syscall_stubs.S new file mode 100644 index 000000000000..65377ba69b95 --- /dev/null +++ b/arch/sparc/kernel/dtrace_syscall_stubs.S @@ -0,0 +1,90 @@ +/* + * FILE: dtrace_syscall_stubs.S + * DESCRIPTION: Dynamic Tracing: Syscall tracing stubs (arch-specific) + * + * Copyright (C) 2010-2014 Oracle Corporation + */ + +#include +#include +#include +#include +#include + + ENTRY(dtrace_stub_execve) + set dtrace_sys_execve, %g1 + jmpl %g1, %g0 + flushw + ENDPROC(dtrace_stub_execve) + + ENTRY(dtrace_stub_pipe) + ba,pt %xcc, dtrace_sys_pipe + add %sp, PTREGS_OFF, %o0 + ENDPROC(dtrace_stub_pipe) + + ENTRY(dtrace_stub_memory_ordering) + ba,pt %xcc, dtrace_sys_memory_ordering + add %sp, PTREGS_OFF, %o1 + ENDPROC(dtrace_stub_memory_ordering) + + ENTRY(dtrace_stub_sigaltstack) + ba,pt %xcc, dtrace_sys_sigaltstack + add %i6, STACK_BIAS, %o2 + ENDPROC(dtrace_stub_sigaltstack) + + ENTRY(dtrace_stub_rt_sigreturn) + add %sp, PTREGS_OFF, %o0 + call dtrace_sys_rt_sigreturn + add %o7, 1f-.-4, %o7 + nop + .align 32 +1: ldx [%g6 + TI_FLAGS], %l5 + andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0 + be,pt %icc, 2f + nop + call syscall_trace_leave + add %sp, PTREGS_OFF, %o0 +2: set rtrap, %g1 + jmpl %g1, %g0 + nop + ENDPROC(dtrace_stub_rt_sigreturn) + + ENTRY(dtrace_stub_vfork) + sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 + or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 + ba,pt %xcc, dtrace_stub_clone + + ENTRY(dtrace_stub_fork) + clr %o1 + mov SIGCHLD, %o0 + + ENTRY(dtrace_stub_clone) + flushw + movrz %o1, %fp, %o1 + mov 0, %o3 + ba,pt %xcc, dtrace_sys_clone + add %sp, PTREGS_OFF, %o2 + ENDPROC(dtrace_stub_clone) + ENDPROC(dtrace_stub_fork) + ENDPROC(dtrace_stub_vfork) + + ENTRY(dtrace_stub_exit_group) + sethi %hi(dtrace_sys_exit_group), %g7 + ba,pt %xcc, 1f + or %g7, %lo(dtrace_sys_exit_group), %g7 + ENDPROC(dtrace_stub_exit_group) + + ENTRY(dtrace_stub_exit) + sethi %hi(dtrace_sys_exit), %g7 + or %g7, %lo(dtrace_sys_exit), %g7 +1: rdpr %pstate, %g2 + wrpr %g2, PSTATE_IE, %pstate + rdpr %otherwin, %g1 + rdpr %cansave, %g3 + add %g3, %g1, %g3 + wrpr %g3, 0x0, %cansave + wrpr %g0, 0x0, %otherwin + wrpr %g2, 0x0, %pstate + jmpl %g7, %g0 + stb %g0, [%g6 + TI_WSAVED] + ENDPROC(dtrace_stub_exit) diff --git a/arch/sparc/kernel/dtrace_util.c b/arch/sparc/kernel/dtrace_util.c new file mode 100644 index 000000000000..4c3126c99cea --- /dev/null +++ b/arch/sparc/kernel/dtrace_util.c @@ -0,0 +1,66 @@ +/* + * FILE: dtrace_util.c + * DESCRIPTION: Dynamic Tracing: Architecture utility functions + * + * Copyright (C) 2010-2014 Oracle Corporation + */ + +#include +#include +#include +#include +#include + +void dtrace_skip_instruction(struct pt_regs *regs) { + regs->tpc = regs->tnpc; + regs->tnpc += 4; +} + + +int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, + void *args) +{ + struct die_args *dargs = args; + + switch (val) { + case DIE_PAGE_FAULT: { + unsigned long addr = current_thread_info()->fault_address; + + if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) + return NOTIFY_DONE; + + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + this_cpu_core->cpuc_dtrace_illval = addr; + + dtrace_skip_instruction(dargs->regs); + + return NOTIFY_OK | NOTIFY_STOP_MASK; + } + case DIE_GPF: { + if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) + return NOTIFY_DONE; + + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + + dtrace_skip_instruction(dargs->regs); + + return NOTIFY_OK | NOTIFY_STOP_MASK; + } + case DIE_TRAP: { + unsigned long addr = current_thread_info()->fault_address; + + if (dargs->trapnr != 0x34) + return NOTIFY_DONE; + if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) + return NOTIFY_DONE; + + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + + dtrace_skip_instruction(dargs->regs); + + return NOTIFY_OK | NOTIFY_STOP_MASK; + } + default: + return NOTIFY_DONE; + } +} diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index 8b1c915fe262..3e66613e7ee4 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,8 @@ /*---------------------------------------------------------------------------*\ (* OS SPECIFIC DTRACE SETUP *) \*---------------------------------------------------------------------------*/ +#define DTRACE_PDATA_MAXSIZE 2048 + struct module *dtrace_kmod = NULL; EXPORT_SYMBOL(dtrace_kmod); @@ -40,19 +43,38 @@ struct kmem_cache *psinfo_cachep; void dtrace_os_init(void) { if (dtrace_kmod != NULL) { - pr_warning("%s: cannot be called twice\n", __func__); + pr_warn_once("%s: cannot be called twice\n", __func__); return; } - dtrace_kmod = kzalloc(sizeof(struct module), GFP_KERNEL); + /* + * A little bit of magic... + * We create a dummy module to represent the core Linux kernel. The + * only data we're interested in is the name, the SDT probe points data + * (to be filled in by dtrace_sdt_register()), and the probe data. + * DTrace uses an architecture-specific structure (hidden from us here) + * to hold some data, and since we do not know the layout or the size, + * we ensure that we allocate enough memory to accomodate the largest + * of those structures. + * So, the memory we allocate will hold: + * - the dtrace_kmod module structure + * - a block of memory (aligned at a structure boundary) to be + * used for pdata and other related data + * The memory is allocated from the modules space. + */ + dtrace_kmod = module_alloc(ALIGN(sizeof(struct module), 8) + + DTRACE_PDATA_MAXSIZE); if (dtrace_kmod == NULL) { pr_warning("%s: cannot allocate kernel pseudo-module\n", __func__); return; } - dtrace_kmod->state = MODULE_STATE_LIVE; strlcpy(dtrace_kmod->name, "vmlinux", MODULE_NAME_LEN); + dtrace_kmod->state = MODULE_STATE_LIVE; + dtrace_kmod->pdata = (char *)dtrace_kmod + + ALIGN(sizeof(struct module), 8); + dtrace_kmod->core_size = DTRACE_PDATA_MAXSIZE; psinfo_cachep = kmem_cache_create("psinfo_cache", sizeof(dtrace_psinfo_t), 0, @@ -80,7 +102,7 @@ EXPORT_SYMBOL(dtrace_os_exit); void dtrace_psinfo_alloc(struct task_struct *tsk) { dtrace_psinfo_t *psinfo; - struct mm_struct *mm; + struct mm_struct *mm = NULL; if (likely(tsk->dtrace_psinfo)) { put_psinfo(tsk); @@ -119,7 +141,7 @@ void dtrace_psinfo_alloc(struct task_struct *tsk) psinfo->argc = 0; for (p = (char *)mm->arg_start; p < (char *)mm->arg_end; psinfo->argc++) { - size_t l = strnlen(p, MAX_ARG_STRLEN); + size_t l = strnlen_user(p, MAX_ARG_STRLEN); if (!l) break; @@ -143,7 +165,7 @@ void dtrace_psinfo_alloc(struct task_struct *tsk) */ for (i = 0, p = (char *)mm->arg_start; i < len; i++) { psinfo->argv[i] = p; - p += strnlen(p, MAX_ARG_STRLEN) + 1; + p += strnlen_user(p, MAX_ARG_STRLEN) + 1; } psinfo->argv[len] = NULL; @@ -152,7 +174,7 @@ void dtrace_psinfo_alloc(struct task_struct *tsk) */ for (p = (char *)mm->env_start; p < (char *)mm->env_end; envc++) { - size_t l = strnlen(p, MAX_ARG_STRLEN); + size_t l = strnlen_user(p, MAX_ARG_STRLEN); if (!l) break; @@ -176,7 +198,7 @@ void dtrace_psinfo_alloc(struct task_struct *tsk) */ for (i = 0, p = (char *)mm->env_start; i < len; i++) { psinfo->envp[i] = p; - p += strnlen(p, MAX_ARG_STRLEN) + 1; + p += strnlen_user(p, MAX_ARG_STRLEN) + 1; } psinfo->envp[len] = NULL; diff --git a/kernel/dtrace/dtrace_sdt_core.c b/kernel/dtrace/dtrace_sdt_core.c index 6a91734c5a5f..e98b5743bdd8 100644 --- a/kernel/dtrace/dtrace_sdt_core.c +++ b/kernel/dtrace/dtrace_sdt_core.c @@ -63,7 +63,7 @@ void dtrace_sdt_register(struct module *mp) * Just in case we run into failures further on... */ mp->sdt_probes = NULL; - mp->num_dtrace_probes = 0; + mp->sdt_probec = 0; if (dtrace_sdt_nprobes == 0) return; @@ -109,7 +109,7 @@ void dtrace_sdt_register(struct module *mp) } mp->sdt_probes = sdps; - mp->num_dtrace_probes = cnt; + mp->sdt_probec = cnt; dtrace_sdt_nop_multi(addrs, cnt); @@ -142,14 +142,14 @@ static int dtrace_mod_notifier(struct notifier_block *nb, unsigned long val, return NOTIFY_DONE; if (!mp) return NOTIFY_DONE; - if (mp->num_dtrace_probes == 0 || mp->sdt_probes == NULL) + if (mp->sdt_probec == 0 || mp->sdt_probes == NULL) return NOTIFY_DONE; /* * Create a list of addresses (SDT probe locations) that need to be * patched with a NOP instruction (or instruction sequence). */ - addrs = (sdt_instr_t **)vmalloc(mp->num_dtrace_probes * + addrs = (sdt_instr_t **)vmalloc(mp->sdt_probec * sizeof(sdt_instr_t *)); if (addrs == NULL) { pr_warning("%s: cannot allocate SDT probe address list (%s)\n", @@ -157,7 +157,7 @@ static int dtrace_mod_notifier(struct notifier_block *nb, unsigned long val, return NOTIFY_DONE; } - for (i = cnt = 0, sdp = mp->sdt_probes; i < mp->num_dtrace_probes; + for (i = cnt = 0, sdp = mp->sdt_probes; i < mp->sdt_probec; i++, sdp++) { /* * Fix-up the offset to reflect the relocated address of the diff --git a/scripts/dtrace_sdt.sh b/scripts/dtrace_sdt.sh index 27979b8ed418..6399dcd31da8 100755 --- a/scripts/dtrace_sdt.sh +++ b/scripts/dtrace_sdt.sh @@ -27,18 +27,24 @@ fi if [ "$opr" = "sdtstub" ]; then ${NM} -u $* | \ grep __dtrace_probe_ | sort | uniq | \ - ${AWK} '{ - printf("\t.globl %s\n\t.type %s,@function\n%s:\n", - $2, $2, $2); - count++; - } - - END { - if (count) - print "\tret"; - else - exit(1); - }' > $tfn + ${AWK} -v arch=${ARCH} \ + '{ + printf("\t.globl %s\n\t.type %s,@function\n%s:\n", + $2, $2, $2); + count++; + } + + END { + if (count) { + if (arch == "x86_64") { + print "\tret"; + } else if (arch == "sparc64") { + print "\tretl"; + print "\tnop"; + } + } else + exit(1); + }' > $tfn exit 0 fi @@ -63,6 +69,8 @@ fi getline; } + + sect = 0; next; } @@ -82,7 +90,7 @@ fi next; } - /__dtrace_probe_/ && sect !~ /debug/ { + /__dtrace_probe_/ && sect && sect !~ /debug/ { $3 = substr($3, 16); sub(/-.*$/, "", $3); printf "%16s %s R %s %s\n", sect, $1, $3, sectbase[sect]; @@ -91,10 +99,12 @@ fi sort [ "x${lfn}" != "x" -a "x${lfn}" != "xkmod" ] && nm ${lfn} ) | \ + tee /tmp/DEBUG | \ awk -v lfn="${lfn}" \ + -v arch=${ARCH} \ 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { tmp = $0; - if (length(v0) > 8) { + if (length(v0) > 8 || length(v1) > 8) { d = length(v0); v0h = strtonum("0x"substr(v0, 1, d - 8)); v0l = strtonum("0x"substr(v0, d - 8 + 1)); @@ -191,18 +201,22 @@ fi pn = fun":"prb; ad = addl(baseaddr, poffst[pn]); + if (arch == "x86_64") + ad = subl(ad, 1); + if (lfn != "kmod") { - print "\tPTR\t0x" ad; - print "\tPTR\t" length(prb); - print "\tPTR\t" length(fun); - print "\t.asciz\t\042" prb "\042"; - print "\t.asciz\t\042" fun "\042"; + printf "\tPTR\t0x%s\n", ad; + printf "\tPTR\t%d\n", length(prb); + printf "\tPTR\t%d\n", length(fun); + printf "\t.asciz\t\042%s\042\n", prb; + printf "\t.asciz\t\042%s\042\n", fun; print "\tALGN"; } else { if (probec == 0) print "static sdt_probedesc_t\t_sdt_probes[] = {"; - print " {\042" prb "\042, \042"fun"\042, 0x" ad " },"; + printf " {\042%s\042, \042%s\042, 0x%s },\n", \ + prb, fun, ad; } probec++; @@ -237,7 +251,7 @@ fi print ".globl dtrace_sdt_nprobes"; print "\tALGN"; print "dtrace_sdt_nprobes:"; - print "\tPTR\t" probec; + printf "\tPTR\t%d\n", probec; } else { if (probec > 0) print "};";