]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: USDT implementation (phase 2)
authorKris Van Hees <kris.van.hees@oracle.com>
Mon, 20 May 2013 20:37:33 +0000 (16:37 -0400)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:41:44 +0000 (22:41 +0100)
This commit contains the 2nd phase of the USDT implementation for DTrace for
Linux.  It provides the mechanics of fasttrap probes (enabling, firing, and
disabling).  It also contains various debugging statements that will be cleaned
up in a future commit.  They exist right now, because this commit represents a
work in progress that is known to contain various bugs and loose ends.  The
commit for this code is provided as a "sharing of the pain" , and to ensure
that others can start playing with this code and test the interaction with
userspace.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
include/linux/dtrace_cpu.h
include/linux/dtrace_os.h
include/linux/fasttrap.h [deleted file]
include/linux/sched.h
kernel/dtrace/dtrace_cpu.c
kernel/dtrace/dtrace_os.c

index 1508de06b56718e7a7a2cfca1e1cdcf0618a40a1..02d5cf90bbd4f87c29b4398489e05e2c215a12da 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/ktime.h>
 #include <linux/mutex.h>
+#include <linux/rwlock.h>
 #include <linux/dtrace_cpu_defines.h>
 
 typedef struct cpu_core {
@@ -17,6 +18,7 @@ typedef struct cpu_core {
        uintptr_t cpu_dtrace_caller;
        ktime_t cpu_dtrace_chillmark;
        ktime_t cpu_dtrace_chilled;
+       rwlock_t cpu_ft_lock;
 } cpu_core_t;
 
 DECLARE_PER_CPU_SHARED_ALIGNED(cpu_core_t, dtrace_cpu_core);
index 969d79fc3919e2035998f2333e1a7ad269d54725..b7a6bb4f85588f3310ba697f8810e24a2caed951 100644 (file)
@@ -79,8 +79,14 @@ extern void unregister_pid_provider(pid_t);
 extern void dtrace_task_init(struct task_struct *tsk);
 extern void dtrace_task_cleanup(struct task_struct *tsk);
 
+typedef struct uprobe_consumer fasttrap_machtp_t;
+
 extern void (*dtrace_helpers_cleanup)(struct task_struct *);
 extern void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *);
+extern void (*dtrace_tracepoint_hit)(fasttrap_machtp_t *, struct pt_regs *);
+
+extern int dtrace_tracepoint_enable(pid_t, uintptr_t, fasttrap_machtp_t *);
+extern int dtrace_tracepoint_disable(pid_t, uintptr_t, fasttrap_machtp_t *);
 
 #endif
 
diff --git a/include/linux/fasttrap.h b/include/linux/fasttrap.h
deleted file mode 100644 (file)
index 75b2f52..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2011, 2012, 2013 Oracle, Inc. */
-
-#ifndef _FASTTRAP_H_
-#define        _FASTTRAP_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(CONFIG_DTRACE) || defined(CONFIG_DTRACE_MODULE)
-
-#define FASTTRAPIOC            (('m' << 24) | ('r' << 16) | ('f' << 8))
-#define FASTTRAPIOC_MAKEPROBE  (FASTTRAPIOC | 1)
-#define FASTTRAPIOC_GETINSTR   (FASTTRAPIOC | 2)
-
-typedef enum fasttrap_probe_type {
-       DTFTP_NONE = 0,
-       DTFTP_ENTRY,
-       DTFTP_RETURN,
-       DTFTP_OFFSETS,
-       DTFTP_POST_OFFSETS,
-       DTFTP_IS_ENABLED
-} fasttrap_probe_type_t;
-
-typedef struct fasttrap_probe_spec {
-       pid_t ftps_pid;
-       fasttrap_probe_type_t ftps_type;
-       char ftps_func[DTRACE_FUNCNAMELEN];
-       char ftps_mod[DTRACE_MODNAMELEN];
-       uint64_t ftps_pc;
-       uint64_t ftps_size;
-       uint64_t ftps_noffs;
-       uint64_t ftps_offs[1];
-} fasttrap_probe_spec_t;
-
-typedef uint8_t                fasttrap_instr_t;
-
-typedef struct fasttrap_instr_query {
-       uint64_t ftiq_pc;
-       pid_t ftiq_pid;
-       fasttrap_instr_t ftiq_instr;
-} fasttrap_instr_query_t;
-
-#endif /* CONFIG_DTRACE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _FASTTRAP_H_ */
index 9ca7eae1a85535176a72d3636f33683a17287171..0e598086f5995683d3a0558b018b76cca867ada1 100644 (file)
@@ -1725,6 +1725,7 @@ struct task_struct {
 
        void *dtrace_helpers;
        uint32_t dtrace_probes;
+       uint64_t dtrace_tp_count;
 #endif
 #ifdef CONFIG_UPROBES
        struct uprobe_task *utask;
index 632b92f5faa0fc426e4df22516e75c04ee61db2d..572c580fca721c58d73def8aef9aabbf5e6f9274 100644 (file)
@@ -21,12 +21,20 @@ void dtrace_cpu_init(void)
 
        for_each_present_cpu(cpu) {
                struct cpuinfo_x86      *c = &cpu_data(cpu);
-               cpuinfo_t               *i = per_cpu_info(cpu);
+               cpuinfo_t               *cpui = per_cpu_info(cpu);
+               cpu_core_t              *cpuc = per_cpu_core(cpu);
 
-               i->cpu_id = cpu;
-               i->cpu_pset = 0;
-               i->cpu_chip = c->phys_proc_id;
-               i->cpu_lgrp = 0;
-               i->cpu_info = c;
+               cpui->cpu_id = cpu;
+               cpui->cpu_pset = 0;
+               cpui->cpu_chip = c->phys_proc_id;
+               cpui->cpu_lgrp = 0;
+               cpui->cpu_info = c;
+
+               cpuc->cpuc_dtrace_flags = 0;
+               cpuc->cpuc_dcpc_intr_state = 0;
+               cpuc->cpuc_dtrace_illval = 0;
+               mutex_init(&cpuc->cpuc_pid_lock);
+               cpuc->cpu_dtrace_caller = 0;
+               rwlock_init(&cpuc->cpu_ft_lock);
        }
 }
