From: Kris Van Hees Date: Mon, 11 Dec 2017 20:20:16 +0000 (-0500) Subject: dtrace: fix arg5 and up retrieval for FBT entry probes on x86 X-Git-Tag: v4.1.12-124.31.3~1469 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=00e6db9038bf73605544ea430012f5272c348091;p=users%2Fjedix%2Flinux-maple.git dtrace: fix arg5 and up retrieval for FBT entry probes on x86 When tracing function entry using FBT entry probes, access to all the function arguments should be supported. The existing code supported access up to the 5th argument, but would yield incorrect results for any argument beyond that. On some kernels it could result in a crash when the 6th (or higher) argument was being retrieved. The reason for the problem lies in the fact that the first 5 arguments could be read directly from the register set, whereas the 6th argument and beyond needs to be retrieved from the stack. The generic code implementing retrieval of arguments turns out to be incorrect for FBT entry probes. Thi commit introduces a FBT-specific function to access function arguments. Orabug: 25949088 Signed-off-by: Kris Van Hees Reviewed-by: Tomas Jedlicka --- diff --git a/arch/x86/dtrace/fbt_x86_64.c b/arch/x86/dtrace/fbt_x86_64.c index 04b4e72d2745..1c40890164f9 100644 --- a/arch/x86/dtrace/fbt_x86_64.c +++ b/arch/x86/dtrace/fbt_x86_64.c @@ -73,6 +73,47 @@ static uint8_t fbt_invop(struct pt_regs *regs) return 0; } +uint64_t fbt_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); + /* + * Skip the topmost slot of the stack because that holds the return + * address for the call to the function we are entering. At this point + * the BP has not been pushed yet, so we are still working within the + * caller's stack frame. + */ + val = st[1 + argno - 6]; + DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); + + return val; +} + void fbt_provide_probe_arch(fbt_probe_t *fbp, int type, int stype) { fbp->fbp_patchval = type == FBT_ENTRY ? FBT_ENTRY_PATCHVAL diff --git a/dtrace/fbt_impl.h b/dtrace/fbt_impl.h index 8c6b052b22f1..475813d62845 100644 --- a/dtrace/fbt_impl.h +++ b/dtrace/fbt_impl.h @@ -37,6 +37,7 @@ extern void fbt_provide_module(void *, struct module *); extern void fbt_destroy_module(void *, struct module *); extern int _fbt_enable(void *, dtrace_id_t, void *); extern void _fbt_disable(void *, dtrace_id_t, void *); +extern uint64_t fbt_getarg(void *, dtrace_id_t, void *, int, int); extern void fbt_destroy(void *, dtrace_id_t, void *); extern dtrace_provider_id_t fbt_id; diff --git a/dtrace/fbt_mod.c b/dtrace/fbt_mod.c index 22a89ae84445..cdaa548b4ff1 100644 --- a/dtrace/fbt_mod.c +++ b/dtrace/fbt_mod.c @@ -45,7 +45,11 @@ static dtrace_pops_t fbt_pops = { .dtps_suspend = NULL, .dtps_resume = NULL, .dtps_getargdesc = NULL, +#ifdef CONFIG_X86_64 + .dtps_getargval = fbt_getarg, +#else .dtps_getargval = NULL, +#endif .dtps_usermode = NULL, .dtps_destroy = fbt_destroy }; diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index 199595a05ce5..3ddd226fcb20 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -315,6 +315,16 @@ fail: static DEFINE_SPINLOCK(psinfo_lock); static dtrace_psinfo_t *psinfo_free_list; +#ifdef CONFIG_DT_DEBUG +void dt_debug_probe(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3, + uint64_t a4, uint64_t a5, uint64_t a6, uint64_t a7) +{ + DTRACE_PROBE(test, uint64_t, a0, uint64_t, a1, uint64_t, a2, + uint64_t, a3, uint64_t, a4, uint64_t, a5, + uint64_t, a6, uint64_t, a7); +} +#endif + /* * Work queue handler to clean up psinfo structures for tasks that no longer * exist. @@ -330,9 +340,7 @@ static void psinfo_cleaner(struct work_struct *work) spin_unlock_irqrestore(&psinfo_lock, flags); #ifdef CONFIG_DT_DEBUG - DTRACE_PROBE(test, uint64_t, 10, uint64_t, 20, uint64_t, 30, - uint64_t, 40, uint64_t, 50, uint64_t, 60, - uint64_t, 70, uint64_t, 80); + dt_debug_probe(10, 20, 30, 40, 50, 60, 70, 80); #endif while (psinfo) {