From d5bbb54614070d154e815928283ac6e601f68cb8 Mon Sep 17 00:00:00 2001 From: Kris Van Hees Date: Mon, 22 May 2017 11:16:45 -0400 Subject: [PATCH] dtrace: FBT return probes on x86_64 run with in_irq() true Because FBT return probes are imeplemented on x86_64 by means of a breakpoint trap (int3), and because int3 (on Linux) causes HARDIRQ to be incremented in the preempt counter, the DTrace core thinks that the probe was triggered from IRQ context (which it may or may not be). This commit ensures that we can detect wether we're processing a probe triggered using int3, and if so, it subtracts from the HARDIRQ counter before testing it (to compensate for the int3-imposed increment). Orabug: 26089286 Signed-off-by: Kris Van Hees Reviewed-by: Tomas Jedlicka --- dtrace/dtrace_dif.c | 12 +++++++++++- dtrace/fbt_x86_64.c | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c index 974d18284935..62a66c155f65 100644 --- a/dtrace/dtrace_dif.c +++ b/dtrace/dtrace_dif.c @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -1094,9 +1095,18 @@ void dtrace_difo_release(dtrace_difo_t *dp, dtrace_vstate_t *vstate) * no way for a global variable key signature to match a thread-local key * signature. */ +#ifdef CONFIG_X86_64 +# define DTRACE_IN_IRQ() \ + ((this_cpu_core->cpu_dtrace_regs && \ + this_cpu_core->cpu_dtrace_regs->orig_ax == X86_TRAP_BP) \ + ? (hardirq_count() - HARDIRQ_OFFSET) \ + : in_irq()) +#else +# define DTRACE_IN_IRQ() in_irq() +#endif #define DTRACE_TLS_THRKEY(where) \ { \ - uint_t intr = in_irq() ? 1 : 0; \ + uint_t intr = DTRACE_IN_IRQ() ? 1 : 0; \ \ (where) = ((current->pid + DIF_VARIABLE_MAX) & \ (((uint64_t)1 << 63) - 1)) | \ diff --git a/dtrace/fbt_x86_64.c b/dtrace/fbt_x86_64.c index 7853963c91f6..7b5611959fa5 100644 --- a/dtrace/fbt_x86_64.c +++ b/dtrace/fbt_x86_64.c @@ -26,6 +26,7 @@ */ #include +#include #include #include "dtrace.h" @@ -41,15 +42,32 @@ static uint8_t fbt_invop(struct pt_regs *regs) for (; fbp != NULL; fbp = fbp->fbp_hashnext) { if ((uintptr_t)fbp->fbp_patchpoint == regs->ip) { + unsigned long orig_ax; + + /* + * We (ab)use regs->orig_ax to store the trapno since + * int3 (used for return probes) causes HARDIRQ to be + * incremented in the preempt_count, which messes with + * the TLS thread key calculation. + * + * This is not pretty, but neither is the fact that + * int3 cause handlers to think they are called from + * within an interrupt. + */ this_cpu_core->cpu_dtrace_regs = regs; + orig_ax = regs->orig_ax; + if (fbp->fbp_roffset == 0) { + regs->orig_ax = X86_TRAP_UD; dtrace_probe(fbp->fbp_id, regs->di, regs->si, regs->dx, regs->cx, regs->r8); } else { + regs->orig_ax = X86_TRAP_BP; dtrace_probe(fbp->fbp_id, fbp->fbp_roffset, regs->ax, 0, 0, 0); } + regs->orig_ax = orig_ax; this_cpu_core->cpu_dtrace_regs = NULL; return fbp->fbp_rval; -- 2.50.1