]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: USDT implementation (Phase 1)
authorKris Van Hees <kris.van.hees@oracle.com>
Wed, 23 Jan 2013 09:53:14 +0000 (04:53 -0500)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:41:41 +0000 (22:41 +0100)
This rather large patch provides the implementation for USDT support at the
DTrace kernel core level, and the fasttrap provider level.  It ensures that
executables can register their embedded providers (with USDT probes), that
the probes are visible to the dtrace userspace utility, and that probes are
properly removed upon executable completion, execve() invocation, or any
unexpected executable termination.

The following parts are provided by this patch:
- meta-provider support (dtrace_ptofapi)
- helper ioctl interface (dtrace_dev)
- DIF validation for helper objects (dtrace_dif)
- DOF processing for helpers for provider and probe definitions (dtrace_dof)
- fasttrap meta-provider for USDT only (fasttrap*)

The dtrace_helper.c file was removed because this code belongs in dtrace_dof.c
instead.

Minimal changes were made to the core kernel in exec.c, sched.h, exit.c, and
fork.c to add support for process-specific helpers (and those encapsulate
providers and probes).

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
fs/exec.c
include/linux/dtrace_ioctl.h
include/linux/dtrace_os.h
include/linux/fasttrap.h [new file with mode: 0644]
include/linux/sched.h
kernel/dtrace/dtrace_os.c
kernel/exit.c
kernel/fork.c

index 36f4f76763c14168dfba7ec86285cda0e66f90d8..98144eb184fdfec9289adfa8a26d364f661e81c0 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -57,6 +57,7 @@
 #include <linux/oom.h>
 #include <linux/compat.h>
 #include <linux/sdt.h>
+#include <linux/dtrace_os.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1589,6 +1590,8 @@ static int do_execveat_common(int fd, struct filename *filename,
 
        /* execve succeeded */
 #ifdef CONFIG_DTRACE
+       dtrace_task_cleanup(current);   /* get rid of probes from old ... */
+       dtrace_task_init(current);      /* ... be ready for probes from new */
        current->dtrace_psinfo = dtrace_psinfo_alloc(current);
 #endif
        current->fs->in_exec = 0;
index 3e343ff60118e7883e336976f30a6eb9749fa891..7bec9b6fe7a2dbd5b84f8cd3b4e3106be9c80720 100644 (file)
@@ -25,7 +25,7 @@
 #define DTRACEIOC_REPLICATE    _IOR(DTRACEIOC, 18, void *)
 
 #define DTRACEHIOC             0xd8
-#define DTRACEHIOC_ADD         _IOW(DTRACEHIOC, 1, int)
+#define DTRACEHIOC_ADD         _IOW(DTRACEHIOC, 1, dof_hdr_t)
 #define DTRACEHIOC_REMOVE      _IOW(DTRACEHIOC, 2, int)
 #define DTRACEHIOC_ADDDOF      _IOW(DTRACEHIOC, 3, dof_helper_t)
 
index 4a828489770ba6fe697808b8ba415551d4931cd9..da541b304b2684e5640318c74e3938eaa03d30e5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011, 2012, 2013 Oracle Corporation */
+/* Copyright (C) 2011, 2012, 2013 Oracle, Inc. */
 
 #ifndef _DTRACE_OS_H_
 #define _DTRACE_OS_H_
@@ -72,4 +72,12 @@ typedef struct stacktrace_state {
 
 extern void dtrace_stacktrace(stacktrace_state_t *);
 
+extern struct task_struct *register_pid_provider(pid_t);
+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);
+
+extern void (*dtrace_helpers_cleanup)(struct task_struct *);
+extern void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *);
+
 #endif /* _DTRACE_OS_H_ */
diff --git a/include/linux/fasttrap.h b/include/linux/fasttrap.h
new file mode 100644 (file)
index 0000000..75b2f52
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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 2b89630bbfc4932f8cab71c986ec24e2a5b07ee1..9ca7eae1a85535176a72d3636f33683a17287171 100644 (file)
@@ -1724,6 +1724,7 @@ struct task_struct {
        dtrace_psinfo_t *dtrace_psinfo;
 
        void *dtrace_helpers;
+       uint32_t dtrace_probes;
 #endif
 #ifdef CONFIG_UPROBES
        struct uprobe_task *utask;
index f55bfd0a024e3806a9358becab70e343b61274b5..ce13292d57fdceb7cc167a417a577cea1a95039f 100644 (file)
@@ -910,3 +910,99 @@ long dtrace_rt_sigreturn(struct pt_regs *regs)
 
        return rc;
 }
