diff options
-rw-r--r-- | arch/x86/include/asm/kdebug.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/stacktrace.h | 33 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 12 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_32.c | 25 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_64.c | 24 | ||||
-rw-r--r-- | arch/x86/kernel/process.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/stacktrace.c | 8 | ||||
-rw-r--r-- | arch/x86/mm/kmemcheck/error.c | 2 | ||||
-rw-r--r-- | arch/x86/oprofile/backtrace.c | 2 | ||||
-rw-r--r-- | include/linux/ftrace_event.h | 10 | ||||
-rw-r--r-- | include/linux/stacktrace.h | 4 | ||||
-rw-r--r-- | include/linux/syscalls.h | 10 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 4 | ||||
-rw-r--r-- | include/trace/events/syscalls.h | 4 | ||||
-rw-r--r-- | include/trace/ftrace.h | 7 | ||||
-rw-r--r-- | kernel/perf_event.c | 9 | ||||
-rw-r--r-- | kernel/trace/trace_event_perf.c | 31 |
18 files changed, 121 insertions, 71 deletions
diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h index 5bdfca86581b..f23eb2528464 100644 --- a/arch/x86/include/asm/kdebug.h +++ b/arch/x86/include/asm/kdebug.h | |||
@@ -28,7 +28,7 @@ extern void die(const char *, struct pt_regs *,long); | |||
28 | extern int __must_check __die(const char *, struct pt_regs *, long); | 28 | extern int __must_check __die(const char *, struct pt_regs *, long); |
29 | extern void show_registers(struct pt_regs *regs); | 29 | extern void show_registers(struct pt_regs *regs); |
30 | extern void show_trace(struct task_struct *t, struct pt_regs *regs, | 30 | extern void show_trace(struct task_struct *t, struct pt_regs *regs, |
31 | unsigned long *sp, unsigned long bp); | 31 | unsigned long *sp); |
32 | extern void __show_regs(struct pt_regs *regs, int all); | 32 | extern void __show_regs(struct pt_regs *regs, int all); |
33 | extern void show_regs(struct pt_regs *regs); | 33 | extern void show_regs(struct pt_regs *regs); |
34 | extern unsigned long oops_begin(void); | 34 | extern unsigned long oops_begin(void); |
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h index 2b16a2ad23dc..52b5c7ed3608 100644 --- a/arch/x86/include/asm/stacktrace.h +++ b/arch/x86/include/asm/stacktrace.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #define _ASM_X86_STACKTRACE_H | 7 | #define _ASM_X86_STACKTRACE_H |
8 | 8 | ||
9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
10 | #include <linux/ptrace.h> | ||
10 | 11 | ||
11 | extern int kstack_depth_to_print; | 12 | extern int kstack_depth_to_print; |
12 | 13 | ||
@@ -46,7 +47,7 @@ struct stacktrace_ops { | |||
46 | }; | 47 | }; |
47 | 48 | ||
48 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | 49 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, |
49 | unsigned long *stack, unsigned long bp, | 50 | unsigned long *stack, |
50 | const struct stacktrace_ops *ops, void *data); | 51 | const struct stacktrace_ops *ops, void *data); |
51 | 52 | ||
52 | #ifdef CONFIG_X86_32 | 53 | #ifdef CONFIG_X86_32 |
@@ -57,13 +58,39 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | |||
57 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) | 58 | #define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :) |
58 | #endif | 59 | #endif |
59 | 60 | ||
61 | #ifdef CONFIG_FRAME_POINTER | ||
62 | static inline unsigned long | ||
63 | stack_frame(struct task_struct *task, struct pt_regs *regs) | ||
64 | { | ||
65 | unsigned long bp; | ||
66 | |||
67 | if (regs) | ||
68 | return regs->bp; | ||
69 | |||
70 | if (task == current) { | ||
71 | /* Grab bp right from our regs */ | ||
72 | get_bp(bp); | ||
73 | return bp; | ||
74 | } | ||
75 | |||
76 | /* bp is the last reg pushed by switch_to */ | ||
77 | return *(unsigned long *)task->thread.sp; | ||
78 | } | ||
79 | #else | ||
80 | static inline unsigned long | ||
81 | stack_frame(struct task_struct *task, struct pt_regs *regs) | ||
82 | { | ||
83 | return 0; | ||
84 | } | ||
85 | #endif | ||
86 | |||
60 | extern void | 87 | extern void |
61 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 88 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
62 | unsigned long *stack, unsigned long bp, char *log_lvl); | 89 | unsigned long *stack, char *log_lvl); |
63 | 90 | ||
64 | extern void | 91 | extern void |
65 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 92 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
66 | unsigned long *sp, unsigned long bp, char *log_lvl); | 93 | unsigned long *sp, char *log_lvl); |
67 | 94 | ||
68 | extern unsigned int code_bytes; | 95 | extern unsigned int code_bytes; |
69 | 96 | ||
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 1f129a14e3a2..5273c7b90b8b 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -1657,7 +1657,7 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) | |||
1657 | 1657 | ||
1658 | perf_callchain_store(entry, regs->ip); | 1658 | perf_callchain_store(entry, regs->ip); |
1659 | 1659 | ||
1660 | dump_trace(NULL, regs, NULL, regs->bp, &backtrace_ops, entry); | 1660 | dump_trace(NULL, regs, NULL, &backtrace_ops, entry); |
1661 | } | 1661 | } |
1662 | 1662 | ||
1663 | #ifdef CONFIG_COMPAT | 1663 | #ifdef CONFIG_COMPAT |
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 6e8752c1bd52..8474c998cbd4 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -175,21 +175,21 @@ static const struct stacktrace_ops print_trace_ops = { | |||
175 | 175 | ||
176 | void | 176 | void |
177 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 177 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
178 | unsigned long *stack, unsigned long bp, char *log_lvl) | 178 | unsigned long *stack, char *log_lvl) |
179 | { | 179 | { |
180 | printk("%sCall Trace:\n", log_lvl); | 180 | printk("%sCall Trace:\n", log_lvl); |
181 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | 181 | dump_trace(task, regs, stack, &print_trace_ops, log_lvl); |
182 | } | 182 | } |
183 | 183 | ||
184 | void show_trace(struct task_struct *task, struct pt_regs *regs, | 184 | void show_trace(struct task_struct *task, struct pt_regs *regs, |
185 | unsigned long *stack, unsigned long bp) | 185 | unsigned long *stack) |
186 | { | 186 | { |
187 | show_trace_log_lvl(task, regs, stack, bp, ""); | 187 | show_trace_log_lvl(task, regs, stack, ""); |
188 | } | 188 | } |
189 | 189 | ||
190 | void show_stack(struct task_struct *task, unsigned long *sp) | 190 | void show_stack(struct task_struct *task, unsigned long *sp) |
191 | { | 191 | { |
192 | show_stack_log_lvl(task, NULL, sp, 0, ""); | 192 | show_stack_log_lvl(task, NULL, sp, ""); |
193 | } | 193 | } |
194 | 194 | ||
195 | /* | 195 | /* |
@@ -210,7 +210,7 @@ void dump_stack(void) | |||
210 | init_utsname()->release, | 210 | init_utsname()->release, |
211 | (int)strcspn(init_utsname()->version, " "), | 211 | (int)strcspn(init_utsname()->version, " "), |
212 | init_utsname()->version); | 212 | init_utsname()->version); |
213 | show_trace(NULL, NULL, &stack, bp); | 213 | show_trace(NULL, NULL, &stack); |
214 | } | 214 | } |
215 | EXPORT_SYMBOL(dump_stack); | 215 | EXPORT_SYMBOL(dump_stack); |
216 | 216 | ||
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index 1bc7f75a5bda..74cc1eda384b 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c | |||
@@ -17,11 +17,12 @@ | |||
17 | #include <asm/stacktrace.h> | 17 | #include <asm/stacktrace.h> |
18 | 18 | ||
19 | 19 | ||
20 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 20 | void dump_trace(struct task_struct *task, |
21 | unsigned long *stack, unsigned long bp, | 21 | struct pt_regs *regs, unsigned long *stack, |
22 | const struct stacktrace_ops *ops, void *data) | 22 | const struct stacktrace_ops *ops, void *data) |
23 | { | 23 | { |
24 | int graph = 0; | 24 | int graph = 0; |
25 | unsigned long bp; | ||
25 | 26 | ||
26 | if (!task) | 27 | if (!task) |
27 | task = current; | 28 | task = current; |
@@ -34,18 +35,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
34 | stack = (unsigned long *)task->thread.sp; | 35 | stack = (unsigned long *)task->thread.sp; |
35 | } | 36 | } |
36 | 37 | ||
37 | #ifdef CONFIG_FRAME_POINTER | 38 | bp = stack_frame(task, regs); |
38 | if (!bp) { | ||
39 | if (task == current) { | ||
40 | /* Grab bp right from our regs */ | ||
41 | get_bp(bp); | ||
42 | } else { | ||
43 | /* bp is the last reg pushed by switch_to */ | ||
44 | bp = *(unsigned long *) task->thread.sp; | ||
45 | } | ||
46 | } | ||
47 | #endif | ||
48 | |||
49 | for (;;) { | 39 | for (;;) { |
50 | struct thread_info *context; | 40 | struct thread_info *context; |
51 | 41 | ||
@@ -65,7 +55,7 @@ EXPORT_SYMBOL(dump_trace); | |||
65 | 55 | ||
66 | void | 56 | void |
67 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 57 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
68 | unsigned long *sp, unsigned long bp, char *log_lvl) | 58 | unsigned long *sp, char *log_lvl) |
69 | { | 59 | { |
70 | unsigned long *stack; | 60 | unsigned long *stack; |
71 | int i; | 61 | int i; |
@@ -87,7 +77,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
87 | touch_nmi_watchdog(); | 77 | touch_nmi_watchdog(); |
88 | } | 78 | } |
89 | printk(KERN_CONT "\n"); | 79 | printk(KERN_CONT "\n"); |
90 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | 80 | show_trace_log_lvl(task, regs, sp, log_lvl); |
91 | } | 81 | } |
92 | 82 | ||
93 | 83 | ||
@@ -112,8 +102,7 @@ void show_registers(struct pt_regs *regs) | |||
112 | u8 *ip; | 102 | u8 *ip; |
113 | 103 | ||
114 | printk(KERN_EMERG "Stack:\n"); | 104 | printk(KERN_EMERG "Stack:\n"); |
115 | show_stack_log_lvl(NULL, regs, ®s->sp, | 105 | show_stack_log_lvl(NULL, regs, ®s->sp, KERN_EMERG); |
116 | 0, KERN_EMERG); | ||
117 | 106 | ||
118 | printk(KERN_EMERG "Code: "); | 107 | printk(KERN_EMERG "Code: "); |
119 | 108 | ||
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 6a340485249a..64101335de19 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -139,8 +139,8 @@ fixup_bp_irq_link(unsigned long bp, unsigned long *stack, | |||
139 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 139 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
140 | */ | 140 | */ |
141 | 141 | ||
142 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 142 | void dump_trace(struct task_struct *task, |
143 | unsigned long *stack, unsigned long bp, | 143 | struct pt_regs *regs, unsigned long *stack, |
144 | const struct stacktrace_ops *ops, void *data) | 144 | const struct stacktrace_ops *ops, void *data) |
145 | { | 145 | { |
146 | const unsigned cpu = get_cpu(); | 146 | const unsigned cpu = get_cpu(); |
@@ -149,6 +149,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
149 | unsigned used = 0; | 149 | unsigned used = 0; |
150 | struct thread_info *tinfo; | 150 | struct thread_info *tinfo; |
151 | int graph = 0; | 151 | int graph = 0; |
152 | unsigned long bp; | ||
152 | 153 | ||
153 | if (!task) | 154 | if (!task) |
154 | task = current; | 155 | task = current; |
@@ -160,18 +161,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
160 | stack = (unsigned long *)task->thread.sp; | 161 | stack = (unsigned long *)task->thread.sp; |
161 | } | 162 | } |
162 | 163 | ||
163 | #ifdef CONFIG_FRAME_POINTER | 164 | bp = stack_frame(task, regs); |
164 | if (!bp) { | ||
165 | if (task == current) { | ||
166 | /* Grab bp right from our regs */ | ||
167 | get_bp(bp); | ||
168 | } else { | ||
169 | /* bp is the last reg pushed by switch_to */ | ||
170 | bp = *(unsigned long *) task->thread.sp; | ||
171 | } | ||
172 | } | ||
173 | #endif | ||
174 | |||
175 | /* | 165 | /* |
176 | * Print function call entries in all stacks, starting at the | 166 | * Print function call entries in all stacks, starting at the |
177 | * current stack address. If the stacks consist of nested | 167 | * current stack address. If the stacks consist of nested |
@@ -235,7 +225,7 @@ EXPORT_SYMBOL(dump_trace); | |||
235 | 225 | ||
236 | void | 226 | void |
237 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 227 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
238 | unsigned long *sp, unsigned long bp, char *log_lvl) | 228 | unsigned long *sp, char *log_lvl) |
239 | { | 229 | { |
240 | unsigned long *irq_stack_end; | 230 | unsigned long *irq_stack_end; |
241 | unsigned long *irq_stack; | 231 | unsigned long *irq_stack; |
@@ -279,7 +269,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
279 | preempt_enable(); | 269 | preempt_enable(); |
280 | 270 | ||
281 | printk(KERN_CONT "\n"); | 271 | printk(KERN_CONT "\n"); |
282 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | 272 | show_trace_log_lvl(task, regs, sp, log_lvl); |
283 | } | 273 | } |
284 | 274 | ||
285 | void show_registers(struct pt_regs *regs) | 275 | void show_registers(struct pt_regs *regs) |
@@ -308,7 +298,7 @@ void show_registers(struct pt_regs *regs) | |||
308 | 298 | ||
309 | printk(KERN_EMERG "Stack:\n"); | 299 | printk(KERN_EMERG "Stack:\n"); |
310 | show_stack_log_lvl(NULL, regs, (unsigned long *)sp, | 300 | show_stack_log_lvl(NULL, regs, (unsigned long *)sp, |
311 | regs->bp, KERN_EMERG); | 301 | KERN_EMERG); |
312 | 302 | ||
313 | printk(KERN_EMERG "Code: "); | 303 | printk(KERN_EMERG "Code: "); |
314 | 304 | ||
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 57d1868a86aa..96ed1aac543a 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -91,8 +91,7 @@ void exit_thread(void) | |||
91 | void show_regs(struct pt_regs *regs) | 91 | void show_regs(struct pt_regs *regs) |
92 | { | 92 | { |
93 | show_registers(regs); | 93 | show_registers(regs); |
94 | show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), | 94 | show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs)); |
95 | regs->bp); | ||
96 | } | 95 | } |
97 | 96 | ||
98 | void show_regs_common(void) | 97 | void show_regs_common(void) |
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c index b53c525368a7..938c8e10a19a 100644 --- a/arch/x86/kernel/stacktrace.c +++ b/arch/x86/kernel/stacktrace.c | |||
@@ -73,22 +73,22 @@ static const struct stacktrace_ops save_stack_ops_nosched = { | |||
73 | */ | 73 | */ |
74 | void save_stack_trace(struct stack_trace *trace) | 74 | void save_stack_trace(struct stack_trace *trace) |
75 | { | 75 | { |
76 | dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace); | 76 | dump_trace(current, NULL, NULL, &save_stack_ops, trace); |
77 | if (trace->nr_entries < trace->max_entries) | 77 | if (trace->nr_entries < trace->max_entries) |
78 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 78 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
79 | } | 79 | } |
80 | EXPORT_SYMBOL_GPL(save_stack_trace); | 80 | EXPORT_SYMBOL_GPL(save_stack_trace); |
81 | 81 | ||
82 | void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp) | 82 | void save_stack_trace_regs(struct stack_trace *trace, struct pt_regs *regs) |
83 | { | 83 | { |
84 | dump_trace(current, NULL, NULL, bp, &save_stack_ops, trace); | 84 | dump_trace(current, regs, NULL, &save_stack_ops, trace); |
85 | if (trace->nr_entries < trace->max_entries) | 85 | if (trace->nr_entries < trace->max_entries) |
86 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 86 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
87 | } | 87 | } |
88 | 88 | ||
89 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 89 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
90 | { | 90 | { |
91 | dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace); | 91 | dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace); |
92 | if (trace->nr_entries < trace->max_entries) | 92 | if (trace->nr_entries < trace->max_entries) |
93 | trace->entries[trace->nr_entries++] = ULONG_MAX; | 93 | trace->entries[trace->nr_entries++] = ULONG_MAX; |
94 | } | 94 | } |
diff --git a/arch/x86/mm/kmemcheck/error.c b/arch/x86/mm/kmemcheck/error.c index af3b6c8a436f..704a37cedddb 100644 --- a/arch/x86/mm/kmemcheck/error.c +++ b/arch/x86/mm/kmemcheck/error.c | |||
@@ -185,7 +185,7 @@ void kmemcheck_error_save(enum kmemcheck_shadow state, | |||
185 | e->trace.entries = e->trace_entries; | 185 | e->trace.entries = e->trace_entries; |
186 | e->trace.max_entries = ARRAY_SIZE(e->trace_entries); | 186 | e->trace.max_entries = ARRAY_SIZE(e->trace_entries); |
187 | e->trace.skip = 0; | 187 | e->trace.skip = 0; |
188 | save_stack_trace_bp(&e->trace, regs->bp); | 188 | save_stack_trace_regs(&e->trace, regs); |
189 | 189 | ||
190 | /* Round address down to nearest 16 bytes */ | 190 | /* Round address down to nearest 16 bytes */ |
191 | shadow_copy = kmemcheck_shadow_lookup(address | 191 | shadow_copy = kmemcheck_shadow_lookup(address |
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c index 2d49d4e19a36..72cbec14d783 100644 --- a/arch/x86/oprofile/backtrace.c +++ b/arch/x86/oprofile/backtrace.c | |||
@@ -126,7 +126,7 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth) | |||
126 | if (!user_mode_vm(regs)) { | 126 | if (!user_mode_vm(regs)) { |
127 | unsigned long stack = kernel_stack_pointer(regs); | 127 | unsigned long stack = kernel_stack_pointer(regs); |
128 | if (depth) | 128 | if (depth) |
129 | dump_trace(NULL, regs, (unsigned long *)stack, 0, | 129 | dump_trace(NULL, regs, (unsigned long *)stack, |
130 | &backtrace_ops, &depth); | 130 | &backtrace_ops, &depth); |
131 | return; | 131 | return; |
132 | } | 132 | } |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 8beabb958f61..725bf6bd39f7 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -154,12 +154,14 @@ enum { | |||
154 | TRACE_EVENT_FL_ENABLED_BIT, | 154 | TRACE_EVENT_FL_ENABLED_BIT, |
155 | TRACE_EVENT_FL_FILTERED_BIT, | 155 | TRACE_EVENT_FL_FILTERED_BIT, |
156 | TRACE_EVENT_FL_RECORDED_CMD_BIT, | 156 | TRACE_EVENT_FL_RECORDED_CMD_BIT, |
157 | TRACE_EVENT_FL_CAP_ANY_BIT, | ||
157 | }; | 158 | }; |
158 | 159 | ||
159 | enum { | 160 | enum { |
160 | TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT), | 161 | TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT), |
161 | TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT), | 162 | TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT), |
162 | TRACE_EVENT_FL_RECORDED_CMD = (1 << TRACE_EVENT_FL_RECORDED_CMD_BIT), | 163 | TRACE_EVENT_FL_RECORDED_CMD = (1 << TRACE_EVENT_FL_RECORDED_CMD_BIT), |
164 | TRACE_EVENT_FL_CAP_ANY = (1 << TRACE_EVENT_FL_CAP_ANY_BIT), | ||
163 | }; | 165 | }; |
164 | 166 | ||
165 | struct ftrace_event_call { | 167 | struct ftrace_event_call { |
@@ -196,6 +198,14 @@ struct ftrace_event_call { | |||
196 | #endif | 198 | #endif |
197 | }; | 199 | }; |
198 | 200 | ||
201 | #define __TRACE_EVENT_FLAGS(name, value) \ | ||
202 | static int __init trace_init_flags_##name(void) \ | ||
203 | { \ | ||
204 | event_##name.flags = value; \ | ||
205 | return 0; \ | ||
206 | } \ | ||
207 | early_initcall(trace_init_flags_##name); | ||
208 | |||
199 | #define PERF_MAX_TRACE_SIZE 2048 | 209 | #define PERF_MAX_TRACE_SIZE 2048 |
200 | 210 | ||
201 | #define MAX_FILTER_PRED 32 | 211 | #define MAX_FILTER_PRED 32 |
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h index 51efbef38fb0..25310f1d7f37 100644 --- a/include/linux/stacktrace.h +++ b/include/linux/stacktrace.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __LINUX_STACKTRACE_H | 2 | #define __LINUX_STACKTRACE_H |
3 | 3 | ||
4 | struct task_struct; | 4 | struct task_struct; |
5 | struct pt_regs; | ||
5 | 6 | ||
6 | #ifdef CONFIG_STACKTRACE | 7 | #ifdef CONFIG_STACKTRACE |
7 | struct task_struct; | 8 | struct task_struct; |
@@ -13,7 +14,8 @@ struct stack_trace { | |||
13 | }; | 14 | }; |
14 | 15 | ||
15 | extern void save_stack_trace(struct stack_trace *trace); | 16 | extern void save_stack_trace(struct stack_trace *trace); |
16 | extern void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp); | 17 | extern void save_stack_trace_regs(struct stack_trace *trace, |
18 | struct pt_regs *regs); | ||
17 | extern void save_stack_trace_tsk(struct task_struct *tsk, | 19 | extern void save_stack_trace_tsk(struct task_struct *tsk, |
18 | struct stack_trace *trace); | 20 | struct stack_trace *trace); |
19 | 21 | ||
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index cacc27a0e285..18cd0684fc4e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -127,8 +127,6 @@ extern struct trace_event_functions exit_syscall_print_funcs; | |||
127 | #define SYSCALL_TRACE_ENTER_EVENT(sname) \ | 127 | #define SYSCALL_TRACE_ENTER_EVENT(sname) \ |
128 | static struct syscall_metadata \ | 128 | static struct syscall_metadata \ |
129 | __attribute__((__aligned__(4))) __syscall_meta_##sname; \ | 129 | __attribute__((__aligned__(4))) __syscall_meta_##sname; \ |
130 | static struct ftrace_event_call \ | ||
131 | __attribute__((__aligned__(4))) event_enter_##sname; \ | ||
132 | static struct ftrace_event_call __used \ | 130 | static struct ftrace_event_call __used \ |
133 | __attribute__((__aligned__(4))) \ | 131 | __attribute__((__aligned__(4))) \ |
134 | __attribute__((section("_ftrace_events"))) \ | 132 | __attribute__((section("_ftrace_events"))) \ |
@@ -137,13 +135,12 @@ extern struct trace_event_functions exit_syscall_print_funcs; | |||
137 | .class = &event_class_syscall_enter, \ | 135 | .class = &event_class_syscall_enter, \ |
138 | .event.funcs = &enter_syscall_print_funcs, \ | 136 | .event.funcs = &enter_syscall_print_funcs, \ |
139 | .data = (void *)&__syscall_meta_##sname,\ | 137 | .data = (void *)&__syscall_meta_##sname,\ |
140 | } | 138 | }; \ |
139 | __TRACE_EVENT_FLAGS(enter_##sname, TRACE_EVENT_FL_CAP_ANY) | ||
141 | 140 | ||
142 | #define SYSCALL_TRACE_EXIT_EVENT(sname) \ | 141 | #define SYSCALL_TRACE_EXIT_EVENT(sname) \ |
143 | static struct syscall_metadata \ | 142 | static struct syscall_metadata \ |
144 | __attribute__((__aligned__(4))) __syscall_meta_##sname; \ | 143 | __attribute__((__aligned__(4))) __syscall_meta_##sname; \ |
145 | static struct ftrace_event_call \ | ||
146 | __attribute__((__aligned__(4))) event_exit_##sname; \ | ||
147 | static struct ftrace_event_call __used \ | 144 | static struct ftrace_event_call __used \ |
148 | __attribute__((__aligned__(4))) \ | 145 | __attribute__((__aligned__(4))) \ |
149 | __attribute__((section("_ftrace_events"))) \ | 146 | __attribute__((section("_ftrace_events"))) \ |
@@ -152,7 +149,8 @@ extern struct trace_event_functions exit_syscall_print_funcs; | |||
152 | .class = &event_class_syscall_exit, \ | 149 | .class = &event_class_syscall_exit, \ |
153 | .event.funcs = &exit_syscall_print_funcs, \ | 150 | .event.funcs = &exit_syscall_print_funcs, \ |
154 | .data = (void *)&__syscall_meta_##sname,\ | 151 | .data = (void *)&__syscall_meta_##sname,\ |
155 | } | 152 | }; \ |
153 | __TRACE_EVENT_FLAGS(exit_##sname, TRACE_EVENT_FL_CAP_ANY) | ||
156 | 154 | ||
157 | #define SYSCALL_METADATA(sname, nb) \ | 155 | #define SYSCALL_METADATA(sname, nb) \ |
158 | SYSCALL_TRACE_ENTER_EVENT(sname); \ | 156 | SYSCALL_TRACE_ENTER_EVENT(sname); \ |
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index a4a90b6726ce..5a6074fcd81d 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -234,6 +234,8 @@ do_trace: \ | |||
234 | PARAMS(void *__data, proto), \ | 234 | PARAMS(void *__data, proto), \ |
235 | PARAMS(__data, args)) | 235 | PARAMS(__data, args)) |
236 | 236 | ||
237 | #define TRACE_EVENT_FLAGS(event, flag) | ||
238 | |||
237 | #endif /* DECLARE_TRACE */ | 239 | #endif /* DECLARE_TRACE */ |
238 | 240 | ||
239 | #ifndef TRACE_EVENT | 241 | #ifndef TRACE_EVENT |
@@ -354,4 +356,6 @@ do_trace: \ | |||
354 | assign, print, reg, unreg) \ | 356 | assign, print, reg, unreg) \ |
355 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) | 357 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) |
356 | 358 | ||
359 | #define TRACE_EVENT_FLAGS(event, flag) | ||
360 | |||
357 | #endif /* ifdef TRACE_EVENT (see note above) */ | 361 | #endif /* ifdef TRACE_EVENT (see note above) */ |
diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h index fb726ac7caee..5a4c04a75b3d 100644 --- a/include/trace/events/syscalls.h +++ b/include/trace/events/syscalls.h | |||
@@ -40,6 +40,8 @@ TRACE_EVENT_FN(sys_enter, | |||
40 | syscall_regfunc, syscall_unregfunc | 40 | syscall_regfunc, syscall_unregfunc |
41 | ); | 41 | ); |
42 | 42 | ||
43 | TRACE_EVENT_FLAGS(sys_enter, TRACE_EVENT_FL_CAP_ANY) | ||
44 | |||
43 | TRACE_EVENT_FN(sys_exit, | 45 | TRACE_EVENT_FN(sys_exit, |
44 | 46 | ||
45 | TP_PROTO(struct pt_regs *regs, long ret), | 47 | TP_PROTO(struct pt_regs *regs, long ret), |
@@ -62,6 +64,8 @@ TRACE_EVENT_FN(sys_exit, | |||
62 | syscall_regfunc, syscall_unregfunc | 64 | syscall_regfunc, syscall_unregfunc |
63 | ); | 65 | ); |
64 | 66 | ||
67 | TRACE_EVENT_FLAGS(sys_exit, TRACE_EVENT_FL_CAP_ANY) | ||
68 | |||
65 | #endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */ | 69 | #endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */ |
66 | 70 | ||
67 | #endif /* _TRACE_EVENTS_SYSCALLS_H */ | 71 | #endif /* _TRACE_EVENTS_SYSCALLS_H */ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index a9377c0083ad..e718a917d897 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -82,6 +82,10 @@ | |||
82 | TRACE_EVENT(name, PARAMS(proto), PARAMS(args), \ | 82 | TRACE_EVENT(name, PARAMS(proto), PARAMS(args), \ |
83 | PARAMS(tstruct), PARAMS(assign), PARAMS(print)) \ | 83 | PARAMS(tstruct), PARAMS(assign), PARAMS(print)) \ |
84 | 84 | ||
85 | #undef TRACE_EVENT_FLAGS | ||
86 | #define TRACE_EVENT_FLAGS(name, value) \ | ||
87 | __TRACE_EVENT_FLAGS(name, value) | ||
88 | |||
85 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 89 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
86 | 90 | ||
87 | 91 | ||
@@ -129,6 +133,9 @@ | |||
129 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ | 133 | #define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ |
130 | DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) | 134 | DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) |
131 | 135 | ||
136 | #undef TRACE_EVENT_FLAGS | ||
137 | #define TRACE_EVENT_FLAGS(event, flag) | ||
138 | |||
132 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) | 139 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
133 | 140 | ||
134 | /* | 141 | /* |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index cb6c0d2af68f..40c3aab648a1 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -4773,15 +4773,6 @@ static int perf_tp_event_init(struct perf_event *event) | |||
4773 | if (event->attr.type != PERF_TYPE_TRACEPOINT) | 4773 | if (event->attr.type != PERF_TYPE_TRACEPOINT) |
4774 | return -ENOENT; | 4774 | return -ENOENT; |
4775 | 4775 | ||
4776 | /* | ||
4777 | * Raw tracepoint data is a severe data leak, only allow root to | ||
4778 | * have these. | ||
4779 | */ | ||
4780 | if ((event->attr.sample_type & PERF_SAMPLE_RAW) && | ||
4781 | perf_paranoid_tracepoint_raw() && | ||
4782 | !capable(CAP_SYS_ADMIN)) | ||
4783 | return -EPERM; | ||
4784 | |||
4785 | err = perf_trace_init(event); | 4776 | err = perf_trace_init(event); |
4786 | if (err) | 4777 | if (err) |
4787 | return err; | 4778 | return err; |
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 39c059ca670e..19a359d5e6d5 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -21,17 +21,46 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)]) | |||
21 | /* Count the events in use (per event id, not per instance) */ | 21 | /* Count the events in use (per event id, not per instance) */ |
22 | static int total_ref_count; | 22 | static int total_ref_count; |
23 | 23 | ||
24 | static int perf_trace_event_perm(struct ftrace_event_call *tp_event, | ||
25 | struct perf_event *p_event) | ||
26 | { | ||
27 | /* No tracing, just counting, so no obvious leak */ | ||
28 | if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) | ||
29 | return 0; | ||
30 | |||
31 | /* Some events are ok to be traced by non-root users... */ | ||
32 | if (p_event->attach_state == PERF_ATTACH_TASK) { | ||
33 | if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY) | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * ...otherwise raw tracepoint data can be a severe data leak, | ||
39 | * only allow root to have these. | ||
40 | */ | ||
41 | if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) | ||
42 | return -EPERM; | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
24 | static int perf_trace_event_init(struct ftrace_event_call *tp_event, | 47 | static int perf_trace_event_init(struct ftrace_event_call *tp_event, |
25 | struct perf_event *p_event) | 48 | struct perf_event *p_event) |
26 | { | 49 | { |
27 | struct hlist_head __percpu *list; | 50 | struct hlist_head __percpu *list; |
28 | int ret = -ENOMEM; | 51 | int ret; |
29 | int cpu; | 52 | int cpu; |
30 | 53 | ||
54 | ret = perf_trace_event_perm(tp_event, p_event); | ||
55 | if (ret) | ||
56 | return ret; | ||
57 | |||
31 | p_event->tp_event = tp_event; | 58 | p_event->tp_event = tp_event; |
32 | if (tp_event->perf_refcount++ > 0) | 59 | if (tp_event->perf_refcount++ > 0) |
33 | return 0; | 60 | return 0; |
34 | 61 | ||
62 | ret = -ENOMEM; | ||
63 | |||
35 | list = alloc_percpu(struct hlist_head); | 64 | list = alloc_percpu(struct hlist_head); |
36 | if (!list) | 65 | if (!list) |
37 | goto fail; | 66 | goto fail; |