From: Kris Van Hees Date: Mon, 20 May 2013 20:37:33 +0000 (-0400) Subject: dtrace: USDT implementation (phase 2) X-Git-Tag: v4.1.12-92~313^2~82 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=b761e6f9ddbbc2cc8677e63ccf546287ffc0c9c5;p=users%2Fjedix%2Flinux-maple.git dtrace: USDT implementation (phase 2) 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 --- diff --git a/include/linux/dtrace_cpu.h b/include/linux/dtrace_cpu.h index 1508de06b567..02d5cf90bbd4 100644 --- a/include/linux/dtrace_cpu.h +++ b/include/linux/dtrace_cpu.h @@ -5,6 +5,7 @@ #include #include +#include #include 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); diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h index 969d79fc3919..b7a6bb4f8558 100644 --- a/include/linux/dtrace_os.h +++ b/include/linux/dtrace_os.h @@ -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 index 75b2f52eb522..000000000000 --- a/include/linux/fasttrap.h +++ /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_ */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 9ca7eae1a855..0e598086f599 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -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; diff --git a/kernel/dtrace/dtrace_cpu.c b/kernel/dtrace/dtrace_cpu.c index 632b92f5faa0..572c580fca72 100644 --- a/kernel/dtrace/dtrace_cpu.c +++ b/kernel/dtrace/dtrace_cpu.c @@ -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); } } diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c index f58e669db409..c8279e31229d 100644 --- a/kernel/dtrace/dtrace_os.c +++ b/kernel/dtrace/dtrace_os.c @@ -24,6 +24,9 @@ #include #include +#include +#include + /*---------------------------------------------------------------------------*\ (* 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);