From ab27b30ac795c2c9807cf8f393fd1af5e81a0791 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Tue, 10 Feb 2015 11:33:19 -0500 Subject: [PATCH] dtrace: restructuring to support DTrace on multiple architectures Restructure the DTrace modules code to facilitate supporting ultiple architectures (rather than just x86_64). - The assembler implementation of support functions is now in a file named dtrace_asm_.S and arch-specific aspects are found in dtrace_isa_.c. The SDT provider requires an arch-specific portion of code as well (in sdt_.c). - The number of frames to skip for specific probes has been updated to be more accurate (mistakes in this area were found during code review). - The mechanism for direct calling the test probe in dt_test_probe() has been updated to work around compiler warnings. - Removed dtrace_modload and dtrace_modunload. They were expected to be needed for multi-arch support but it turns out that was not the case. - Add conditionals to not try to build anything that relates to providers not necessarily being supported on all platforms. - Various fixes for varable datatype issues that were not noticed on x86 because they mapped to the same or similar numeric datatypes. - Pass the dtrace_mstate_t struct to dtrace_getstackdepth() to support the limitation that memory allocation cannot be done from probe context. The dtrace_getstackdepth() function uses the dtrace_mstate_t information to obtain a scratch area of memory to use as temporary storage for PCs in the processing of dtrace_stacktrace(). - Handle the fact that on x86, the user sp for the current task can be obtained using current_user_stack_pointer() whereas other platforms use user_stack_pointer(current_pt_regs). - Support that fact that the current instruction pointer is not always an 'ip' member of the pt_regs struct. Always obtain the value of the instruction pointer using the instruction_pointer(regs function. - Support the use of asm/dtrace_syscall.h to list the system calls that are implemented using an assembler stub. - Ensure that membar functions use the SMP-versions. - Clean up byte order conditionals. - Remove dead code. - Ensure needed header files are explicitly included. - Update copyright statements. Orabug: 20262965 Signed-off-by: Kris Van Hees Acked-by: Nick Alcock --- dtrace/Kbuild | 9 +- dtrace/dt_test_dev.c | 33 ++- dtrace/dtrace_actdesc.c | 3 +- dtrace/{dtrace_asm.S => dtrace_asm_x86_64.S} | 2 +- dtrace/dtrace_dev.c | 20 +- dtrace/dtrace_dif.c | 28 ++- dtrace/dtrace_dof.c | 3 +- dtrace/dtrace_ecb.c | 3 +- dtrace/dtrace_enable.c | 3 +- dtrace/dtrace_fmt.c | 3 +- dtrace/dtrace_hash.c | 3 +- dtrace/dtrace_isa.c | 207 +++-------------- dtrace/dtrace_isa_x86_64.c | 228 +++++++++++++++++++ dtrace/dtrace_probe.c | 13 +- dtrace/dtrace_util.c | 3 +- dtrace/include/dtrace/dtrace_impl.h | 9 +- dtrace/include/dtrace/dtrace_impl_defines.h | 34 +-- dtrace/include/x86_64/dtrace/sdt_arch.h | 38 ++++ dtrace/profile_dev.c | 10 +- dtrace/sdt_dev.c | 88 ++----- dtrace/sdt_impl.h | 18 +- dtrace/sdt_mod.c | 6 +- dtrace/sdt_x86_64.c | 125 ++++++++++ dtrace/systrace_dev.c | 68 +++--- 24 files changed, 568 insertions(+), 389 deletions(-) rename dtrace/{dtrace_asm.S => dtrace_asm_x86_64.S} (98%) create mode 100644 dtrace/dtrace_isa_x86_64.c create mode 100644 dtrace/include/x86_64/dtrace/sdt_arch.h create mode 100644 dtrace/sdt_x86_64.c diff --git a/dtrace/Kbuild b/dtrace/Kbuild index 89b78c669701..a567bb8c9b69 100644 --- a/dtrace/Kbuild +++ b/dtrace/Kbuild @@ -24,7 +24,8 @@ # Copyright 2011 -- 2013 Oracle, Inc. All rights reserved. # Use is subject to license terms. -EXTRA_CFLAGS := -I$(src)/include -I$(src)/include/uapi +EXTRA_CFLAGS := -I$(src)/include -I$(src)/include/uapi \ + -I$(src)/include/$(ARCH) obj-$(CONFIG_DT_CORE) += dtrace.o obj-$(CONFIG_DT_FASTTRAP) += fasttrap.o @@ -35,18 +36,18 @@ obj-$(CONFIG_DT_DT_TEST) += dt_test.o obj-$(CONFIG_DT_DT_PERF) += dt_perf.o dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_asm.o dtrace_isa.o \ + dtrace_asm_$(ARCH).o dtrace_isa_$(ARCH).o \ dtrace_actdesc.o dtrace_anon.o \ dtrace_buffer.o dtrace_dif.o dtrace_dof.o \ dtrace_ecb.o dtrace_enable.o \ - dtrace_fmt.o dtrace_hash.o \ + dtrace_fmt.o dtrace_hash.o dtrace_isa.o \ dtrace_match.o dtrace_priv.o \ dtrace_probe.o dtrace_probe_ctx.o \ dtrace_ptofapi.o dtrace_predicate.o \ dtrace_spec.o dtrace_state.o dtrace_util.o fasttrap-y := fasttrap_mod.o fasttrap_dev.o profile-y := profile_mod.o profile_dev.o -sdt-y := sdt_mod.o sdt_dev.o +sdt-y := sdt_mod.o sdt_dev.o sdt_$(ARCH).o systrace-y := systrace_mod.o systrace_dev.o dt_test-y := dt_test_mod.o dt_test_dev.o dt_perf-y := dt_perf_mod.o dt_perf_dev.o diff --git a/dtrace/dt_test_dev.c b/dtrace/dt_test_dev.c index 30a4131caa84..33cec8e396b7 100644 --- a/dtrace/dt_test_dev.c +++ b/dtrace/dt_test_dev.c @@ -21,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2011-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -43,7 +43,7 @@ void dt_test_provide(void *arg, const dtrace_probedesc_t *desc) return; pid = dtrace_probe_create(dt_test_id, - "dt_test", NULL, "test", 0, NULL); + "dt_test", NULL, "test", 1, NULL); } int _dt_test_enable(void *arg, dtrace_id_t id, void *parg) @@ -62,22 +62,33 @@ void dt_test_destroy(void *arg, dtrace_id_t id, void *parg) { } -static long dt_test_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +/* + * Direct calling into dtrace_probe() when passing more than 5 parameters to + * the probe requires a stub function. Otherwise we may not be able to get + * to the value of all arguments correctly. + */ +void dt_test_probe(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, + uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, + uintptr_t arg6, uintptr_t arg7, uintptr_t arg8, + uintptr_t arg9) { /* * Yes, this is not nice. - * Not at all. + * Not at all... * But we're doing it anyway... */ - void (*dt_test_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, - uintptr_t, uintptr_t, uintptr_t, uintptr_t, - uintptr_t, uintptr_t, uintptr_t); + void (*probe_fn)() = (void *)&dtrace_probe; + probe_fn(pid, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, + arg9); +} + +static long dt_test_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ if (enabled) { - dt_test_probe = (void *)&dtrace_probe; - dt_test_probe(pid, cmd, arg, 2ULL, 3ULL, 4ULL, 5ULL, - 6ULL, 7ULL, 8ULL, 9ULL); + dt_test_probe(cmd, arg, 2ULL, 3ULL, 4ULL, 5ULL, 6ULL, 7ULL, + 8ULL, 9ULL); return 0; } diff --git a/dtrace/dtrace_actdesc.c b/dtrace/dtrace_actdesc.c index be58b37a55a4..75a96eddf26a 100644 --- a/dtrace/dtrace_actdesc.c +++ b/dtrace/dtrace_actdesc.c @@ -21,11 +21,12 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include +#include #include "dtrace.h" diff --git a/dtrace/dtrace_asm.S b/dtrace/dtrace_asm_x86_64.S similarity index 98% rename from dtrace/dtrace_asm.S rename to dtrace/dtrace_asm_x86_64.S index 3aeb2c53ebb3..e84190d364f1 100644 --- a/dtrace/dtrace_asm.S +++ b/dtrace/dtrace_asm_x86_64.S @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ diff --git a/dtrace/dtrace_dev.c b/dtrace/dtrace_dev.c index 081d329fbf84..039d0a1e8b2c 100644 --- a/dtrace/dtrace_dev.c +++ b/dtrace/dtrace_dev.c @@ -21,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012, 2013 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "ctf_api.h" @@ -85,9 +86,6 @@ static dtrace_pattr_t dtrace_provider_attr = { DEFINE_MUTEX(dtrace_lock); -void (*dtrace_modload)(struct module *); -void (*dtrace_modunload)(struct module *); - void dtrace_nullop(void) { } @@ -1387,12 +1385,10 @@ int dtrace_dev_init(void) register_module_notifier(&dtrace_modmgmt); -#ifdef FIXME - dtrace_modload = dtrace_module_loaded; - dtrace_modunload = dtrace_module_unloaded; -#endif +#if defined(CONFIG_DT_FASTTRAP) || defined(CONFIG_DT_FASTTRAP_MODULE) dtrace_helpers_cleanup = dtrace_helpers_destroy; dtrace_helpers_fork = dtrace_helpers_duplicate; +#endif #ifdef FIXME dtrace_cpu_init = dtrace_cpu_setup_initial; dtrace_cpustart_init = dtrace_suspend; @@ -1464,7 +1460,7 @@ int dtrace_dev_init(void) NULL, "END", 0, NULL); dtrace_probeid_error = dtrace_probe_create( (dtrace_provider_id_t)dtrace_provider, NULL, - NULL, "ERROR", 0, NULL); + NULL, "ERROR", 1, NULL); dtrace_anon_property(); @@ -1515,12 +1511,10 @@ void dtrace_dev_exit(void) unregister_module_notifier(&dtrace_modmgmt); -#ifdef FIXME - dtrace_modload = NULL; - dtrace_modunload = NULL; -#endif +#if defined(CONFIG_DT_FASTTRAP) || defined(CONFIG_DT_FASTTRAP_MODULE) dtrace_helpers_cleanup = NULL; dtrace_helpers_fork = NULL; +#endif #ifdef FIXME dtrace_cpu_init = NULL; dtrace_cpustart_init = NULL; diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c index 928e9ed94014..b759f5c14d6e 100644 --- a/dtrace/dtrace_dif.c +++ b/dtrace/dtrace_dif.c @@ -21,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012, 2013 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #include @@ -1506,7 +1508,8 @@ static dtrace_dynvar_t *dtrace_dynvar(dtrace_dstate_t *dstate, uint_t nkeys, dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[me]; size_t bucket, ksize; size_t chunksize = dstate->dtds_chunksize; - uintptr_t kdata, lock, nstate; + uintptr_t kdata, lock; + dtrace_dstate_state_t nstate; uint_t i; ASSERT(nkeys != 0); @@ -1816,8 +1819,8 @@ retry: */ switch (dstate->dtds_state) { case DTRACE_DSTATE_CLEAN: { - uintptr_t *sp = - (uintptr_t *) + dtrace_dstate_state_t *sp = + (dtrace_dstate_state_t *) &dstate->dtds_state; if (++cpu >= NR_CPUS) @@ -2030,7 +2033,7 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, if (ndx >= sizeof(mstate->dtms_arg) / sizeof(mstate->dtms_arg[0])) { int aframes = - mstate->dtms_probe->dtpr_aframes + 3; + mstate->dtms_probe->dtpr_aframes + 2; dtrace_provider_t *pv; uint64_t val; @@ -2115,9 +2118,10 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, if (!dtrace_priv_kernel(state)) return 0; if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) { - int aframes = mstate->dtms_probe->dtpr_aframes + 3; + int aframes = mstate->dtms_probe->dtpr_aframes + 2; - mstate->dtms_stackdepth = dtrace_getstackdepth(aframes); + mstate->dtms_stackdepth = dtrace_getstackdepth( + mstate, aframes); mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH; } @@ -2148,7 +2152,7 @@ static uint64_t dtrace_dif_variable(dtrace_mstate_t *mstate, return 0; if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) { - int aframes = mstate->dtms_probe->dtpr_aframes + 3; + int aframes = mstate->dtms_probe->dtpr_aframes + 2; if (!DTRACE_ANCHORED(mstate->dtms_probe)) { /* @@ -2902,7 +2906,7 @@ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, uintptr_t tokaddr = tupregs[1].dttk_value; uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; uintptr_t limit, toklimit = tokaddr + size; - uint8_t c, tokmap[32]; /* 256 / 8 */ + uint8_t c = 0, tokmap[32]; /* 256 / 8 */ char *dest = (char *)mstate->dtms_scratch_ptr; int i; @@ -3352,7 +3356,7 @@ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, case DIF_SUBR_HTONS: case DIF_SUBR_NTOHS: -#ifndef __LITTLE_ENDIAN +#ifdef __BIG_ENDIAN regs[rd] = (uint16_t)tupregs[0].dttk_value; #else regs[rd] = DT_BSWAP_16((uint16_t)tupregs[0].dttk_value); @@ -3362,7 +3366,7 @@ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, case DIF_SUBR_HTONL: case DIF_SUBR_NTOHL: -#ifndef __LITTLE_ENDIAN +#ifdef __BIG_ENDIAN regs[rd] = (uint32_t)tupregs[0].dttk_value; #else regs[rd] = DT_BSWAP_32((uint32_t)tupregs[0].dttk_value); @@ -3372,7 +3376,7 @@ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, case DIF_SUBR_HTONLL: case DIF_SUBR_NTOHLL: -#ifndef __LITTLE_ENDIAN +#ifdef __BIG_ENDIAN regs[rd] = (uint64_t)tupregs[0].dttk_value; #else regs[rd] = DT_BSWAP_64((uint64_t)tupregs[0].dttk_value); diff --git a/dtrace/dtrace_dof.c b/dtrace/dtrace_dof.c index ea9cfd1cebb0..8b9094103f03 100644 --- a/dtrace/dtrace_dof.c +++ b/dtrace/dtrace_dof.c @@ -21,12 +21,13 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012, 2013 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include #include +#include #include #include "dtrace.h" diff --git a/dtrace/dtrace_ecb.c b/dtrace/dtrace_ecb.c index 388108c592e3..c7ad8c976a10 100644 --- a/dtrace/dtrace_ecb.c +++ b/dtrace/dtrace_ecb.c @@ -21,11 +21,12 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include +#include #include "dtrace.h" diff --git a/dtrace/dtrace_enable.c b/dtrace/dtrace_enable.c index 117c3793b33f..7fe1ad10be41 100644 --- a/dtrace/dtrace_enable.c +++ b/dtrace/dtrace_enable.c @@ -21,13 +21,14 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include +#include #include "dtrace.h" diff --git a/dtrace/dtrace_fmt.c b/dtrace/dtrace_fmt.c index 408a5ab59f3e..939333b5846b 100644 --- a/dtrace/dtrace_fmt.c +++ b/dtrace/dtrace_fmt.c @@ -21,11 +21,12 @@ * * CDDL HEADER END * - * Copyright 2010, 2011 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include +#include #include "dtrace.h" diff --git a/dtrace/dtrace_hash.c b/dtrace/dtrace_hash.c index 8c07769c4dcb..0ae9dac957d7 100644 --- a/dtrace/dtrace_hash.c +++ b/dtrace/dtrace_hash.c @@ -21,11 +21,12 @@ * * CDDL HEADER END * - * Copyright 2010, 2011 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include +#include #include "dtrace.h" diff --git a/dtrace/dtrace_isa.c b/dtrace/dtrace_isa.c index 18ead9c6ec08..1e9b2c8d096d 100644 --- a/dtrace/dtrace_isa.c +++ b/dtrace/dtrace_isa.c @@ -30,199 +30,25 @@ #include #include #include +#include #include #include "dtrace.h" -/* FIXME */ -uintptr_t _userlimit = 0x00007fffffffffffLL; -uintptr_t kernelbase = 0xffff880000000000LL; - EXPORT_SYMBOL(dtrace_getfp); DEFINE_MUTEX(cpu_lock); EXPORT_SYMBOL(cpu_lock); -extern void dtrace_copy(uintptr_t, uintptr_t, size_t); -extern void dtrace_copystr(uintptr_t, uintptr_t, size_t, - volatile uint16_t *); - -static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) -{ -#ifdef FIXME - ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); -#else - if (kaddr < kernelbase || kaddr + size < kaddr) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); - this_cpu_core->cpuc_dtrace_illval = kaddr; - return 0; - } -#endif - - if (uaddr + size >= kernelbase || uaddr + size < uaddr) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); - this_cpu_core->cpuc_dtrace_illval = uaddr; - return 0; - } - - return 1; -} - -void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, - volatile uint16_t *flags) -{ - if (dtrace_copycheck(uaddr, kaddr, size)) - dtrace_copy(uaddr, kaddr, size); -} - -void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size, - volatile uint16_t *flags) -{ - if (dtrace_copycheck(uaddr, kaddr, size)) - dtrace_copy(kaddr, uaddr, size); -} - -void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, - volatile uint16_t *flags) -{ - if (dtrace_copycheck(uaddr, kaddr, size)) - dtrace_copystr(uaddr, kaddr, size, flags); -} - -void dtrace_copyoutstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, - volatile uint16_t *flags) -{ - if (dtrace_copycheck(uaddr, kaddr, size)) - dtrace_copystr(kaddr, uaddr, size, flags); -} - -#define DTRACE_FUWORD(bits) \ - uint##bits##_t dtrace_fuword##bits(void *uaddr) \ - { \ - extern uint##bits##_t dtrace_fuword##bits##_nocheck(void *);\ - \ - if ((uintptr_t)uaddr > _userlimit) { \ - DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); \ - this_cpu_core->cpuc_dtrace_illval = (uintptr_t)uaddr; \ - return 0; \ - } \ - \ - return dtrace_fuword##bits##_nocheck(uaddr); \ - } - -DTRACE_FUWORD(8) -DTRACE_FUWORD(16) -DTRACE_FUWORD(32) -DTRACE_FUWORD(64) - -uint64_t dtrace_getarg(int argno, int aframes) -{ - unsigned long bp; - uint64_t *st; - uint64_t val; - int i; - - asm volatile("movq %%rbp,%0" : "=m"(bp)); - - for (i = 0; i < aframes; i++) - bp = *((unsigned long *)bp); - - ASSERT(argno >= 5); - - /* - * The first 5 arguments (arg0 through arg4) are passed in registers - * to dtrace_probe(). The remaining arguments (arg5 through arg9) are - * passed on the stack. - * - * Stack layout: - * bp[0] = pushed bp from caller - * bp[1] = return address - * bp[2] = 6th argument (arg5 -> argno = 5) - * bp[3] = 7th argument (arg6 -> argno = 6) - * ... - */ - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - st = (uint64_t *)bp; - val = st[2 + (argno - 5)]; - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - - return val; -} - int dtrace_getipl(void) { return in_interrupt(); } -ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) -{ - struct pt_regs *rp = task_pt_regs(task); - - int regmap[] = { - REG_RBX, /* 0 -> EBX */ - REG_RCX, /* 1 -> ECX */ - REG_RDX, /* 2 -> EDX */ - REG_RSI, /* 3 -> ESI */ - REG_RDI, /* 4 -> EDI */ - REG_RBP, /* 5 -> EBP */ - REG_RAX, /* 6 -> EAX */ - REG_DS, /* 7 -> DS */ - REG_ES, /* 8 -> ES */ - REG_FS, /* 9 -> FS */ - REG_GS, /* 10 -> GS */ - REG_TRAPNO, /* 11 -> TRAPNO */ - REG_RIP, /* 12 -> EIP */ - REG_CS, /* 13 -> CS */ - REG_RFL, /* 14 -> EFL */ - REG_RSP, /* 15 -> UESP */ - REG_SS, /* 16 -> SS */ - }; - if (reg > REG_TRAPNO) { - /* - * Convert register alias index into register mapping index. - */ - reg -= REG_TRAPNO + 1; - - if (reg >= sizeof(regmap) / sizeof(int)) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return 0; - } - - reg = regmap[reg]; - } - - /* - * Most common case: direct index into pt_regs structure. - */ - if (reg <= REG_SS) - return (&rp->r15)[reg]; - - switch (reg) { - case REG_DS: - return task->thread.ds; - case REG_ES: - return task->thread.es; - case REG_FS: - return task->thread.fs; - case REG_GS: - return task->thread.gs; - case REG_TRAPNO: - return task->thread.trap_nr; - default: - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return 0; - } -} - static void dtrace_sync_func(void) { } -void dtrace_sync(void) -{ - dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); -} - void dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) { if (cpu == DTRACE_CPUALL) { @@ -231,6 +57,11 @@ void dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) smp_call_function_single(cpu, func, arg, 1); } +void dtrace_sync(void) +{ + dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); +} + void dtrace_toxic_ranges(void (*func)(uintptr_t, uintptr_t)) { /* FIXME */ @@ -248,7 +79,7 @@ void dtrace_getpcstack(uint64_t *pcstack, int pcstack_limit, int aframes, pcstack, NULL, pcstack_limit, - 0, + aframes, STACKTRACE_KERNEL }; @@ -330,7 +161,11 @@ unsigned long dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, goto out; atomic_inc(&mm->mm_users); +#ifdef CONFIG_X86_64 tos = current_user_stack_pointer(); +#else + tos = user_stack_pointer(current_pt_regs()); +#endif stack_vma = find_user_vma(p, mm, NULL, (unsigned long) tos, 0); if (!stack_vma || stack_vma->vm_start > (unsigned long) tos) @@ -417,22 +252,32 @@ void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) dtrace_getufpstack(pcstack, NULL, pcstack_limit); } -int dtrace_getstackdepth(int aframes) +int dtrace_getstackdepth(dtrace_mstate_t *mstate, int aframes) { + uintptr_t old = mstate->dtms_scratch_ptr; + size_t size; struct stacktrace_state st = { NULL, NULL, 0, - 0, + aframes, STACKTRACE_KERNEL }; + st.pcs = (uint64_t *)P2ROUNDUP(mstate->dtms_scratch_ptr, 8); + size = (uintptr_t)st.pcs - mstate->dtms_scratch_ptr + + aframes * sizeof(uint64_t); + if (mstate->dtms_scratch_ptr + size > + mstate->dtms_scratch_base + mstate->dtms_scratch_size) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); + return 0; + } + dtrace_stacktrace(&st); - if (st.depth <= aframes) - return 0; + mstate->dtms_scratch_ptr = old; - return st.depth - aframes; + return st.depth; } int dtrace_getustackdepth(void) diff --git a/dtrace/dtrace_isa_x86_64.c b/dtrace/dtrace_isa_x86_64.c new file mode 100644 index 000000000000..192017123515 --- /dev/null +++ b/dtrace/dtrace_isa_x86_64.c @@ -0,0 +1,228 @@ +/* + * FILE: dtrace_isa_x86_64.c + * DESCRIPTION: Dynamic Tracing: x86_64 architecture specific support functions + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2010-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include + +#include "dtrace.h" + +/* Register indices */ +#define REG_TRAPNO 25 +#define REG_GS 24 +#define REG_FS 23 +#define REG_ES 22 +#define REG_DS 21 +#define REG_SS 20 +#define REG_RSP 19 +#define REG_RFL 18 +#define REG_CS 17 +#define REG_RIP 16 +#define REG_ERR 15 +#define REG_RDI 14 +#define REG_RSI 13 +#define REG_RDX 12 +#define REG_RCX 11 +#define REG_RAX 10 +#define REG_R8 9 +#define REG_R9 8 +#define REG_R10 7 +#define REG_R11 6 +#define REG_RBX 5 +#define REG_RBP 4 +#define REG_R12 3 +#define REG_R13 2 +#define REG_R14 1 +#define REG_R15 0 + +extern void dtrace_copy(uintptr_t, uintptr_t, size_t); +extern void dtrace_copystr(uintptr_t, uintptr_t, size_t, + volatile uint16_t *); + +uintptr_t _userlimit = 0x00007fffffffffffLL; +uintptr_t kernelbase = 0xffff880000000000LL; + +static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) +{ +#ifdef FIXME + ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); +#else + if (kaddr < kernelbase || kaddr + size < kaddr) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + this_cpu_core->cpuc_dtrace_illval = kaddr; + return 0; + } +#endif + + if (uaddr + size >= kernelbase || uaddr + size < uaddr) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + this_cpu_core->cpuc_dtrace_illval = uaddr; + return 0; + } + + return 1; +} + +void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +{ + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copy(uaddr, kaddr, size); +} + +void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +{ + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copy(kaddr, uaddr, size); +} + +void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +{ + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copystr(uaddr, kaddr, size, flags); +} + +void dtrace_copyoutstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, + volatile uint16_t *flags) +{ + if (dtrace_copycheck(uaddr, kaddr, size)) + dtrace_copystr(kaddr, uaddr, size, flags); +} + +#define DTRACE_FUWORD(bits) \ + uint##bits##_t dtrace_fuword##bits(void *uaddr) \ + { \ + extern uint##bits##_t dtrace_fuword##bits##_nocheck(void *);\ + \ + if ((uintptr_t)uaddr > _userlimit) { \ + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); \ + this_cpu_core->cpuc_dtrace_illval = (uintptr_t)uaddr; \ + return 0; \ + } \ + \ + return dtrace_fuword##bits##_nocheck(uaddr); \ + } + +DTRACE_FUWORD(8) +DTRACE_FUWORD(16) +DTRACE_FUWORD(32) +DTRACE_FUWORD(64) + +uint64_t dtrace_getarg(int argno, int aframes) +{ + unsigned long bp; + uint64_t *st; + uint64_t val; + int i; + + asm volatile("movq %%rbp,%0" : "=m"(bp)); + + for (i = 0; i < aframes; i++) + bp = *((unsigned long *)bp); + + ASSERT(argno >= 5); + + /* + * The first 5 arguments (arg0 through arg4) are passed in registers + * to dtrace_probe(). The remaining arguments (arg5 through arg9) are + * passed on the stack. + * + * Stack layout: + * bp[0] = pushed bp from caller + * bp[1] = return address + * bp[2] = 6th argument (arg5 -> argno = 5) + * bp[3] = 7th argument (arg6 -> argno = 6) + * ... + */ + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + st = (uint64_t *)bp; + val = st[2 + (argno - 5)]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + + return val; +} + +ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) +{ + struct pt_regs *rp = task_pt_regs(task); + + int regmap[] = { + REG_RBX, /* 0 -> EBX */ + REG_RCX, /* 1 -> ECX */ + REG_RDX, /* 2 -> EDX */ + REG_RSI, /* 3 -> ESI */ + REG_RDI, /* 4 -> EDI */ + REG_RBP, /* 5 -> EBP */ + REG_RAX, /* 6 -> EAX */ + REG_DS, /* 7 -> DS */ + REG_ES, /* 8 -> ES */ + REG_FS, /* 9 -> FS */ + REG_GS, /* 10 -> GS */ + REG_TRAPNO, /* 11 -> TRAPNO */ + REG_RIP, /* 12 -> EIP */ + REG_CS, /* 13 -> CS */ + REG_RFL, /* 14 -> EFL */ + REG_RSP, /* 15 -> UESP */ + REG_SS, /* 16 -> SS */ + }; + + if (reg > REG_TRAPNO) { + /* + * Convert register alias index into register mapping index. + */ + reg -= REG_TRAPNO + 1; + + if (reg >= sizeof(regmap) / sizeof(int)) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return 0; + } + + reg = regmap[reg]; + } + + /* + * Most common case: direct index into pt_regs structure. + */ + if (reg <= REG_SS) + return (&rp->r15)[reg]; + + switch (reg) { + case REG_DS: + return task->thread.ds; + case REG_ES: + return task->thread.es; + case REG_FS: + return task->thread.fs; + case REG_GS: + return task->thread.gs; + case REG_TRAPNO: + return task->thread.trap_nr; + default: + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return 0; + } +} diff --git a/dtrace/dtrace_probe.c b/dtrace/dtrace_probe.c index 5076765a1f2c..e042e82fe4a8 100644 --- a/dtrace/dtrace_probe.c +++ b/dtrace/dtrace_probe.c @@ -21,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012, 2013 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,10 +30,11 @@ #include #include #include +#include +#include #include #include "dtrace.h" -#include "sdt_impl.h" ktime_t dtrace_chill_interval = KTIME_INIT(1, 0); @@ -384,14 +385,8 @@ static void dtrace_action_raise(uint64_t sig) * raise() has a queue depth of 1 -- we ignore all subsequent * invocations of the raise() action. */ -#if 0 - - sigaddset(¤t->pending.signal, sig); - set_thread_flag(TIF_SIGPENDING); -#else if (current->dtrace_sig == 0) current->dtrace_sig = (uint8_t)sig; -#endif } static void dtrace_action_stop(void) @@ -1260,7 +1255,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, dtrace_probe_error( state, ecb->dte_epid, ndx, (mstate.dtms_present & DTRACE_MSTATE_FLTOFFS) - ? mstate.dtms_fltoffs + ? mstate.dtms_fltoffs : -1, DTRACE_FLAGS2FLT(*flags), this_cpu_core->cpuc_dtrace_illval); diff --git a/dtrace/dtrace_util.c b/dtrace/dtrace_util.c index bfbf3b46d880..8063f01608f5 100644 --- a/dtrace/dtrace_util.c +++ b/dtrace/dtrace_util.c @@ -21,12 +21,13 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ #include #include +#include #include "dtrace.h" diff --git a/dtrace/include/dtrace/dtrace_impl.h b/dtrace/include/dtrace/dtrace_impl.h index c1198cb3b4aa..01482893b14e 100644 --- a/dtrace/include/dtrace/dtrace_impl.h +++ b/dtrace/include/dtrace/dtrace_impl.h @@ -28,7 +28,7 @@ * * CDDL HEADER END * - * Copyright 2009 -- 2013 Oracle, Inc. All rights reserved. + * Copyright 2009-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -854,8 +854,8 @@ extern void dtrace_cred2priv(const cred_t *, uint32_t *, uid_t *); extern void ctf_forceload(void); -#define dtrace_membar_producer() wmb() -#define dtrace_membar_consumer() rmb() +#define dtrace_membar_producer() smp_wmb() +#define dtrace_membar_consumer() smp_rmb() typedef unsigned long dtrace_icookie_t; @@ -875,6 +875,7 @@ typedef void (*dtrace_xcall_t)(void *); extern void dtrace_xcall(processorid_t, dtrace_xcall_t, void *); +extern uintptr_t dtrace_fulword(void *); extern uint8_t dtrace_fuword8(void *); extern uint16_t dtrace_fuword16(void *); extern uint32_t dtrace_fuword32(void *); @@ -888,7 +889,7 @@ extern void dtrace_getupcstack(uint64_t *, int); extern unsigned long dtrace_getufpstack(uint64_t *, uint64_t *, int); extern uintptr_t dtrace_getfp(void); extern uint64_t dtrace_getarg(int, int); -extern int dtrace_getstackdepth(int); +extern int dtrace_getstackdepth(dtrace_mstate_t *, int); extern int dtrace_getustackdepth(void); extern ulong_t dtrace_getreg(struct task_struct *, uint_t); extern void dtrace_copyin(uintptr_t, uintptr_t, size_t, volatile uint16_t *); diff --git a/dtrace/include/dtrace/dtrace_impl_defines.h b/dtrace/include/dtrace/dtrace_impl_defines.h index 39327155f21d..c18586ac84fe 100644 --- a/dtrace/include/dtrace/dtrace_impl_defines.h +++ b/dtrace/include/dtrace/dtrace_impl_defines.h @@ -28,7 +28,7 @@ * * CDDL HEADER END * - * Copyright 2009 -- 2013 Oracle, Inc. All rights reserved. + * Copyright 2009-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,7 +36,7 @@ #include #include -typedef typeof(((struct pt_regs *)0)->ip) pc_t; +typedef typeof(instruction_pointer((struct pt_regs *)0)) pc_t; typedef enum dtrace_activity { DTRACE_ACTIVITY_INACTIVE = 0, @@ -155,36 +155,6 @@ typedef enum dtrace_speculation_state { #define KERNELBASE (uintptr_t)_text -/* - * regset.h information - */ -#define REG_TRAPNO 25 -#define REG_GS 24 -#define REG_FS 23 -#define REG_ES 22 -#define REG_DS 21 -#define REG_SS 20 -#define REG_RSP 19 -#define REG_RFL 18 -#define REG_CS 17 -#define REG_RIP 16 -#define REG_ERR 15 -#define REG_RDI 14 -#define REG_RSI 13 -#define REG_RDX 12 -#define REG_RCX 11 -#define REG_RAX 10 -#define REG_R8 9 -#define REG_R9 8 -#define REG_R10 7 -#define REG_R11 6 -#define REG_RBX 5 -#define REG_RBP 4 -#define REG_R12 3 -#define REG_R13 2 -#define REG_R14 1 -#define REG_R15 0 - #if defined(__i386__) || defined(__x86_64__) # define DTRACE_INVOP_PUSHL_EBP 1 # define DTRACE_INVOP_POPL_EBP 2 diff --git a/dtrace/include/x86_64/dtrace/sdt_arch.h b/dtrace/include/x86_64/dtrace/sdt_arch.h new file mode 100644 index 000000000000..0179400a2e3b --- /dev/null +++ b/dtrace/include/x86_64/dtrace/sdt_arch.h @@ -0,0 +1,38 @@ +#ifndef _X86_64_SDT_ARCH_H +#define _X86_64_SDT_ARCH_H + +/* + * Statically Defined Tracing Implementation defines + * + * Note: The contents of this file are private to the implementation of the + * DTrace subsystem and are subject to change at any time without notice. + */ + +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2009-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + + +#define SDT_AFRAMES 4 + +#endif /* _X86_64_SDT_ARCH_H */ diff --git a/dtrace/profile_dev.c b/dtrace/profile_dev.c index 8805d9112202..73aba6fd9d04 100644 --- a/dtrace/profile_dev.c +++ b/dtrace/profile_dev.c @@ -21,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -107,9 +107,9 @@ static void profile_tick_fn(uintptr_t arg) dtrace_getpcstack(stack, 8, 0, NULL); pc = stack[7]; } else if (user_mode(regs)) - upc = GET_IP(regs); + upc = instruction_pointer(regs); else - pc = GET_IP(regs); + pc = instruction_pointer(regs); dtrace_probe(prof->prof_id, pc, upc, 0, 0, 0); } @@ -140,9 +140,9 @@ static void profile_prof_fn(uintptr_t arg) dtrace_getpcstack(stack, 8, 0, NULL); pc = stack[7]; } else if (user_mode(regs)) - upc = GET_IP(regs); + upc = instruction_pointer(regs); else - pc = GET_IP(regs); + pc = instruction_pointer(regs); dtrace_probe(prof->prof_id, pc, upc, ktime_to_ns(late), 0, 0); } diff --git a/dtrace/sdt_dev.c b/dtrace/sdt_dev.c index e4b668ddbf83..c0bc989f5985 100644 --- a/dtrace/sdt_dev.c +++ b/dtrace/sdt_dev.c @@ -21,7 +21,7 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,18 +30,17 @@ #include #include #include +#include #include "dtrace.h" #include "dtrace_dev.h" #include "sdt_impl.h" -#define SDT_PATCHVAL 0xf0 -#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask) #define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ -static sdt_probe_t **sdt_probetab; -static int sdt_probetab_size; -static int sdt_probetab_mask; +sdt_probe_t **sdt_probetab; +int sdt_probetab_size; +int sdt_probetab_mask; static sdt_argdesc_t sdt_args[] = { /* @@ -103,26 +102,6 @@ static sdt_argdesc_t sdt_args[] = { { NULL, } }; -static uint8_t sdt_invop(struct pt_regs *regs) -{ - sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(regs->ip)]; - - for (; sdt != NULL; sdt = sdt->sdp_hashnext) { - if ((uintptr_t)sdt->sdp_patchpoint == regs->ip) { - this_cpu_core->cpu_dtrace_regs = regs; - - dtrace_probe(sdt->sdp_id, regs->di, regs->si, - regs->dx, regs->cx, regs->r8); - - this_cpu_core->cpu_dtrace_regs = NULL; - - return DTRACE_INVOP_NOP; - } - } - - return 0; -} - void sdt_provide_module(void *arg, struct module *mp) { char *modname = mp->name; @@ -152,6 +131,9 @@ void sdt_provide_module(void *arg, struct module *mp) return; } + if (!sdt_provide_module_arch(arg, mp)) + return; + for (idx = 0, sdpd = mp->sdt_probes; idx < mp->num_dtrace_probes; idx++, sdpd++) { char *name = sdpd->sdpd_name, *nname; @@ -212,7 +194,8 @@ void sdt_provide_module(void *arg, struct module *mp) sdp->sdp_id = dtrace_probe_create(prov->dtmp_id, modname, sdpd->sdpd_func, - nname, 3, sdp); + nname, SDT_AFRAMES, + sdp); mp->sdt_nprobes++; } @@ -220,9 +203,9 @@ void sdt_provide_module(void *arg, struct module *mp) SDT_ADDR2NDX(sdpd->sdpd_offset)]; sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp; - sdp->sdp_patchval = SDT_PATCHVAL; - sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset; - sdp->sdp_savedval = *sdp->sdp_patchpoint; + sdp->sdp_patchpoint = (sdt_instr_t *)sdpd->sdpd_offset; + + sdt_provide_probe_arch(sdp, mp, idx); } } @@ -246,7 +229,7 @@ int _sdt_enable(void *arg, dtrace_id_t id, void *parg) module_put(sdp->sdp_module); while (sdp != NULL) { - dtrace_invop_enable(sdp->sdp_patchpoint); + sdt_enable_arch(sdp, id, arg); sdp = sdp->sdp_next; } @@ -268,7 +251,7 @@ void _sdt_disable(void *arg, dtrace_id_t id, void *parg) module_put(sdp->sdp_module); while (sdp != NULL) { - dtrace_invop_disable(sdp->sdp_patchpoint, sdp->sdp_savedval); + sdt_disable_arch(sdp, id, arg); sdp = sdp->sdp_next; } } @@ -309,42 +292,6 @@ void sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, desc->dtargd_ndx = DTRACE_ARGNONE; } -uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, - int aframes) -{ - struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; - uint64_t *st; - uint64_t val; - - if (regs == NULL) - return 0; - - switch (argno) { - case 0: - return regs->di; - case 1: - return regs->si; - case 2: - return regs->dx; - case 3: - return regs->cx; - case 4: - return regs->r8; - case 5: - return regs->r9; - } - - ASSERT(argno > 5); - - st = (uint64_t *)regs->sp; - DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); - __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6], - sizeof(st[0])); - DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); - - return val; -} - void sdt_destroy(void *arg, dtrace_id_t id, void *parg) { sdt_probe_t *sdp = parg; @@ -425,14 +372,15 @@ int sdt_dev_init(void) if (sdt_probetab == NULL) return -ENOMEM; - ret = dtrace_invop_add(sdt_invop); + sdt_dev_init_arch(); return ret; } void sdt_dev_exit(void) { - dtrace_invop_remove(sdt_invop); + sdt_dev_exit_arch(); + vfree(sdt_probetab); misc_deregister(&sdt_dev); diff --git a/dtrace/sdt_impl.h b/dtrace/sdt_impl.h index e26f795de507..bcfe2533968f 100644 --- a/dtrace/sdt_impl.h +++ b/dtrace/sdt_impl.h @@ -2,6 +2,8 @@ #define _SDT_IMPL_H_ #include +#include +#include extern struct module *dtrace_kmod; @@ -29,7 +31,18 @@ typedef struct sdt_argdesc { char *sda_xlate; } sdt_argdesc_t; -extern dtrace_mprovider_t sdt_providers[]; +extern dtrace_mprovider_t sdt_providers[]; +extern sdt_probe_t **sdt_probetab; +extern int sdt_probetab_size; +extern int sdt_probetab_mask; + +#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & \ + sdt_probetab_mask) + +extern void sdt_provide_probe_arch(sdt_probe_t *, struct module *, int); +extern int sdt_provide_module_arch(void *, struct module *); +extern void sdt_enable_arch(sdt_probe_t *, dtrace_id_t, void *); +extern void sdt_disable_arch(sdt_probe_t *, dtrace_id_t, void *); extern void sdt_provide_module(void *, struct module *); extern int _sdt_enable(void *, dtrace_id_t, void *); @@ -41,4 +54,7 @@ extern void sdt_destroy(void *, dtrace_id_t, void *); extern int sdt_dev_init(void); extern void sdt_dev_exit(void); +extern int sdt_dev_init_arch(void); +extern void sdt_dev_exit_arch(void); + #endif /* _SDT_IMPL_H_ */ diff --git a/dtrace/sdt_mod.c b/dtrace/sdt_mod.c index 643b1539929f..f189edca980e 100644 --- a/dtrace/sdt_mod.c +++ b/dtrace/sdt_mod.c @@ -22,7 +22,7 @@ * * CDDL HEADER END * - * Copyright 2010, 2011, 2012 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ @@ -119,7 +119,11 @@ static dtrace_pops_t sdt_pops = { NULL, NULL, sdt_getargdesc, +#ifdef CONFIG_X86_64 sdt_getarg, +#else + NULL, +#endif NULL, sdt_destroy, }; diff --git a/dtrace/sdt_x86_64.c b/dtrace/sdt_x86_64.c new file mode 100644 index 000000000000..1faac5b601da --- /dev/null +++ b/dtrace/sdt_x86_64.c @@ -0,0 +1,125 @@ +/* + * FILE: sdt_dev.c + * DESCRIPTION: Statically Defined Tracing: device file handling + * + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2010-2014 Oracle, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include +#include +#include +#include + +#include "dtrace.h" +#include "dtrace_dev.h" +#include "sdt_impl.h" + +#define SDT_PATCHVAL 0xf0 + +static uint8_t sdt_invop(struct pt_regs *regs) +{ + sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(regs->ip)]; + + for (; sdt != NULL; sdt = sdt->sdp_hashnext) { + if ((uintptr_t)sdt->sdp_patchpoint == regs->ip) { + this_cpu_core->cpu_dtrace_regs = regs; + + dtrace_probe(sdt->sdp_id, regs->di, regs->si, + regs->dx, regs->cx, regs->r8); + + this_cpu_core->cpu_dtrace_regs = NULL; + + return DTRACE_INVOP_NOP; + } + } + + return 0; +} + +void sdt_provide_probe_arch(sdt_probe_t *sdp, struct module *mp, int idx) +{ + sdp->sdp_patchval = SDT_PATCHVAL; + sdp->sdp_savedval = *sdp->sdp_patchpoint; +} + +int sdt_provide_module_arch(void *arg, struct module *mp) +{ + return 1; +} + +void sdt_enable_arch(sdt_probe_t *sdp, dtrace_id_t id, void *arg) +{ + dtrace_invop_enable((uint8_t *)sdp->sdp_patchpoint); +} + +void sdt_disable_arch(sdt_probe_t *sdp, dtrace_id_t id, void *arg) +{ + dtrace_invop_disable((uint8_t *)sdp->sdp_patchpoint, + sdp->sdp_savedval); +} + +uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, + int aframes) +{ + struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; + uint64_t *st; + uint64_t val; + + if (regs == NULL) + return 0; + + switch (argno) { + case 0: + return regs->di; + case 1: + return regs->si; + case 2: + return regs->dx; + case 3: + return regs->cx; + case 4: + return regs->r8; + case 5: + return regs->r9; + } + + ASSERT(argno > 5); + + st = (uint64_t *)regs->sp; + DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); + __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6], + sizeof(st[0])); + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + + return val; +} + +int sdt_dev_init_arch(void) +{ + return dtrace_invop_add(sdt_invop); +} + +void sdt_dev_exit_arch(void) +{ + dtrace_invop_remove(sdt_invop); +} diff --git a/dtrace/systrace_dev.c b/dtrace/systrace_dev.c index a4c6c3c2deec..8727637a4b73 100644 --- a/dtrace/systrace_dev.c +++ b/dtrace/systrace_dev.c @@ -21,10 +21,11 @@ * * CDDL HEADER END * - * Copyright 2010, 2011 Oracle, Inc. All rights reserved. + * Copyright 2010-2014 Oracle, Inc. All rights reserved. * Use is subject to license terms. */ +#include #include #include #include @@ -33,7 +34,7 @@ #include "dtrace_dev.h" #include "systrace.h" -#define SYSTRACE_ARTIFICIAL_FRAMES 0 +#define SYSTRACE_ARTIFICIAL_FRAMES 1 #define SYSTRACE_SHIFT 16 #define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id)) @@ -93,64 +94,55 @@ static dt_sys_call_t get_intercept(int sysnum) switch (sysnum) { default: return systrace_info->syscall; - case __NR_clone: - return systrace_info->stubs[SCE_CLONE]; - case __NR_fork: - return systrace_info->stubs[SCE_FORK]; - case __NR_vfork: - return systrace_info->stubs[SCE_VFORK]; - case __NR_iopl: - return systrace_info->stubs[SCE_IOPL]; - case __NR_execve: - return systrace_info->stubs[SCE_EXECVE]; - case __NR_rt_sigreturn: - return systrace_info->stubs[SCE_RT_SIGRETURN]; +#define DTRACE_SYSCALL_STUB(t, n) \ + case __NR_##n: \ + return systrace_info->stubs[SCE_##t]; +#include +#undef DTRACE_SYSCALL_STUB } } int _systrace_enable(void *arg, dtrace_id_t id, void *parg) { - int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); - int enabled = - systrace_info->sysent[sysnum].stsy_entry != DTRACE_IDNONE || - systrace_info->sysent[sysnum].stsy_return != DTRACE_IDNONE; - dt_sys_call_t intercept = get_intercept(sysnum); + int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); + dtrace_syscalls_t *sc = &systrace_info->sysent[sysnum]; + int enabled = sc->stsy_entry != DTRACE_IDNONE || + sc->stsy_return != DTRACE_IDNONE; + dt_sys_call_t intercept = get_intercept(sysnum); if (!enabled) { - if (cmpxchg(systrace_info->sysent[sysnum].stsy_tblent, - systrace_info->sysent[sysnum].stsy_underlying, - intercept) != - systrace_info->sysent[sysnum].stsy_underlying) - return 0; + if (cmpxchg((uint32_t *)sc->stsy_tblent, + (uint32_t)sc->stsy_underlying, + (uint32_t)intercept) != + (uint32_t)sc->stsy_underlying) + return 1; } else - ASSERT((void *)*(systrace_info->sysent[sysnum].stsy_tblent) == - (void *)intercept); + ASSERT(*(uint32_t *)sc->stsy_tblent == (uint32_t)intercept); if (SYSTRACE_ISENTRY((uintptr_t)parg)) - systrace_info->sysent[sysnum].stsy_entry = id; + sc->stsy_entry = id; else - systrace_info->sysent[sysnum].stsy_return = id; + sc->stsy_return = id; return 0; } void _systrace_disable(void *arg, dtrace_id_t id, void *parg) { - int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); - int enabled = - systrace_info->sysent[sysnum].stsy_entry != DTRACE_IDNONE || - systrace_info->sysent[sysnum].stsy_return != DTRACE_IDNONE; - dt_sys_call_t intercept = get_intercept(sysnum); + int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); + dtrace_syscalls_t *sc = &systrace_info->sysent[sysnum]; + int enabled = sc->stsy_entry != DTRACE_IDNONE || + sc->stsy_return != DTRACE_IDNONE; + dt_sys_call_t intercept = get_intercept(sysnum); if (enabled) - (void)cmpxchg(systrace_info->sysent[sysnum].stsy_tblent, - intercept, - systrace_info->sysent[sysnum].stsy_underlying); + (void)cmpxchg((uint32_t *)sc->stsy_tblent, (uint32_t)intercept, + (uint32_t)sc->stsy_underlying); if (SYSTRACE_ISENTRY((uintptr_t)parg)) - systrace_info->sysent[sysnum].stsy_entry = DTRACE_IDNONE; + sc->stsy_entry = DTRACE_IDNONE; else - systrace_info->sysent[sysnum].stsy_return = DTRACE_IDNONE; + sc->stsy_return = DTRACE_IDNONE; } void systrace_destroy(void *arg, dtrace_id_t id, void *parg) -- 2.50.1