index f58e669db409e8f9dd21241f06c99c0464e74dd0..c8279e31229d992dd43580d9ee03e4197ffcff1c 100644 (file)
@@ -24,6 +24,9 @@
 #include <asm/stacktrace.h>
 #include <asm/syscalls.h>
 
+#include <linux/uprobes.h>
+#include <asm/ptrace.h>
+
 /*---------------------------------------------------------------------------*\
 (* OS SPECIFIC DTRACE SETUP                                                  *)
 \*---------------------------------------------------------------------------*/
@@ -983,6 +986,8 @@ void (*dtrace_helpers_cleanup)(struct task_struct *);
 EXPORT_SYMBOL(dtrace_helpers_cleanup);
 void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *);
 EXPORT_SYMBOL(dtrace_fasttrap_probes_cleanup);
+void (*dtrace_tracepoint_hit)(fasttrap_machtp_t *, struct pt_regs *);
+EXPORT_SYMBOL(dtrace_tracepoint_hit);
 
 void dtrace_task_init(struct task_struct *tsk)
 {
@@ -1005,3 +1010,104 @@ void dtrace_task_cleanup(struct task_struct *tsk)
                        (*dtrace_fasttrap_probes_cleanup)(tsk);
        }
 }
+
+static int handler(struct uprobe_consumer *self, struct pt_regs *regs)
+{
+       pr_info("USDT-HANDLER: Called for PC %lx\n", GET_IP(regs));
+       read_lock(&this_cpu_core->cpu_ft_lock);
+       if (dtrace_tracepoint_hit == NULL)
+               pr_warn("Fasttrap probes, but no handler\n");
+       else
+               (*dtrace_tracepoint_hit)(self, regs);
+       read_unlock(&this_cpu_core->cpu_ft_lock);
+
+       return 0;
+}
+
+static struct uprobe_consumer  usdt_hndlr = { handler, };
+static int done = 0;
+
+int dtrace_tracepoint_enable(pid_t pid, uintptr_t addr,
+                            fasttrap_machtp_t *mtp)
+{
+       struct task_struct      *p;
+       struct inode            *ino;
+       struct vm_area_struct   *vma;
+       loff_t                  off;
+       int                     rc = 0;
+
+       p = find_task_by_vpid(pid);
+       if (!p) {
+               pr_warn("PID %d not found\n", pid);
+               return -ESRCH;
+       }
+
+       vma = p->mm->mmap;
+       if (vma->vm_file == NULL) {
+               pr_warn("DTRACE: vma->vm_file is NULL\n");
+               return -ESRCH;
+       }
+
+       ino = vma->vm_file->f_mapping->host;
+       off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start);
+pr_info("DEBUG: PID %d: vma 0x%p, mapping 0x%p, inode 0x%p, offset 0x%llx\n", pid, vma, vma->vm_file->f_mapping, ino, off);
+
+       if (((uintptr_t)ino & 0xffff880000000000ULL) == 0xffff880000000000ULL) {
+pr_info("DEBUG: Registering uprobe...\n");
+               mtp->handler = handler;
+               rc = uprobe_register(ino, off, mtp);
+
+               /*
+                * If successful, increment the count of the number of
+                * tracepoints active in the victim process.
+                */
+               if (rc == 0)
+                       p->dtrace_tp_count++;
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL(dtrace_tracepoint_enable);
+
+int dtrace_tracepoint_disable(pid_t pid, uintptr_t addr,
+                             fasttrap_machtp_t *mtp)
+{
+       struct task_struct      *p;
+       struct inode            *ino;
+       struct vm_area_struct   *vma;
+       loff_t                  off;
+
+       if (!mtp || !mtp->handler) {
+               pr_warn("DTRACE: No handler for tracepoint\n");
+               return -ENOENT;
+       }
+
+       p = find_task_by_vpid(pid);
+       if (!p) {
+               pr_warn("PID %d not found\n", pid);
+               return -ESRCH;
+       }
+
+       vma = p->mm->mmap;
+       if (vma->vm_file == NULL) {
+               pr_warn("DTRACE: vma->vm_file is NULL\n");
+               return -ESRCH;
+       }
+
+       ino = vma->vm_file->f_mapping->host;
+       off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start);
+pr_info("DEBUG: PID %d: vma 0x%p, mapping 0x%p, inode 0x%p, offset 0x%llx\n", pid, vma, vma->vm_file->f_mapping, ino, off);
+
+       if (((uintptr_t)ino & 0xffff880000000000ULL) == 0xffff880000000000ULL) {
+pr_info("DEBUG: Registering uprobe...\n");
+               uprobe_unregister(ino, off, mtp);
+               /*
+                * Decrement the count of the number of tracepoints active in
+                * the victim process.
+                */
+               p->dtrace_tp_count--;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(dtrace_tracepoint_disable);