diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-19 12:48:42 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-19 12:48:42 -0500 |
| commit | eca9dfcd0029c8a84b1094bb84a2fb53e4addf6c (patch) | |
| tree | 2e5982fef1e737ce5f8936981c7dc7fb50fc655c | |
| parent | 3981e152864fcc1dbbb564e1f4c0ae11a09639d2 (diff) | |
| parent | b5b60fda1e462a849bc37dfbace2888191be82cc (diff) | |
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
perf session: Make events_stats u64 to avoid overflow on 32-bit arches
hw-breakpoints: Fix hardware breakpoints -> perf events dependency
perf events: Dont report side-band events on each cpu for per-task-per-cpu events
perf events, x86/stacktrace: Fix performance/softlockup by providing a special frame pointer-only stack walker
perf events, x86/stacktrace: Make stack walking optional
perf events: Remove unused perf_counter.h header file
perf probe: Check new event name
kprobe-tracer: Check new event/group name
perf probe: Check whether debugfs path is correct
perf probe: Fix libdwarf include path for Debian
| -rw-r--r-- | arch/Kconfig | 4 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/stacktrace.h | 24 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/dumpstack.c | 33 | ||||
| -rw-r--r-- | arch/x86/kernel/dumpstack.h | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/dumpstack_32.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/dumpstack_64.c | 4 | ||||
| -rw-r--r-- | arch/x86/kernel/stacktrace.c | 18 | ||||
| -rw-r--r-- | arch/x86/oprofile/backtrace.c | 9 | ||||
| -rw-r--r-- | include/linux/perf_counter.h | 444 | ||||
| -rw-r--r-- | kernel/perf_event.c | 32 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 31 | ||||
| -rw-r--r-- | kernel/trace/trace_sysprof.c | 1 | ||||
| -rw-r--r-- | tools/perf/Makefile | 3 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 4 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 15 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.h | 59 |
20 files changed, 175 insertions, 523 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index d82875820a15..9d055b4f0585 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
| @@ -135,9 +135,7 @@ config HAVE_DEFAULT_NO_SPIN_MUTEXES | |||
| 135 | 135 | ||
| 136 | config HAVE_HW_BREAKPOINT | 136 | config HAVE_HW_BREAKPOINT |
| 137 | bool | 137 | bool |
| 138 | depends on HAVE_PERF_EVENTS | 138 | depends on PERF_EVENTS |
| 139 | select ANON_INODES | ||
| 140 | select PERF_EVENTS | ||
| 141 | 139 | ||
| 142 | config HAVE_USER_RETURN_NOTIFIER | 140 | config HAVE_USER_RETURN_NOTIFIER |
| 143 | bool | 141 | bool |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3b2a5aca4edb..55298e891571 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -50,6 +50,8 @@ config X86 | |||
| 50 | select HAVE_KERNEL_BZIP2 | 50 | select HAVE_KERNEL_BZIP2 |
| 51 | select HAVE_KERNEL_LZMA | 51 | select HAVE_KERNEL_LZMA |
| 52 | select HAVE_HW_BREAKPOINT | 52 | select HAVE_HW_BREAKPOINT |
| 53 | select PERF_EVENTS | ||
| 54 | select ANON_INODES | ||
| 53 | select HAVE_ARCH_KMEMCHECK | 55 | select HAVE_ARCH_KMEMCHECK |
| 54 | select HAVE_USER_RETURN_NOTIFIER | 56 | select HAVE_USER_RETURN_NOTIFIER |
| 55 | 57 | ||
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index cf86a5e73815..35e89122a42f 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h | |||
| @@ -5,6 +5,29 @@ extern int kstack_depth_to_print; | |||
| 5 | 5 | ||
| 6 | int x86_is_stack_id(int id, char *name); | 6 | int x86_is_stack_id(int id, char *name); |
| 7 | 7 | ||
| 8 | struct thread_info; | ||
| 9 | struct stacktrace_ops; | ||
| 10 | |||
| 11 | typedef unsigned long (*walk_stack_t)(struct thread_info *tinfo, | ||
| 12 | unsigned long *stack, | ||
| 13 | unsigned long bp, | ||
| 14 | const struct stacktrace_ops *ops, | ||
| 15 | void *data, | ||
| 16 | unsigned long *end, | ||
| 17 | int *graph); | ||
| 18 | |||
| 19 | extern unsigned long | ||
| 20 | print_context_stack(struct thread_info *tinfo, | ||
| 21 | unsigned long *stack, unsigned long bp, | ||
| 22 | const struct stacktrace_ops *ops, void *data, | ||
| 23 | unsigned long *end, int *graph); | ||
| 24 | |||
| 25 | extern unsigned long | ||
| 26 | print_context_stack_bp(struct thread_info *tinfo, | ||
| 27 | unsigned long *stack, unsigned long bp, | ||
| 28 | const struct stacktrace_ops *ops, void *data, | ||
| 29 | unsigned long *end, int *graph); | ||
| 30 | |||
| 8 | /* Generic stack tracer with callbacks */ | 31 | /* Generic stack tracer with callbacks */ |
| 9 | 32 | ||
| 10 | struct stacktrace_ops { | 33 | struct stacktrace_ops { |
| @@ -14,6 +37,7 @@ struct stacktrace_ops { | |||
| 14 | void (*address)(void *data, unsigned long address, int reliable); | 37 | void (*address)(void *data, unsigned long address, int reliable); |
| 15 | /* On negative return stop dumping */ | 38 | /* On negative return stop dumping */ |
| 16 | int (*stack)(void *data, char *name); | 39 | int (*stack)(void *data, char *name); |
| 40 | walk_stack_t walk_stack; | ||
| 17 | }; | 41 | }; |
| 18 | 42 | ||
| 19 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | 43 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 45506d5dd8df..c223b7e895d9 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
| @@ -2336,6 +2336,7 @@ static const struct stacktrace_ops backtrace_ops = { | |||
| 2336 | .warning_symbol = backtrace_warning_symbol, | 2336 | .warning_symbol = backtrace_warning_symbol, |
| 2337 | .stack = backtrace_stack, | 2337 | .stack = backtrace_stack, |
| 2338 | .address = backtrace_address, | 2338 | .address = backtrace_address, |
| 2339 | .walk_stack = print_context_stack_bp, | ||
| 2339 | }; | 2340 | }; |
| 2340 | 2341 | ||
| 2341 | #include "../dumpstack.h" | 2342 | #include "../dumpstack.h" |
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 0a0aa1cec8f1..c56bc2873030 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
| @@ -109,6 +109,30 @@ print_context_stack(struct thread_info *tinfo, | |||
| 109 | } | 109 | } |
| 110 | return bp; | 110 | return bp; |
| 111 | } | 111 | } |
| 112 | EXPORT_SYMBOL_GPL(print_context_stack); | ||
| 113 | |||
| 114 | unsigned long | ||
| 115 | print_context_stack_bp(struct thread_info *tinfo, | ||
| 116 | unsigned long *stack, unsigned long bp, | ||
| 117 | const struct stacktrace_ops *ops, void *data, | ||
| 118 | unsigned long *end, int *graph) | ||
| 119 | { | ||
| 120 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
| 121 | unsigned long *ret_addr = &frame->return_address; | ||
| 122 | |||
| 123 | while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) { | ||
| 124 | unsigned long addr = *ret_addr; | ||
| 125 | |||
| 126 | if (__kernel_text_address(addr)) { | ||
| 127 | ops->address(data, addr, 1); | ||
| 128 | frame = frame->next_frame; | ||
| 129 | ret_addr = &frame->return_address; | ||
| 130 | print_ftrace_graph_addr(addr, data, ops, tinfo, graph); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | return (unsigned long)frame; | ||
| 134 | } | ||
| 135 | EXPORT_SYMBOL_GPL(print_context_stack_bp); | ||
| 112 | 136 | ||
| 113 | 137 | ||
| 114 | static void | 138 | static void |
| @@ -141,10 +165,11 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) | |||
| 141 | } | 165 | } |
| 142 | 166 | ||
| 143 | static const struct stacktrace_ops print_trace_ops = { | 167 | static const struct stacktrace_ops print_trace_ops = { |
| 144 | .warning = print_trace_warning, | 168 | .warning = print_trace_warning, |
| 145 | .warning_symbol = print_trace_warning_symbol, | 169 | .warning_symbol = print_trace_warning_symbol, |
| 146 | .stack = print_trace_stack, | 170 | .stack = print_trace_stack, |
| 147 | .address = print_trace_address, | 171 | .address = print_trace_address, |
| 172 | .walk_stack = print_context_stack, | ||
| 148 | }; | 173 | }; |
| 149 | 174 | ||
| 150 | void | 175 | void |
diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h index 81086c227ab7..4fd1420faffa 100644 --- a/arch/x86/kernel/dumpstack.h +++ b/arch/x86/kernel/dumpstack.h | |||
| @@ -14,12 +14,6 @@ | |||
| 14 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) | 14 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) |
| 15 | #endif | 15 | #endif |
| 16 | 16 | ||
| 17 | extern unsigned long | ||
| 18 | print_context_stack(struct thread_info *tinfo, | ||
| 19 | unsigned long *stack, unsigned long bp, | ||
| 20 | const struct stacktrace_ops *ops, void *data, | ||
| 21 | unsigned long *end, int *graph); | ||
| 22 | |||
| 23 | extern void | 17 | extern void |
| 24 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 18 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
| 25 | unsigned long *stack, unsigned long bp, char *log_lvl); | 19 | unsigned long *stack, unsigned long bp, char *log_lvl); |
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index e0ed4c7abb62..ae775ca47b25 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c | |||
| @@ -58,7 +58,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
| 58 | 58 | ||
| 59 | context = (struct thread_info *) | 59 | context = (struct thread_info *) |
| 60 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | 60 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); |
| 61 | bp = print_context_stack(context, stack, bp, ops, data, NULL, &graph); | 61 | bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph); |
| 62 | 62 | ||
| 63 | stack = (unsigned long *)context->previous_esp; | 63 | stack = (unsigned long *)context->previous_esp; |
| 64 | if (!stack) | 64 | if (!stack) |
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index b13af53883aa..0ad9597073f5 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
| @@ -188,8 +188,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
| 188 | if (ops->stack(data, id) < 0) | 188 | if (ops->stack(data, id) < 0) |
| 189 | break; | 189 | break; |
| 190 | 190 | ||
| 191 | bp = print_context_stack(tinfo, stack, bp, ops, | 191 | bp = ops->walk_stack(tinfo, stack, bp, ops, |
| 192 | data, estack_end, &graph); | 192 | data, estack_end, &graph); |
| 193 | ops->stack(data, "<EOE>"); | 193 | ops->stack(data, "<EOE>"); |
| 194 | /* | 194 | /* |
| 195 | * We link to the next stack via the | 195 | * We link to the next stack via the |
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index c3eb207181fe..922eefbb3f6c 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
| @@ -53,17 +53,19 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable) | |||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static const struct stacktrace_ops save_stack_ops = { | 55 | static const struct stacktrace_ops save_stack_ops = { |
| 56 | .warning = save_stack_warning, | 56 | .warning = save_stack_warning, |
| 57 | .warning_symbol = save_stack_warning_symbol, | 57 | .warning_symbol = save_stack_warning_symbol, |
| 58 | .stack = save_stack_stack, | 58 | .stack = save_stack_stack, |
| 59 | .address = save_stack_address, | 59 | .address = save_stack_address, |
| 60 | .walk_stack = print_context_stack, | ||
| 60 | }; | 61 | }; |
| 61 | 62 | ||
| 62 | static const struct stacktrace_ops save_stack_ops_nosched = { | 63 | static const struct stacktrace_ops save_stack_ops_nosched = { |
| 63 | .warning = save_stack_warning, | 64 | .warning = save_stack_warning, |
| 64 | .warning_symbol = save_stack_warning_symbol, | 65 | .warning_symbol = save_stack_warning_symbol, |
| 65 | .stack = save_stack_stack, | 66 | .stack = save_stack_stack, |
| 66 | .address = save_stack_address_nosched, | 67 | .address = save_stack_address_nosched, |
| 68 | .walk_stack = print_context_stack, | ||
| 67 | }; | 69 | }; |
| 68 | 70 | ||
| 69 | /* | 71 | /* |
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index 044897be021f..3855096c59b8 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c | |||
| @@ -41,10 +41,11 @@ static void backtrace_address(void *data, unsigned long addr, int reliable) | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static struct stacktrace_ops backtrace_ops = { | 43 | static struct stacktrace_ops backtrace_ops = { |
| 44 | .warning = backtrace_warning, | 44 | .warning = backtrace_warning, |
| 45 | .warning_symbol = backtrace_warning_symbol, | 45 | .warning_symbol = backtrace_warning_symbol, |
| 46 | .stack = backtrace_stack, | 46 | .stack = backtrace_stack, |
| 47 | .address = backtrace_address, | 47 | .address = backtrace_address, |
| 48 | .walk_stack = print_context_stack, | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | struct frame_head { | 51 | struct frame_head { |
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h deleted file mode 100644 index e3fb25606706..000000000000 --- a/include/linux/perf_counter.h +++ /dev/null | |||
| @@ -1,444 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * NOTE: this file will be removed in a future kernel release, it is | ||
| 3 | * provided as a courtesy copy of user-space code that relies on the | ||
| 4 | * old (pre-rename) symbols and constants. | ||
| 5 | * | ||
| 6 | * Performance events: | ||
| 7 | * | ||
| 8 | * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de> | ||
| 9 | * Copyright (C) 2008-2009, Red Hat, Inc., Ingo Molnar | ||
| 10 | * Copyright (C) 2008-2009, Red Hat, Inc., Peter Zijlstra | ||
| 11 | * | ||
| 12 | * Data type definitions, declarations, prototypes. | ||
| 13 | * | ||
| 14 | * Started by: Thomas Gleixner and Ingo Molnar | ||
| 15 | * | ||
| 16 | * For licencing details see kernel-base/COPYING | ||
| 17 | */ | ||
| 18 | #ifndef _LINUX_PERF_COUNTER_H | ||
| 19 | #define _LINUX_PERF_COUNTER_H | ||
| 20 | |||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/ioctl.h> | ||
| 23 | #include <asm/byteorder.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * User-space ABI bits: | ||
| 27 | */ | ||
| 28 | |||
| 29 | /* | ||
| 30 | * attr.type | ||
| 31 | */ | ||
| 32 | enum perf_type_id { | ||
| 33 | PERF_TYPE_HARDWARE = 0, | ||
| 34 | PERF_TYPE_SOFTWARE = 1, | ||
| 35 | PERF_TYPE_TRACEPOINT = 2, | ||
| 36 | PERF_TYPE_HW_CACHE = 3, | ||
| 37 | PERF_TYPE_RAW = 4, | ||
| 38 | |||
| 39 | PERF_TYPE_MAX, /* non-ABI */ | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * Generalized performance counter event types, used by the | ||
| 44 | * attr.event_id parameter of the sys_perf_counter_open() | ||
| 45 | * syscall: | ||
| 46 | */ | ||
| 47 | enum perf_hw_id { | ||
| 48 | /* | ||
| 49 | * Common hardware events, generalized by the kernel: | ||
| 50 | */ | ||
| 51 | PERF_COUNT_HW_CPU_CYCLES = 0, | ||
| 52 | PERF_COUNT_HW_INSTRUCTIONS = 1, | ||
| 53 | PERF_COUNT_HW_CACHE_REFERENCES = 2, | ||
| 54 | PERF_COUNT_HW_CACHE_MISSES = 3, | ||
| 55 | PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, | ||
| 56 | PERF_COUNT_HW_BRANCH_MISSES = 5, | ||
| 57 | PERF_COUNT_HW_BUS_CYCLES = 6, | ||
| 58 | |||
| 59 | PERF_COUNT_HW_MAX, /* non-ABI */ | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Generalized hardware cache counters: | ||
| 64 | * | ||
| 65 | * { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x | ||
| 66 | * { read, write, prefetch } x | ||
| 67 | * { accesses, misses } | ||
| 68 | */ | ||
| 69 | enum perf_hw_cache_id { | ||
| 70 | PERF_COUNT_HW_CACHE_L1D = 0, | ||
| 71 | PERF_COUNT_HW_CACHE_L1I = 1, | ||
| 72 | PERF_COUNT_HW_CACHE_LL = 2, | ||
| 73 | PERF_COUNT_HW_CACHE_DTLB = 3, | ||
| 74 | PERF_COUNT_HW_CACHE_ITLB = 4, | ||
| 75 | PERF_COUNT_HW_CACHE_BPU = 5, | ||
| 76 | |||
| 77 | PERF_COUNT_HW_CACHE_MAX, /* non-ABI */ | ||
| 78 | }; | ||
| 79 | |||
| 80 | enum perf_hw_cache_op_id { | ||
| 81 | PERF_COUNT_HW_CACHE_OP_READ = 0, | ||
| 82 | PERF_COUNT_HW_CACHE_OP_WRITE = 1, | ||
| 83 | PERF_COUNT_HW_CACHE_OP_PREFETCH = 2, | ||
| 84 | |||
| 85 | PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */ | ||
| 86 | }; | ||
| 87 | |||
| 88 | enum perf_hw_cache_op_result_id { | ||
| 89 | PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0, | ||
| 90 | PERF_COUNT_HW_CACHE_RESULT_MISS = 1, | ||
| 91 | |||
| 92 | PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */ | ||
| 93 | }; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Special "software" counters provided by the kernel, even if the hardware | ||
| 97 | * does not support performance counters. These counters measure various | ||
| 98 | * physical and sw events of the kernel (and allow the profiling of them as | ||
| 99 | * well): | ||
| 100 | */ | ||
| 101 | enum perf_sw_ids { | ||
| 102 | PERF_COUNT_SW_CPU_CLOCK = 0, | ||
| 103 | PERF_COUNT_SW_TASK_CLOCK = 1, | ||
| 104 | PERF_COUNT_SW_PAGE_FAULTS = 2, | ||
| 105 | PERF_COUNT_SW_CONTEXT_SWITCHES = 3, | ||
| 106 | PERF_COUNT_SW_CPU_MIGRATIONS = 4, | ||
| 107 | PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, | ||
| 108 | PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, | ||
| 109 | PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, | ||
| 110 | PERF_COUNT_SW_EMULATION_FAULTS = 8, | ||
| 111 | |||
| 112 | PERF_COUNT_SW_MAX, /* non-ABI */ | ||
| 113 | }; | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Bits that can be set in attr.sample_type to request information | ||
| 117 | * in the overflow packets. | ||
| 118 | */ | ||
| 119 | enum perf_counter_sample_format { | ||
| 120 | PERF_SAMPLE_IP = 1U << 0, | ||
| 121 | PERF_SAMPLE_TID = 1U << 1, | ||
| 122 | PERF_SAMPLE_TIME = 1U << 2, | ||
| 123 | PERF_SAMPLE_ADDR = 1U << 3, | ||
| 124 | PERF_SAMPLE_READ = 1U << 4, | ||
| 125 | PERF_SAMPLE_CALLCHAIN = 1U << 5, | ||
| 126 | PERF_SAMPLE_ID = 1U << 6, | ||
| 127 | PERF_SAMPLE_CPU = 1U << 7, | ||
| 128 | PERF_SAMPLE_PERIOD = 1U << 8, | ||
| 129 | PERF_SAMPLE_STREAM_ID = 1U << 9, | ||
| 130 | PERF_SAMPLE_RAW = 1U << 10, | ||
| 131 | |||
| 132 | PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ | ||
| 133 | }; | ||
| 134 | |||
| 135 | /* | ||
| 136 | * The format of the data returned by read() on a perf counter fd, | ||
| 137 | * as specified by attr.read_format: | ||
| 138 | * | ||
| 139 | * struct read_format { | ||
| 140 | * { u64 value; | ||
| 141 | * { u64 time_enabled; } && PERF_FORMAT_ENABLED | ||
| 142 | * { u64 time_running; } && PERF_FORMAT_RUNNING | ||
| 143 | * { u64 id; } && PERF_FORMAT_ID | ||
| 144 | * } && !PERF_FORMAT_GROUP | ||
| 145 | * | ||
| 146 | * { u64 nr; | ||
| 147 | * { u64 time_enabled; } && PERF_FORMAT_ENABLED | ||
| 148 | * { u64 time_running; } && PERF_FORMAT_RUNNING | ||
| 149 | * { u64 value; | ||
| 150 | * { u64 id; } && PERF_FORMAT_ID | ||
| 151 | * } cntr[nr]; | ||
| 152 | * } && PERF_FORMAT_GROUP | ||
| 153 | * }; | ||
| 154 | */ | ||
| 155 | enum perf_counter_read_format { | ||
| 156 | PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0, | ||
| 157 | PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1, | ||
| 158 | PERF_FORMAT_ID = 1U << 2, | ||
| 159 | PERF_FORMAT_GROUP = 1U << 3, | ||
| 160 | |||
| 161 | PERF_FORMAT_MAX = 1U << 4, /* non-ABI */ | ||
| 162 | }; | ||
| 163 | |||
| 164 | #define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */ | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Hardware event to monitor via a performance monitoring counter: | ||
| 168 | */ | ||
| 169 | struct perf_counter_attr { | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Major type: hardware/software/tracepoint/etc. | ||
| 173 | */ | ||
| 174 | __u32 type; | ||
| 175 | |||
| 176 | /* | ||
| 177 | * Size of the attr structure, for fwd/bwd compat. | ||
| 178 | */ | ||
| 179 | __u32 size; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Type specific configuration information. | ||
| 183 | */ | ||
| 184 | __u64 config; | ||
| 185 | |||
| 186 | union { | ||
| 187 | __u64 sample_period; | ||
| 188 | __u64 sample_freq; | ||
| 189 | }; | ||
| 190 | |||
| 191 | __u64 sample_type; | ||
| 192 | __u64 read_format; | ||
| 193 | |||
| 194 | __u64 disabled : 1, /* off by default */ | ||
| 195 | inherit : 1, /* children inherit it */ | ||
| 196 | pinned : 1, /* must always be on PMU */ | ||
| 197 | exclusive : 1, /* only group on PMU */ | ||
| 198 | exclude_user : 1, /* don't count user */ | ||
| 199 | exclude_kernel : 1, /* ditto kernel */ | ||
| 200 | exclude_hv : 1, /* ditto hypervisor */ | ||
| 201 | exclude_idle : 1, /* don't count when idle */ | ||
| 202 | mmap : 1, /* include mmap data */ | ||
| 203 | comm : 1, /* include comm data */ | ||
| 204 | freq : 1, /* use freq, not period */ | ||
| 205 | inherit_stat : 1, /* per task counts */ | ||
| 206 | enable_on_exec : 1, /* next exec enables */ | ||
| 207 | task : 1, /* trace fork/exit */ | ||
| 208 | watermark : 1, /* wakeup_watermark */ | ||
| 209 | |||
| 210 | __reserved_1 : 49; | ||
| 211 | |||
| 212 | union { | ||
| 213 | __u32 wakeup_events; /* wakeup every n events */ | ||
| 214 | __u32 wakeup_watermark; /* bytes before wakeup */ | ||
| 215 | }; | ||
| 216 | __u32 __reserved_2; | ||
| 217 | |||
| 218 | __u64 __reserved_3; | ||
| 219 | }; | ||
| 220 | |||
| 221 | /* | ||
| 222 | * Ioctls that can be done on a perf counter fd: | ||
| 223 | */ | ||
| 224 | #define PERF_COUNTER_IOC_ENABLE _IO ('$', 0) | ||
| 225 | #define PERF_COUNTER_IOC_DISABLE _IO ('$', 1) | ||
| 226 | #define PERF_COUNTER_IOC_REFRESH _IO ('$', 2) | ||
| 227 | #define PERF_COUNTER_IOC_RESET _IO ('$', 3) | ||
| 228 | #define PERF_COUNTER_IOC_PERIOD _IOW('$', 4, u64) | ||
| 229 | #define PERF_COUNTER_IOC_SET_OUTPUT _IO ('$', 5) | ||
| 230 | #define PERF_COUNTER_IOC_SET_FILTER _IOW('$', 6, char *) | ||
| 231 | |||
| 232 | enum perf_counter_ioc_flags { | ||
| 233 | PERF_IOC_FLAG_GROUP = 1U << 0, | ||
| 234 | }; | ||
| 235 | |||
| 236 | /* | ||
| 237 | * Structure of the page that can be mapped via mmap | ||
| 238 | */ | ||
| 239 | struct perf_counter_mmap_page { | ||
| 240 | __u32 version; /* version number of this structure */ | ||
| 241 | __u32 compat_version; /* lowest version this is compat with */ | ||
| 242 | |||
| 243 | /* | ||
| 244 | * Bits needed to read the hw counters in user-space. | ||
| 245 | * | ||
| 246 | * u32 seq; | ||
| 247 | * s64 count; | ||
| 248 | * | ||
| 249 | * do { | ||
| 250 | * seq = pc->lock; | ||
| 251 | * | ||
| 252 | * barrier() | ||
| 253 | * if (pc->index) { | ||
| 254 | * count = pmc_read(pc->index - 1); | ||
| 255 | * count += pc->offset; | ||
| 256 | * } else | ||
| 257 | * goto regular_read; | ||
| 258 | * | ||
| 259 | * barrier(); | ||
| 260 | * } while (pc->lock != seq); | ||
| 261 | * | ||
| 262 | * NOTE: for obvious reason this only works on self-monitoring | ||
| 263 | * processes. | ||
| 264 | */ | ||
| 265 | __u32 lock; /* seqlock for synchronization */ | ||
| 266 | __u32 index; /* hardware counter identifier */ | ||
| 267 | __s64 offset; /* add to hardware counter value */ | ||
| 268 | __u64 time_enabled; /* time counter active */ | ||
| 269 | __u64 time_running; /* time counter on cpu */ | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Hole for extension of the self monitor capabilities | ||
| 273 | */ | ||
| 274 | |||
| 275 | __u64 __reserved[123]; /* align to 1k */ | ||
| 276 | |||
| 277 | /* | ||
| 278 | * Control data for the mmap() data buffer. | ||
| 279 | * | ||
| 280 | * User-space reading the @data_head value should issue an rmb(), on | ||
| 281 | * SMP capable platforms, after reading this value -- see | ||
| 282 | * perf_counter_wakeup(). | ||
| 283 | * | ||
| 284 | * When the mapping is PROT_WRITE the @data_tail value should be | ||
| 285 | * written by userspace to reflect the last read data. In this case | ||
| 286 | * the kernel will not over-write unread data. | ||
| 287 | */ | ||
| 288 | __u64 data_head; /* head in the data section */ | ||
| 289 | __u64 data_tail; /* user-space written tail */ | ||
| 290 | }; | ||
| 291 | |||
| 292 | #define PERF_EVENT_MISC_CPUMODE_MASK (3 << 0) | ||
| 293 | #define PERF_EVENT_MISC_CPUMODE_UNKNOWN (0 << 0) | ||
| 294 | #define PERF_EVENT_MISC_KERNEL (1 << 0) | ||
| 295 | #define PERF_EVENT_MISC_USER (2 << 0) | ||
| 296 | #define PERF_EVENT_MISC_HYPERVISOR (3 << 0) | ||
| 297 | |||
| 298 | struct perf_event_header { | ||
| 299 | __u32 type; | ||
| 300 | __u16 misc; | ||
| 301 | __u16 size; | ||
| 302 | }; | ||
| 303 | |||
| 304 | enum perf_event_type { | ||
| 305 | |||
| 306 | /* | ||
| 307 | * The MMAP events record the PROT_EXEC mappings so that we can | ||
| 308 | * correlate userspace IPs to code. They have the following structure: | ||
| 309 | * | ||
| 310 | * struct { | ||
| 311 | * struct perf_event_header header; | ||
| 312 | * | ||
| 313 | * u32 pid, tid; | ||
| 314 | * u64 addr; | ||
| 315 | * u64 len; | ||
| 316 | * u64 pgoff; | ||
| 317 | * char filename[]; | ||
| 318 | * }; | ||
| 319 | */ | ||
| 320 | PERF_EVENT_MMAP = 1, | ||
| 321 | |||
| 322 | /* | ||
| 323 | * struct { | ||
| 324 | * struct perf_event_header header; | ||
| 325 | * u64 id; | ||
| 326 | * u64 lost; | ||
| 327 | * }; | ||
| 328 | */ | ||
| 329 | PERF_EVENT_LOST = 2, | ||
| 330 | |||
| 331 | /* | ||
| 332 | * struct { | ||
| 333 | * struct perf_event_header header; | ||
| 334 | * | ||
| 335 | * u32 pid, tid; | ||
| 336 | * char comm[]; | ||
| 337 | * }; | ||
| 338 | */ | ||
| 339 | PERF_EVENT_COMM = 3, | ||
| 340 | |||
| 341 | /* | ||
| 342 | * struct { | ||
| 343 | * struct perf_event_header header; | ||
| 344 | * u32 pid, ppid; | ||
| 345 | * u32 tid, ptid; | ||
| 346 | * u64 time; | ||
| 347 | * }; | ||
| 348 | */ | ||
| 349 | PERF_EVENT_EXIT = 4, | ||
| 350 | |||
| 351 | /* | ||
| 352 | * struct { | ||
| 353 | * struct perf_event_header header; | ||
| 354 | * u64 time; | ||
| 355 | * u64 id; | ||
| 356 | * u64 stream_id; | ||
| 357 | * }; | ||
| 358 | */ | ||
| 359 | PERF_EVENT_THROTTLE = 5, | ||
| 360 | PERF_EVENT_UNTHROTTLE = 6, | ||
| 361 | |||
| 362 | /* | ||
| 363 | * struct { | ||
| 364 | * struct perf_event_header header; | ||
| 365 | * u32 pid, ppid; | ||
| 366 | * u32 tid, ptid; | ||
| 367 | * u64 time; | ||
| 368 | * }; | ||
| 369 | */ | ||
| 370 | PERF_EVENT_FORK = 7, | ||
| 371 | |||
| 372 | /* | ||
| 373 | * struct { | ||
| 374 | * struct perf_event_header header; | ||
| 375 | * u32 pid, tid; | ||
| 376 | * | ||
| 377 | * struct read_format values; | ||
| 378 | * }; | ||
| 379 | */ | ||
| 380 | PERF_EVENT_READ = 8, | ||
| 381 | |||
| 382 | /* | ||
| 383 | * struct { | ||
| 384 | * struct perf_event_header header; | ||
| 385 | * | ||
| 386 | * { u64 ip; } && PERF_SAMPLE_IP | ||
| 387 | * { u32 pid, tid; } && PERF_SAMPLE_TID | ||
| 388 | * { u64 time; } && PERF_SAMPLE_TIME | ||
| 389 | * { u64 addr; } && PERF_SAMPLE_ADDR | ||
| 390 | * { u64 id; } && PERF_SAMPLE_ID | ||
| 391 | * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID | ||
| 392 | * { u32 cpu, res; } && PERF_SAMPLE_CPU | ||
| 393 | * { u64 period; } && PERF_SAMPLE_PERIOD | ||
| 394 | * | ||
| 395 | * { struct read_format values; } && PERF_SAMPLE_READ | ||
| 396 | * | ||
| 397 | * { u64 nr, | ||
| 398 | * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN | ||
| 399 | * | ||
| 400 | * # | ||
| 401 | * # The RAW record below is opaque data wrt the ABI | ||
| 402 | * # | ||
| 403 | * # That is, the ABI doesn't make any promises wrt to | ||
| 404 | * # the stability of its content, it may vary depending | ||
| 405 | * # on event, hardware, kernel version and phase of | ||
| 406 | * # the moon. | ||
| 407 | * # | ||
| 408 | * # In other words, PERF_SAMPLE_RAW contents are not an ABI. | ||
| 409 | * # | ||
| 410 | * | ||
| 411 | * { u32 size; | ||
| 412 | * char data[size];}&& PERF_SAMPLE_RAW | ||
| 413 | * }; | ||
| 414 | */ | ||
| 415 | PERF_EVENT_SAMPLE = 9, | ||
| 416 | |||
| 417 | PERF_EVENT_MAX, /* non-ABI */ | ||
| 418 | }; | ||
| 419 | |||
| 420 | enum perf_callchain_context { | ||
| 421 | PERF_CONTEXT_HV = (__u64)-32, | ||
| 422 | PERF_CONTEXT_KERNEL = (__u64)-128, | ||
| 423 | PERF_CONTEXT_USER = (__u64)-512, | ||
| 424 | |||
| 425 | PERF_CONTEXT_GUEST = (__u64)-2048, | ||
| 426 | PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176, | ||
| 427 | PERF_CONTEXT_GUEST_USER = (__u64)-2560, | ||
| 428 | |||
| 429 | PERF_CONTEXT_MAX = (__u64)-4095, | ||
| 430 | }; | ||
| 431 | |||
| 432 | #define PERF_FLAG_FD_NO_GROUP (1U << 0) | ||
| 433 | #define PERF_FLAG_FD_OUTPUT (1U << 1) | ||
| 434 | |||
| 435 | /* | ||
| 436 | * In case some app still references the old symbols: | ||
| 437 | */ | ||
| 438 | |||
| 439 | #define __NR_perf_counter_open __NR_perf_event_open | ||
| 440 | |||
| 441 | #define PR_TASK_PERF_COUNTERS_DISABLE PR_TASK_PERF_EVENTS_DISABLE | ||
| 442 | #define PR_TASK_PERF_COUNTERS_ENABLE PR_TASK_PERF_EVENTS_ENABLE | ||
| 443 | |||
| 444 | #endif /* _LINUX_PERF_COUNTER_H */ | ||
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 97d1a3dd7a59..e0eb4a2fe183 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -1381,6 +1381,9 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx) | |||
| 1381 | if (event->state != PERF_EVENT_STATE_ACTIVE) | 1381 | if (event->state != PERF_EVENT_STATE_ACTIVE) |
| 1382 | continue; | 1382 | continue; |
| 1383 | 1383 | ||
| 1384 | if (event->cpu != -1 && event->cpu != smp_processor_id()) | ||
| 1385 | continue; | ||
| 1386 | |||
| 1384 | hwc = &event->hw; | 1387 | hwc = &event->hw; |
| 1385 | 1388 | ||
| 1386 | interrupts = hwc->interrupts; | 1389 | interrupts = hwc->interrupts; |
| @@ -3265,6 +3268,9 @@ static void perf_event_task_output(struct perf_event *event, | |||
| 3265 | 3268 | ||
| 3266 | static int perf_event_task_match(struct perf_event *event) | 3269 | static int perf_event_task_match(struct perf_event *event) |
| 3267 | { | 3270 | { |
| 3271 | if (event->cpu != -1 && event->cpu != smp_processor_id()) | ||
| 3272 | return 0; | ||
| 3273 | |||
| 3268 | if (event->attr.comm || event->attr.mmap || event->attr.task) | 3274 | if (event->attr.comm || event->attr.mmap || event->attr.task) |
| 3269 | return 1; | 3275 | return 1; |
| 3270 | 3276 | ||
| @@ -3290,12 +3296,11 @@ static void perf_event_task_event(struct perf_task_event *task_event) | |||
| 3290 | rcu_read_lock(); | 3296 | rcu_read_lock(); |
| 3291 | cpuctx = &get_cpu_var(perf_cpu_context); | 3297 | cpuctx = &get_cpu_var(perf_cpu_context); |
| 3292 | perf_event_task_ctx(&cpuctx->ctx, task_event); | 3298 | perf_event_task_ctx(&cpuctx->ctx, task_event); |
| 3293 | put_cpu_var(perf_cpu_context); | ||
| 3294 | |||
| 3295 | if (!ctx) | 3299 | if (!ctx) |
| 3296 | ctx = rcu_dereference(task_event->task->perf_event_ctxp); | 3300 | ctx = rcu_dereference(task_event->task->perf_event_ctxp); |
| 3297 | if (ctx) | 3301 | if (ctx) |
| 3298 | perf_event_task_ctx(ctx, task_event); | 3302 | perf_event_task_ctx(ctx, task_event); |
| 3303 | put_cpu_var(perf_cpu_context); | ||
| 3299 | rcu_read_unlock(); | 3304 | rcu_read_unlock(); |
| 3300 | } | 3305 | } |
| 3301 | 3306 | ||
| @@ -3372,6 +3377,9 @@ static void perf_event_comm_output(struct perf_event *event, | |||
| 3372 | 3377 | ||
| 3373 | static int perf_event_comm_match(struct perf_event *event) | 3378 | static int perf_event_comm_match(struct perf_event *event) |
| 3374 | { | 3379 | { |
| 3380 | if (event->cpu != -1 && event->cpu != smp_processor_id()) | ||
| 3381 | return 0; | ||
| 3382 | |||
| 3375 | if (event->attr.comm) | 3383 | if (event->attr.comm) |
| 3376 | return 1; | 3384 | return 1; |
| 3377 | 3385 | ||
| @@ -3408,15 +3416,10 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) | |||
| 3408 | rcu_read_lock(); | 3416 | rcu_read_lock(); |
| 3409 | cpuctx = &get_cpu_var(perf_cpu_context); | 3417 | cpuctx = &get_cpu_var(perf_cpu_context); |
| 3410 | perf_event_comm_ctx(&cpuctx->ctx, comm_event); | 3418 | perf_event_comm_ctx(&cpuctx->ctx, comm_event); |
| 3411 | put_cpu_var(perf_cpu_context); | ||
| 3412 | |||
| 3413 | /* | ||
| 3414 | * doesn't really matter which of the child contexts the | ||
| 3415 | * events ends up in. | ||
| 3416 | */ | ||
| 3417 | ctx = rcu_dereference(current->perf_event_ctxp); | 3419 | ctx = rcu_dereference(current->perf_event_ctxp); |
| 3418 | if (ctx) | 3420 | if (ctx) |
| 3419 | perf_event_comm_ctx(ctx, comm_event); | 3421 | perf_event_comm_ctx(ctx, comm_event); |
| 3422 | put_cpu_var(perf_cpu_context); | ||
| 3420 | rcu_read_unlock(); | 3423 | rcu_read_unlock(); |
| 3421 | } | 3424 | } |
| 3422 | 3425 | ||
| @@ -3491,6 +3494,9 @@ static void perf_event_mmap_output(struct perf_event *event, | |||
| 3491 | static int perf_event_mmap_match(struct perf_event *event, | 3494 | static int perf_event_mmap_match(struct perf_event *event, |
| 3492 | struct perf_mmap_event *mmap_event) | 3495 | struct perf_mmap_event *mmap_event) |
| 3493 | { | 3496 | { |
| 3497 | if (event->cpu != -1 && event->cpu != smp_processor_id()) | ||
| 3498 | return 0; | ||
| 3499 | |||
| 3494 | if (event->attr.mmap) | 3500 | if (event->attr.mmap) |
| 3495 | return 1; | 3501 | return 1; |
| 3496 | 3502 | ||
| @@ -3564,15 +3570,10 @@ got_name: | |||
| 3564 | rcu_read_lock(); | 3570 | rcu_read_lock(); |
| 3565 | cpuctx = &get_cpu_var(perf_cpu_context); | 3571 | cpuctx = &get_cpu_var(perf_cpu_context); |
| 3566 | perf_event_mmap_ctx(&cpuctx->ctx, mmap_event); | 3572 | perf_event_mmap_ctx(&cpuctx->ctx, mmap_event); |
| 3567 | put_cpu_var(perf_cpu_context); | ||
| 3568 | |||
| 3569 | /* | ||
| 3570 | * doesn't really matter which of the child contexts the | ||
| 3571 | * events ends up in. | ||
| 3572 | */ | ||
| 3573 | ctx = rcu_dereference(current->perf_event_ctxp); | 3573 | ctx = rcu_dereference(current->perf_event_ctxp); |
| 3574 | if (ctx) | 3574 | if (ctx) |
| 3575 | perf_event_mmap_ctx(ctx, mmap_event); | 3575 | perf_event_mmap_ctx(ctx, mmap_event); |
| 3576 | put_cpu_var(perf_cpu_context); | ||
| 3576 | rcu_read_unlock(); | 3577 | rcu_read_unlock(); |
| 3577 | 3578 | ||
| 3578 | kfree(buf); | 3579 | kfree(buf); |
| @@ -3863,6 +3864,9 @@ static int perf_swevent_match(struct perf_event *event, | |||
| 3863 | struct perf_sample_data *data, | 3864 | struct perf_sample_data *data, |
| 3864 | struct pt_regs *regs) | 3865 | struct pt_regs *regs) |
| 3865 | { | 3866 | { |
| 3867 | if (event->cpu != -1 && event->cpu != smp_processor_id()) | ||
| 3868 | return 0; | ||
| 3869 | |||
| 3866 | if (!perf_swevent_is_counting(event)) | 3870 | if (!perf_swevent_is_counting(event)) |
| 3867 | return 0; | 3871 | return 0; |
| 3868 | 3872 | ||
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 7ecab06547a5..375f81a568dc 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -282,6 +282,18 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); | |||
| 282 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, | 282 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, |
| 283 | struct pt_regs *regs); | 283 | struct pt_regs *regs); |
| 284 | 284 | ||
| 285 | /* Check the name is good for event/group */ | ||
| 286 | static int check_event_name(const char *name) | ||
| 287 | { | ||
| 288 | if (!isalpha(*name) && *name != '_') | ||
| 289 | return 0; | ||
| 290 | while (*++name != '\0') { | ||
| 291 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | return 1; | ||
| 295 | } | ||
| 296 | |||
| 285 | /* | 297 | /* |
| 286 | * Allocate new trace_probe and initialize it (including kprobes). | 298 | * Allocate new trace_probe and initialize it (including kprobes). |
| 287 | */ | 299 | */ |
| @@ -293,10 +305,11 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
| 293 | int nargs, int is_return) | 305 | int nargs, int is_return) |
| 294 | { | 306 | { |
| 295 | struct trace_probe *tp; | 307 | struct trace_probe *tp; |
| 308 | int ret = -ENOMEM; | ||
| 296 | 309 | ||
| 297 | tp = kzalloc(SIZEOF_TRACE_PROBE(nargs), GFP_KERNEL); | 310 | tp = kzalloc(SIZEOF_TRACE_PROBE(nargs), GFP_KERNEL); |
| 298 | if (!tp) | 311 | if (!tp) |
| 299 | return ERR_PTR(-ENOMEM); | 312 | return ERR_PTR(ret); |
| 300 | 313 | ||
| 301 | if (symbol) { | 314 | if (symbol) { |
| 302 | tp->symbol = kstrdup(symbol, GFP_KERNEL); | 315 | tp->symbol = kstrdup(symbol, GFP_KERNEL); |
| @@ -312,14 +325,20 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
| 312 | else | 325 | else |
| 313 | tp->rp.kp.pre_handler = kprobe_dispatcher; | 326 | tp->rp.kp.pre_handler = kprobe_dispatcher; |
| 314 | 327 | ||
| 315 | if (!event) | 328 | if (!event || !check_event_name(event)) { |
| 329 | ret = -EINVAL; | ||
| 316 | goto error; | 330 | goto error; |
| 331 | } | ||
| 332 | |||
| 317 | tp->call.name = kstrdup(event, GFP_KERNEL); | 333 | tp->call.name = kstrdup(event, GFP_KERNEL); |
| 318 | if (!tp->call.name) | 334 | if (!tp->call.name) |
| 319 | goto error; | 335 | goto error; |
| 320 | 336 | ||
| 321 | if (!group) | 337 | if (!group || !check_event_name(group)) { |
| 338 | ret = -EINVAL; | ||
| 322 | goto error; | 339 | goto error; |
| 340 | } | ||
| 341 | |||
| 323 | tp->call.system = kstrdup(group, GFP_KERNEL); | 342 | tp->call.system = kstrdup(group, GFP_KERNEL); |
| 324 | if (!tp->call.system) | 343 | if (!tp->call.system) |
| 325 | goto error; | 344 | goto error; |
| @@ -330,7 +349,7 @@ error: | |||
| 330 | kfree(tp->call.name); | 349 | kfree(tp->call.name); |
| 331 | kfree(tp->symbol); | 350 | kfree(tp->symbol); |
| 332 | kfree(tp); | 351 | kfree(tp); |
| 333 | return ERR_PTR(-ENOMEM); | 352 | return ERR_PTR(ret); |
| 334 | } | 353 | } |
| 335 | 354 | ||
| 336 | static void free_probe_arg(struct probe_arg *arg) | 355 | static void free_probe_arg(struct probe_arg *arg) |
| @@ -695,10 +714,10 @@ static int create_trace_probe(int argc, char **argv) | |||
| 695 | if (!event) { | 714 | if (!event) { |
| 696 | /* Make a new event name */ | 715 | /* Make a new event name */ |
| 697 | if (symbol) | 716 | if (symbol) |
| 698 | snprintf(buf, MAX_EVENT_NAME_LEN, "%c@%s%+ld", | 717 | snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_%ld", |
| 699 | is_return ? 'r' : 'p', symbol, offset); | 718 | is_return ? 'r' : 'p', symbol, offset); |
| 700 | else | 719 | else |
| 701 | snprintf(buf, MAX_EVENT_NAME_LEN, "%c@0x%p", | 720 | snprintf(buf, MAX_EVENT_NAME_LEN, "%c_0x%p", |
| 702 | is_return ? 'r' : 'p', addr); | 721 | is_return ? 'r' : 'p', addr); |
| 703 | event = buf; | 722 | event = buf; |
| 704 | } | 723 | } |
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index f6693969287d..a7974a552ca9 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c | |||
| @@ -93,6 +93,7 @@ static const struct stacktrace_ops backtrace_ops = { | |||
| 93 | .warning_symbol = backtrace_warning_symbol, | 93 | .warning_symbol = backtrace_warning_symbol, |
| 94 | .stack = backtrace_stack, | 94 | .stack = backtrace_stack, |
| 95 | .address = backtrace_address, | 95 | .address = backtrace_address, |
| 96 | .walk_stack = print_context_stack, | ||
| 96 | }; | 97 | }; |
| 97 | 98 | ||
| 98 | static int | 99 | static int |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 7814dbbd401d..4390d225686d 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -487,10 +487,11 @@ else | |||
| 487 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); | 487 | msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); |
| 488 | endif | 488 | endif |
| 489 | 489 | ||
| 490 | ifneq ($(shell sh -c "(echo '\#include <libdwarf/dwarf.h>'; echo '\#include <libdwarf/libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | 490 | ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o /dev/null $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) |
| 491 | msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); | 491 | msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); |
| 492 | BASIC_CFLAGS += -DNO_LIBDWARF | 492 | BASIC_CFLAGS += -DNO_LIBDWARF |
| 493 | else | 493 | else |
| 494 | BASIC_CFLAGS += -I/usr/include/libdwarf | ||
| 494 | EXTLIBS += -lelf -ldwarf | 495 | EXTLIBS += -lelf -ldwarf |
| 495 | LIB_OBJS += util/probe-finder.o | 496 | LIB_OBJS += util/probe-finder.o |
| 496 | endif | 497 | endif |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 7e741f54d798..c1e6774fd3ed 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include "util/strlist.h" | 38 | #include "util/strlist.h" |
| 39 | #include "util/event.h" | 39 | #include "util/event.h" |
| 40 | #include "util/debug.h" | 40 | #include "util/debug.h" |
| 41 | #include "util/debugfs.h" | ||
| 41 | #include "util/symbol.h" | 42 | #include "util/symbol.h" |
| 42 | #include "util/thread.h" | 43 | #include "util/thread.h" |
| 43 | #include "util/session.h" | 44 | #include "util/session.h" |
| @@ -205,6 +206,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
| 205 | if ((!session.nr_probe && !session.dellist && !session.list_events)) | 206 | if ((!session.nr_probe && !session.dellist && !session.list_events)) |
| 206 | usage_with_options(probe_usage, options); | 207 | usage_with_options(probe_usage, options); |
| 207 | 208 | ||
| 209 | if (debugfs_valid_mountpoint(debugfs_path) < 0) | ||
| 210 | die("Failed to find debugfs path."); | ||
| 211 | |||
| 208 | if (session.list_events) { | 212 | if (session.list_events) { |
| 209 | if (session.nr_probe != 0 || session.dellist) { | 213 | if (session.nr_probe != 0 || session.dellist) { |
| 210 | pr_warning(" Error: Don't use --list with" | 214 | pr_warning(" Error: Don't use --list with" |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index e50a6b10ee6f..5c2ab5357ec6 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -224,7 +224,7 @@ static int __cmd_report(void) | |||
| 224 | 224 | ||
| 225 | perf_session__collapse_resort(session); | 225 | perf_session__collapse_resort(session); |
| 226 | perf_session__output_resort(session, session->events_stats.total); | 226 | perf_session__output_resort(session, session->events_stats.total); |
| 227 | fprintf(stdout, "# Samples: %ld\n#\n", session->events_stats.total); | 227 | fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); |
| 228 | perf_session__fprintf_hists(session, NULL, false, stdout); | 228 | perf_session__fprintf_hists(session, NULL, false, stdout); |
| 229 | if (sort_order == default_sort_order && | 229 | if (sort_order == default_sort_order && |
| 230 | parent_pattern == default_parent_pattern) | 230 | parent_pattern == default_parent_pattern) |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 8027309b0422..690a96d0467c 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -95,8 +95,8 @@ typedef union event_union { | |||
| 95 | } event_t; | 95 | } event_t; |
| 96 | 96 | ||
| 97 | struct events_stats { | 97 | struct events_stats { |
| 98 | unsigned long total; | 98 | u64 total; |
| 99 | unsigned long lost; | 99 | u64 lost; |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | void event__print_totals(void); | 102 | void event__print_totals(void); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2ca62154f79b..29465d440043 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -62,6 +62,18 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
| 62 | return ret; | 62 | return ret; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | /* Check the name is good for event/group */ | ||
| 66 | static bool check_event_name(const char *name) | ||
| 67 | { | ||
| 68 | if (!isalpha(*name) && *name != '_') | ||
| 69 | return false; | ||
| 70 | while (*++name != '\0') { | ||
| 71 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | return true; | ||
| 75 | } | ||
| 76 | |||
| 65 | /* Parse probepoint definition. */ | 77 | /* Parse probepoint definition. */ |
| 66 | static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | 78 | static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) |
| 67 | { | 79 | { |
| @@ -82,6 +94,9 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | |||
| 82 | ptr = strchr(arg, ':'); | 94 | ptr = strchr(arg, ':'); |
| 83 | if (ptr) /* Group name is not supported yet. */ | 95 | if (ptr) /* Group name is not supported yet. */ |
| 84 | semantic_error("Group name is not supported yet."); | 96 | semantic_error("Group name is not supported yet."); |
| 97 | if (!check_event_name(arg)) | ||
| 98 | semantic_error("%s is bad for event name -it must " | ||
| 99 | "follow C symbol-naming rule.", arg); | ||
| 85 | pp->event = strdup(arg); | 100 | pp->event = strdup(arg); |
| 86 | arg = tmp; | 101 | arg = tmp; |
| 87 | } | 102 | } |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 5e4050ce2963..a4086aaddb73 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | #ifndef _PROBE_FINDER_H | 1 | #ifndef _PROBE_FINDER_H |
| 2 | #define _PROBE_FINDER_H | 2 | #define _PROBE_FINDER_H |
| 3 | 3 | ||
| 4 | #define MAX_PATH_LEN 256 | 4 | #define MAX_PATH_LEN 256 |
| 5 | #define MAX_PROBE_BUFFER 1024 | 5 | #define MAX_PROBE_BUFFER 1024 |
| 6 | #define MAX_PROBES 128 | 6 | #define MAX_PROBES 128 |
| 7 | 7 | ||
| 8 | static inline int is_c_varname(const char *name) | 8 | static inline int is_c_varname(const char *name) |
| 9 | { | 9 | { |
| @@ -12,48 +12,53 @@ static inline int is_c_varname(const char *name) | |||
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | struct probe_point { | 14 | struct probe_point { |
| 15 | char *event; /* Event name */ | 15 | char *event; /* Event name */ |
| 16 | char *group; /* Event group */ | 16 | char *group; /* Event group */ |
| 17 | 17 | ||
| 18 | /* Inputs */ | 18 | /* Inputs */ |
| 19 | char *file; /* File name */ | 19 | char *file; /* File name */ |
| 20 | int line; /* Line number */ | 20 | int line; /* Line number */ |
| 21 | 21 | ||
| 22 | char *function; /* Function name */ | 22 | char *function; /* Function name */ |
| 23 | int offset; /* Offset bytes */ | 23 | int offset; /* Offset bytes */ |
| 24 | 24 | ||
| 25 | int nr_args; /* Number of arguments */ | 25 | int nr_args; /* Number of arguments */ |
| 26 | char **args; /* Arguments */ | 26 | char **args; /* Arguments */ |
| 27 | 27 | ||
| 28 | int retprobe; /* Return probe */ | 28 | int retprobe; /* Return probe */ |
| 29 | 29 | ||
| 30 | /* Output */ | 30 | /* Output */ |
| 31 | int found; /* Number of found probe points */ | 31 | int found; /* Number of found probe points */ |
| 32 | char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ | 32 | char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | #ifndef NO_LIBDWARF | 35 | #ifndef NO_LIBDWARF |
| 36 | extern int find_probepoint(int fd, struct probe_point *pp); | 36 | extern int find_probepoint(int fd, struct probe_point *pp); |
| 37 | 37 | ||
| 38 | #include <libdwarf/dwarf.h> | 38 | /* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ |
| 39 | #include <libdwarf/libdwarf.h> | 39 | #ifndef _MIPS_SZLONG |
| 40 | # define _MIPS_SZLONG 0 | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #include <dwarf.h> | ||
| 44 | #include <libdwarf.h> | ||
| 40 | 45 | ||
| 41 | struct probe_finder { | 46 | struct probe_finder { |
| 42 | struct probe_point *pp; /* Target probe point */ | 47 | struct probe_point *pp; /* Target probe point */ |
| 43 | 48 | ||
| 44 | /* For function searching */ | 49 | /* For function searching */ |
| 45 | Dwarf_Addr addr; /* Address */ | 50 | Dwarf_Addr addr; /* Address */ |
| 46 | Dwarf_Unsigned fno; /* File number */ | 51 | Dwarf_Unsigned fno; /* File number */ |
| 47 | Dwarf_Unsigned lno; /* Line number */ | 52 | Dwarf_Unsigned lno; /* Line number */ |
| 48 | Dwarf_Off inl_offs; /* Inline offset */ | 53 | Dwarf_Off inl_offs; /* Inline offset */ |
| 49 | Dwarf_Die cu_die; /* Current CU */ | 54 | Dwarf_Die cu_die; /* Current CU */ |
| 50 | 55 | ||
| 51 | /* For variable searching */ | 56 | /* For variable searching */ |
| 52 | Dwarf_Addr cu_base; /* Current CU base address */ | 57 | Dwarf_Addr cu_base; /* Current CU base address */ |
| 53 | Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ | 58 | Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ |
| 54 | const char *var; /* Current variable name */ | 59 | const char *var; /* Current variable name */ |
| 55 | char *buf; /* Current output buffer */ | 60 | char *buf; /* Current output buffer */ |
| 56 | int len; /* Length of output buffer */ | 61 | int len; /* Length of output buffer */ |
| 57 | }; | 62 | }; |
| 58 | #endif /* NO_LIBDWARF */ | 63 | #endif /* NO_LIBDWARF */ |
| 59 | 64 | ||