+
+/*---------------------------------------------------------------------------*\
+(* USER SPACE TRACING (FASTTRAP) SUPPORT                                     *)
+\*---------------------------------------------------------------------------*/
+struct task_struct *register_pid_provider(pid_t pid)
+{
+       struct task_struct      *p;
+
+       /*
+        * Make sure the process exists, (FIXME: isn't a child created as the
+        * result of a vfork(2)), and isn't a zombie (but may be in fork).
+        */
+       rcu_read_lock();
+       read_lock(&tasklist_lock);
+       if ((p = find_task_by_vpid(pid)) == NULL) {
+               read_unlock(&tasklist_lock);
+               rcu_read_unlock();
+               return NULL;
+       }
+
+       get_task_struct(p);
+       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
+
+       if (p->state & TASK_DEAD ||
+           p->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)) {
+               put_task_struct(p);
+               return NULL;
+       }
+
+       /*
+        * Increment dtrace_probes so that the process knows to inform us
+        * when it exits or execs. fasttrap_provider_free() decrements this
+        * when we're done with this provider.
+        */
+       p->dtrace_probes++;
+       put_task_struct(p);
+
+       return p;
+}
+EXPORT_SYMBOL(register_pid_provider);
+
+void unregister_pid_provider(pid_t pid)
+{
+       struct task_struct      *p;
+
+       /*
+        * Decrement dtrace_probes on the process whose provider we're
+        * freeing. We don't have to worry about clobbering somone else's
+        * modifications to it because we have locked the bucket that
+        * corresponds to this process's hash chain in the provider hash
+        * table. Don't sweat it if we can't find the process.
+        */
+       rcu_read_lock();
+       read_lock(&tasklist_lock);
+       if ((p = find_task_by_vpid(pid)) == NULL) {
+               read_unlock(&tasklist_lock);
+               rcu_read_unlock();
+               return;
+       }
+
+       get_task_struct(p);
+       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
+
+       p->dtrace_probes--;
+       put_task_struct(p);
+}
+EXPORT_SYMBOL(unregister_pid_provider);
+
+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_task_init(struct task_struct *tsk)
+{
+       tsk->dtrace_helpers = NULL;
+       tsk->dtrace_probes = 0;
+}
+
+void dtrace_task_cleanup(struct task_struct *tsk)
+{
+       if (likely(dtrace_helpers_cleanup == NULL))
+               return;
+
+       if (tsk->dtrace_helpers != NULL)
+               (*dtrace_helpers_cleanup)(tsk);
+
+       if (tsk->dtrace_probes) {
+               if (dtrace_fasttrap_probes_cleanup == NULL)
+                       pr_warn("Fasttrap probes, yet no cleanup routine\n");
+               else
+                       (*dtrace_fasttrap_probes_cleanup)(tsk);
+       }
+}
index 7125b5184bcc6242bbef6100a7e1df56e73baade..7ff3c4aed9c6fc86487d3185ee751377fcedbe45 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/writeback.h>
 #include <linux/shm.h>
 #include <linux/sdt.h>
+#include <linux/dtrace_os.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -734,6 +735,10 @@ void do_exit(long code)
        DTRACE_PROC(lwp__exit);
        DTRACE_PROC1(exit, int, code & 0x80 ? 3 : code & 0x7f ? 2 : 1);
 
+#ifdef CONFIG_DTRACE
+       dtrace_task_cleanup(tsk);
+#endif
+
        exit_mm(tsk);
 
        if (group_dead)
index dfd447cf0def47254775c32f8e41104703b48344..328f8828b7837b9ae3f5f5230c56e1a4c309733f 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/compiler.h>
 #include <linux/sysctl.h>
 #include <linux/sdt.h>
+#include <linux/dtrace_os.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -384,6 +385,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
 
 #ifdef CONFIG_DTRACE
        tsk->dtrace_psinfo = NULL;
+       dtrace_task_init(tsk);
 #endif
 
        return tsk;