diff options
Diffstat (limited to 'kernel/trace/trace_event_perf.c')
-rw-r--r-- | kernel/trace/trace_event_perf.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index d72af0b03822..fdeeb5c49627 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -24,6 +24,11 @@ static int total_ref_count; | |||
24 | static int perf_trace_event_perm(struct ftrace_event_call *tp_event, | 24 | static int perf_trace_event_perm(struct ftrace_event_call *tp_event, |
25 | struct perf_event *p_event) | 25 | struct perf_event *p_event) |
26 | { | 26 | { |
27 | /* The ftrace function trace is allowed only for root. */ | ||
28 | if (ftrace_event_is_function(tp_event) && | ||
29 | perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | ||
30 | return -EPERM; | ||
31 | |||
27 | /* No tracing, just counting, so no obvious leak */ | 32 | /* No tracing, just counting, so no obvious leak */ |
28 | if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) | 33 | if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) |
29 | return 0; | 34 | return 0; |
@@ -250,3 +255,84 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, | |||
250 | return raw_data; | 255 | return raw_data; |
251 | } | 256 | } |
252 | EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); | 257 | EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); |
258 | |||
259 | #ifdef CONFIG_FUNCTION_TRACER | ||
260 | static void | ||
261 | perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip) | ||
262 | { | ||
263 | struct ftrace_entry *entry; | ||
264 | struct hlist_head *head; | ||
265 | struct pt_regs regs; | ||
266 | int rctx; | ||
267 | |||
268 | #define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \ | ||
269 | sizeof(u64)) - sizeof(u32)) | ||
270 | |||
271 | BUILD_BUG_ON(ENTRY_SIZE > PERF_MAX_TRACE_SIZE); | ||
272 | |||
273 | perf_fetch_caller_regs(®s); | ||
274 | |||
275 | entry = perf_trace_buf_prepare(ENTRY_SIZE, TRACE_FN, NULL, &rctx); | ||
276 | if (!entry) | ||
277 | return; | ||
278 | |||
279 | entry->ip = ip; | ||
280 | entry->parent_ip = parent_ip; | ||
281 | |||
282 | head = this_cpu_ptr(event_function.perf_events); | ||
283 | perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0, | ||
284 | 1, ®s, head); | ||
285 | |||
286 | #undef ENTRY_SIZE | ||
287 | } | ||
288 | |||
289 | static int perf_ftrace_function_register(struct perf_event *event) | ||
290 | { | ||
291 | struct ftrace_ops *ops = &event->ftrace_ops; | ||
292 | |||
293 | ops->flags |= FTRACE_OPS_FL_CONTROL; | ||
294 | ops->func = perf_ftrace_function_call; | ||
295 | return register_ftrace_function(ops); | ||
296 | } | ||
297 | |||
298 | static int perf_ftrace_function_unregister(struct perf_event *event) | ||
299 | { | ||
300 | struct ftrace_ops *ops = &event->ftrace_ops; | ||
301 | return unregister_ftrace_function(ops); | ||
302 | } | ||
303 | |||
304 | static void perf_ftrace_function_enable(struct perf_event *event) | ||
305 | { | ||
306 | ftrace_function_local_enable(&event->ftrace_ops); | ||
307 | } | ||
308 | |||
309 | static void perf_ftrace_function_disable(struct perf_event *event) | ||
310 | { | ||
311 | ftrace_function_local_disable(&event->ftrace_ops); | ||
312 | } | ||
313 | |||
314 | int perf_ftrace_event_register(struct ftrace_event_call *call, | ||
315 | enum trace_reg type, void *data) | ||
316 | { | ||
317 | switch (type) { | ||
318 | case TRACE_REG_REGISTER: | ||
319 | case TRACE_REG_UNREGISTER: | ||
320 | break; | ||
321 | case TRACE_REG_PERF_REGISTER: | ||
322 | case TRACE_REG_PERF_UNREGISTER: | ||
323 | return 0; | ||
324 | case TRACE_REG_PERF_OPEN: | ||
325 | return perf_ftrace_function_register(data); | ||
326 | case TRACE_REG_PERF_CLOSE: | ||
327 | return perf_ftrace_function_unregister(data); | ||
328 | case TRACE_REG_PERF_ADD: | ||
329 | perf_ftrace_function_enable(data); | ||
330 | return 0; | ||
331 | case TRACE_REG_PERF_DEL: | ||
332 | perf_ftrace_function_disable(data); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | return -EINVAL; | ||
337 | } | ||
338 | #endif /* CONFIG_FUNCTION_TRACER */ | ||