perf/core: Implement the 'perf_kprobe' PMU
A new PMU type, perf_kprobe is added. Based on attr from perf_event_open(), perf_kprobe creates a kprobe (or kretprobe) for the perf_event. This kprobe is private to this perf_event, and thus not added to global lists, and not available in tracefs. Two functions, create_local_trace_kprobe() and destroy_local_trace_kprobe() are added to created and destroy these local trace_kprobe. Signed-off-by: Song Liu <songliubraving@fb.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Yonghong Song <yhs@fb.com> Reviewed-by: Josef Bacik <jbacik@fb.com> Cc: <daniel@iogearbox.net> Cc: <davem@davemloft.net> Cc: <kernel-team@fb.com> Cc: <rostedt@goodmis.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/20171206224518.3598254-6-songliubraving@fb.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include "trace.h"
|
||||
#include "trace_probe.h"
|
||||
|
||||
static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
|
||||
|
||||
@@ -237,6 +238,54 @@ void perf_trace_destroy(struct perf_event *p_event)
|
||||
mutex_unlock(&event_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KPROBE_EVENTS
|
||||
int perf_kprobe_init(struct perf_event *p_event, bool is_retprobe)
|
||||
{
|
||||
int ret;
|
||||
char *func = NULL;
|
||||
struct trace_event_call *tp_event;
|
||||
|
||||
if (p_event->attr.kprobe_func) {
|
||||
func = kzalloc(KSYM_NAME_LEN, GFP_KERNEL);
|
||||
if (!func)
|
||||
return -ENOMEM;
|
||||
ret = strncpy_from_user(
|
||||
func, u64_to_user_ptr(p_event->attr.kprobe_func),
|
||||
KSYM_NAME_LEN);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (func[0] == '\0') {
|
||||
kfree(func);
|
||||
func = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
tp_event = create_local_trace_kprobe(
|
||||
func, (void *)(unsigned long)(p_event->attr.kprobe_addr),
|
||||
p_event->attr.probe_offset, is_retprobe);
|
||||
if (IS_ERR(tp_event)) {
|
||||
ret = PTR_ERR(tp_event);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = perf_trace_event_init(tp_event, p_event);
|
||||
if (ret)
|
||||
destroy_local_trace_kprobe(tp_event);
|
||||
out:
|
||||
kfree(func);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void perf_kprobe_destroy(struct perf_event *p_event)
|
||||
{
|
||||
perf_trace_event_close(p_event);
|
||||
perf_trace_event_unreg(p_event);
|
||||
|
||||
destroy_local_trace_kprobe(p_event->tp_event);
|
||||
}
|
||||
#endif /* CONFIG_KPROBE_EVENTS */
|
||||
|
||||
int perf_trace_add(struct perf_event *p_event, int flags)
|
||||
{
|
||||
struct trace_event_call *tp_event = p_event->tp_event;
|
||||
|
Reference in New Issue
Block a user