]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: fix arg5 and up retrieval for FBT entry probes on x86
authorKris Van Hees <kris.van.hees@oracle.com>
Mon, 11 Dec 2017 20:20:16 +0000 (15:20 -0500)
committerKris Van Hees <kris.van.hees@oracle.com>
Fri, 15 Dec 2017 05:28:13 +0000 (00:28 -0500)
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 <kris.van.hees@oracle.com>
Reviewed-by: Tomas Jedlicka <tomas.jedlicka@oracle.com>
arch/x86/dtrace/fbt_x86_64.c
dtrace/fbt_impl.h
dtrace/fbt_mod.c
kernel/dtrace/dtrace_os.c

index 04b4e72d2745ff952929d471b44c2c7f8415b95b..1c40890164f9f28c597aaf018e329a9862637af5 100644 (file)
@@ -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
index 8c6b052b22f1c4074dd175496867e3ae5c3ff0c8..475813d62845652a864db3d7b14bf7f5adf8b863 100644 (file)
@@ -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;
index 22a89ae8444551f1ef1f4377b683447165637772..cdaa548b4ff113bd80f8606454e5f3485e6a0022 100644 (file)
@@ -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
 };
index 199595a05ce5eadfe76b5846d3b4d3a58490aaf5..3ddd226fcb20b50831eb54a629b67742af71fe2e 100644 (file)
@@ -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) {