162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * trace event based perf event profiling/tracing
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra
662306a36Sopenharmony_ci * Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/kprobes.h>
1162306a36Sopenharmony_ci#include <linux/security.h>
1262306a36Sopenharmony_ci#include "trace.h"
1362306a36Sopenharmony_ci#include "trace_probe.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Force it to be aligned to unsigned long to avoid misaligned accesses
1962306a36Sopenharmony_ci * surprises
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_citypedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
2262306a36Sopenharmony_ci	perf_trace_t;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Count the events in use (per event id, not per instance) */
2562306a36Sopenharmony_cistatic int	total_ref_count;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int perf_trace_event_perm(struct trace_event_call *tp_event,
2862306a36Sopenharmony_ci				 struct perf_event *p_event)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	int ret;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	if (tp_event->perf_perm) {
3362306a36Sopenharmony_ci		ret = tp_event->perf_perm(tp_event, p_event);
3462306a36Sopenharmony_ci		if (ret)
3562306a36Sopenharmony_ci			return ret;
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/*
3962306a36Sopenharmony_ci	 * We checked and allowed to create parent,
4062306a36Sopenharmony_ci	 * allow children without checking.
4162306a36Sopenharmony_ci	 */
4262306a36Sopenharmony_ci	if (p_event->parent)
4362306a36Sopenharmony_ci		return 0;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/*
4662306a36Sopenharmony_ci	 * It's ok to check current process (owner) permissions in here,
4762306a36Sopenharmony_ci	 * because code below is called only via perf_event_open syscall.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* The ftrace function trace is allowed only for root. */
5162306a36Sopenharmony_ci	if (ftrace_event_is_function(tp_event)) {
5262306a36Sopenharmony_ci		ret = perf_allow_tracepoint(&p_event->attr);
5362306a36Sopenharmony_ci		if (ret)
5462306a36Sopenharmony_ci			return ret;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci		if (!is_sampling_event(p_event))
5762306a36Sopenharmony_ci			return 0;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		/*
6062306a36Sopenharmony_ci		 * We don't allow user space callchains for  function trace
6162306a36Sopenharmony_ci		 * event, due to issues with page faults while tracing page
6262306a36Sopenharmony_ci		 * fault handler and its overall trickiness nature.
6362306a36Sopenharmony_ci		 */
6462306a36Sopenharmony_ci		if (!p_event->attr.exclude_callchain_user)
6562306a36Sopenharmony_ci			return -EINVAL;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		/*
6862306a36Sopenharmony_ci		 * Same reason to disable user stack dump as for user space
6962306a36Sopenharmony_ci		 * callchains above.
7062306a36Sopenharmony_ci		 */
7162306a36Sopenharmony_ci		if (p_event->attr.sample_type & PERF_SAMPLE_STACK_USER)
7262306a36Sopenharmony_ci			return -EINVAL;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* No tracing, just counting, so no obvious leak */
7662306a36Sopenharmony_ci	if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
7762306a36Sopenharmony_ci		return 0;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* Some events are ok to be traced by non-root users... */
8062306a36Sopenharmony_ci	if (p_event->attach_state == PERF_ATTACH_TASK) {
8162306a36Sopenharmony_ci		if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY)
8262306a36Sopenharmony_ci			return 0;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/*
8662306a36Sopenharmony_ci	 * ...otherwise raw tracepoint data can be a severe data leak,
8762306a36Sopenharmony_ci	 * only allow root to have these.
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci	ret = perf_allow_tracepoint(&p_event->attr);
9062306a36Sopenharmony_ci	if (ret)
9162306a36Sopenharmony_ci		return ret;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	return 0;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int perf_trace_event_reg(struct trace_event_call *tp_event,
9762306a36Sopenharmony_ci				struct perf_event *p_event)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct hlist_head __percpu *list;
10062306a36Sopenharmony_ci	int ret = -ENOMEM;
10162306a36Sopenharmony_ci	int cpu;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	p_event->tp_event = tp_event;
10462306a36Sopenharmony_ci	if (tp_event->perf_refcount++ > 0)
10562306a36Sopenharmony_ci		return 0;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	list = alloc_percpu(struct hlist_head);
10862306a36Sopenharmony_ci	if (!list)
10962306a36Sopenharmony_ci		goto fail;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	for_each_possible_cpu(cpu)
11262306a36Sopenharmony_ci		INIT_HLIST_HEAD(per_cpu_ptr(list, cpu));
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	tp_event->perf_events = list;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (!total_ref_count) {
11762306a36Sopenharmony_ci		char __percpu *buf;
11862306a36Sopenharmony_ci		int i;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
12162306a36Sopenharmony_ci			buf = (char __percpu *)alloc_percpu(perf_trace_t);
12262306a36Sopenharmony_ci			if (!buf)
12362306a36Sopenharmony_ci				goto fail;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci			perf_trace_buf[i] = buf;
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER, NULL);
13062306a36Sopenharmony_ci	if (ret)
13162306a36Sopenharmony_ci		goto fail;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	total_ref_count++;
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cifail:
13762306a36Sopenharmony_ci	if (!total_ref_count) {
13862306a36Sopenharmony_ci		int i;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
14162306a36Sopenharmony_ci			free_percpu(perf_trace_buf[i]);
14262306a36Sopenharmony_ci			perf_trace_buf[i] = NULL;
14362306a36Sopenharmony_ci		}
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (!--tp_event->perf_refcount) {
14762306a36Sopenharmony_ci		free_percpu(tp_event->perf_events);
14862306a36Sopenharmony_ci		tp_event->perf_events = NULL;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return ret;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void perf_trace_event_unreg(struct perf_event *p_event)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct trace_event_call *tp_event = p_event->tp_event;
15762306a36Sopenharmony_ci	int i;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (--tp_event->perf_refcount > 0)
16062306a36Sopenharmony_ci		return;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/*
16562306a36Sopenharmony_ci	 * Ensure our callback won't be called anymore. The buffers
16662306a36Sopenharmony_ci	 * will be freed after that.
16762306a36Sopenharmony_ci	 */
16862306a36Sopenharmony_ci	tracepoint_synchronize_unregister();
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	free_percpu(tp_event->perf_events);
17162306a36Sopenharmony_ci	tp_event->perf_events = NULL;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (!--total_ref_count) {
17462306a36Sopenharmony_ci		for (i = 0; i < PERF_NR_CONTEXTS; i++) {
17562306a36Sopenharmony_ci			free_percpu(perf_trace_buf[i]);
17662306a36Sopenharmony_ci			perf_trace_buf[i] = NULL;
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int perf_trace_event_open(struct perf_event *p_event)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct trace_event_call *tp_event = p_event->tp_event;
18462306a36Sopenharmony_ci	return tp_event->class->reg(tp_event, TRACE_REG_PERF_OPEN, p_event);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic void perf_trace_event_close(struct perf_event *p_event)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct trace_event_call *tp_event = p_event->tp_event;
19062306a36Sopenharmony_ci	tp_event->class->reg(tp_event, TRACE_REG_PERF_CLOSE, p_event);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int perf_trace_event_init(struct trace_event_call *tp_event,
19462306a36Sopenharmony_ci				 struct perf_event *p_event)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	int ret;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	ret = perf_trace_event_perm(tp_event, p_event);
19962306a36Sopenharmony_ci	if (ret)
20062306a36Sopenharmony_ci		return ret;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ret = perf_trace_event_reg(tp_event, p_event);
20362306a36Sopenharmony_ci	if (ret)
20462306a36Sopenharmony_ci		return ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	ret = perf_trace_event_open(p_event);
20762306a36Sopenharmony_ci	if (ret) {
20862306a36Sopenharmony_ci		perf_trace_event_unreg(p_event);
20962306a36Sopenharmony_ci		return ret;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return 0;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciint perf_trace_init(struct perf_event *p_event)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct trace_event_call *tp_event;
21862306a36Sopenharmony_ci	u64 event_id = p_event->attr.config;
21962306a36Sopenharmony_ci	int ret = -EINVAL;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	mutex_lock(&event_mutex);
22262306a36Sopenharmony_ci	list_for_each_entry(tp_event, &ftrace_events, list) {
22362306a36Sopenharmony_ci		if (tp_event->event.type == event_id &&
22462306a36Sopenharmony_ci		    tp_event->class && tp_event->class->reg &&
22562306a36Sopenharmony_ci		    trace_event_try_get_ref(tp_event)) {
22662306a36Sopenharmony_ci			ret = perf_trace_event_init(tp_event, p_event);
22762306a36Sopenharmony_ci			if (ret)
22862306a36Sopenharmony_ci				trace_event_put_ref(tp_event);
22962306a36Sopenharmony_ci			break;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci	mutex_unlock(&event_mutex);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return ret;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_civoid perf_trace_destroy(struct perf_event *p_event)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	mutex_lock(&event_mutex);
24062306a36Sopenharmony_ci	perf_trace_event_close(p_event);
24162306a36Sopenharmony_ci	perf_trace_event_unreg(p_event);
24262306a36Sopenharmony_ci	trace_event_put_ref(p_event->tp_event);
24362306a36Sopenharmony_ci	mutex_unlock(&event_mutex);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#ifdef CONFIG_KPROBE_EVENTS
24762306a36Sopenharmony_ciint perf_kprobe_init(struct perf_event *p_event, bool is_retprobe)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	int ret;
25062306a36Sopenharmony_ci	char *func = NULL;
25162306a36Sopenharmony_ci	struct trace_event_call *tp_event;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (p_event->attr.kprobe_func) {
25462306a36Sopenharmony_ci		func = strndup_user(u64_to_user_ptr(p_event->attr.kprobe_func),
25562306a36Sopenharmony_ci				    KSYM_NAME_LEN);
25662306a36Sopenharmony_ci		if (IS_ERR(func)) {
25762306a36Sopenharmony_ci			ret = PTR_ERR(func);
25862306a36Sopenharmony_ci			return (ret == -EINVAL) ? -E2BIG : ret;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (func[0] == '\0') {
26262306a36Sopenharmony_ci			kfree(func);
26362306a36Sopenharmony_ci			func = NULL;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	tp_event = create_local_trace_kprobe(
26862306a36Sopenharmony_ci		func, (void *)(unsigned long)(p_event->attr.kprobe_addr),
26962306a36Sopenharmony_ci		p_event->attr.probe_offset, is_retprobe);
27062306a36Sopenharmony_ci	if (IS_ERR(tp_event)) {
27162306a36Sopenharmony_ci		ret = PTR_ERR(tp_event);
27262306a36Sopenharmony_ci		goto out;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	mutex_lock(&event_mutex);
27662306a36Sopenharmony_ci	ret = perf_trace_event_init(tp_event, p_event);
27762306a36Sopenharmony_ci	if (ret)
27862306a36Sopenharmony_ci		destroy_local_trace_kprobe(tp_event);
27962306a36Sopenharmony_ci	mutex_unlock(&event_mutex);
28062306a36Sopenharmony_ciout:
28162306a36Sopenharmony_ci	kfree(func);
28262306a36Sopenharmony_ci	return ret;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_civoid perf_kprobe_destroy(struct perf_event *p_event)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	mutex_lock(&event_mutex);
28862306a36Sopenharmony_ci	perf_trace_event_close(p_event);
28962306a36Sopenharmony_ci	perf_trace_event_unreg(p_event);
29062306a36Sopenharmony_ci	trace_event_put_ref(p_event->tp_event);
29162306a36Sopenharmony_ci	mutex_unlock(&event_mutex);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	destroy_local_trace_kprobe(p_event->tp_event);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci#endif /* CONFIG_KPROBE_EVENTS */
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#ifdef CONFIG_UPROBE_EVENTS
29862306a36Sopenharmony_ciint perf_uprobe_init(struct perf_event *p_event,
29962306a36Sopenharmony_ci		     unsigned long ref_ctr_offset, bool is_retprobe)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	int ret;
30262306a36Sopenharmony_ci	char *path = NULL;
30362306a36Sopenharmony_ci	struct trace_event_call *tp_event;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (!p_event->attr.uprobe_path)
30662306a36Sopenharmony_ci		return -EINVAL;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	path = strndup_user(u64_to_user_ptr(p_event->attr.uprobe_path),
30962306a36Sopenharmony_ci			    PATH_MAX);
31062306a36Sopenharmony_ci	if (IS_ERR(path)) {
31162306a36Sopenharmony_ci		ret = PTR_ERR(path);
31262306a36Sopenharmony_ci		return (ret == -EINVAL) ? -E2BIG : ret;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	if (path[0] == '\0') {
31562306a36Sopenharmony_ci		ret = -EINVAL;
31662306a36Sopenharmony_ci		goto out;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	tp_event = create_local_trace_uprobe(path, p_event->attr.probe_offset,
32062306a36Sopenharmony_ci					     ref_ctr_offset, is_retprobe);
32162306a36Sopenharmony_ci	if (IS_ERR(tp_event)) {
32262306a36Sopenharmony_ci		ret = PTR_ERR(tp_event);
32362306a36Sopenharmony_ci		goto out;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/*
32762306a36Sopenharmony_ci	 * local trace_uprobe need to hold event_mutex to call
32862306a36Sopenharmony_ci	 * uprobe_buffer_enable() and uprobe_buffer_disable().
32962306a36Sopenharmony_ci	 * event_mutex is not required for local trace_kprobes.
33062306a36Sopenharmony_ci	 */
33162306a36Sopenharmony_ci	mutex_lock(&event_mutex);
33262306a36Sopenharmony_ci	ret = perf_trace_event_init(tp_event, p_event);
33362306a36Sopenharmony_ci	if (ret)
33462306a36Sopenharmony_ci		destroy_local_trace_uprobe(tp_event);
33562306a36Sopenharmony_ci	mutex_unlock(&event_mutex);
33662306a36Sopenharmony_ciout:
33762306a36Sopenharmony_ci	kfree(path);
33862306a36Sopenharmony_ci	return ret;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_civoid perf_uprobe_destroy(struct perf_event *p_event)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	mutex_lock(&event_mutex);
34462306a36Sopenharmony_ci	perf_trace_event_close(p_event);
34562306a36Sopenharmony_ci	perf_trace_event_unreg(p_event);
34662306a36Sopenharmony_ci	trace_event_put_ref(p_event->tp_event);
34762306a36Sopenharmony_ci	mutex_unlock(&event_mutex);
34862306a36Sopenharmony_ci	destroy_local_trace_uprobe(p_event->tp_event);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci#endif /* CONFIG_UPROBE_EVENTS */
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ciint perf_trace_add(struct perf_event *p_event, int flags)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct trace_event_call *tp_event = p_event->tp_event;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (!(flags & PERF_EF_START))
35762306a36Sopenharmony_ci		p_event->hw.state = PERF_HES_STOPPED;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/*
36062306a36Sopenharmony_ci	 * If TRACE_REG_PERF_ADD returns false; no custom action was performed
36162306a36Sopenharmony_ci	 * and we need to take the default action of enqueueing our event on
36262306a36Sopenharmony_ci	 * the right per-cpu hlist.
36362306a36Sopenharmony_ci	 */
36462306a36Sopenharmony_ci	if (!tp_event->class->reg(tp_event, TRACE_REG_PERF_ADD, p_event)) {
36562306a36Sopenharmony_ci		struct hlist_head __percpu *pcpu_list;
36662306a36Sopenharmony_ci		struct hlist_head *list;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		pcpu_list = tp_event->perf_events;
36962306a36Sopenharmony_ci		if (WARN_ON_ONCE(!pcpu_list))
37062306a36Sopenharmony_ci			return -EINVAL;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		list = this_cpu_ptr(pcpu_list);
37362306a36Sopenharmony_ci		hlist_add_head_rcu(&p_event->hlist_entry, list);
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return 0;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_civoid perf_trace_del(struct perf_event *p_event, int flags)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct trace_event_call *tp_event = p_event->tp_event;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/*
38462306a36Sopenharmony_ci	 * If TRACE_REG_PERF_DEL returns false; no custom action was performed
38562306a36Sopenharmony_ci	 * and we need to take the default action of dequeueing our event from
38662306a36Sopenharmony_ci	 * the right per-cpu hlist.
38762306a36Sopenharmony_ci	 */
38862306a36Sopenharmony_ci	if (!tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event))
38962306a36Sopenharmony_ci		hlist_del_rcu(&p_event->hlist_entry);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_civoid *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	char *raw_data;
39562306a36Sopenharmony_ci	int rctx;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long));
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
40062306a36Sopenharmony_ci		      "perf buffer not large enough, wanted %d, have %d",
40162306a36Sopenharmony_ci		      size, PERF_MAX_TRACE_SIZE))
40262306a36Sopenharmony_ci		return NULL;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	*rctxp = rctx = perf_swevent_get_recursion_context();
40562306a36Sopenharmony_ci	if (rctx < 0)
40662306a36Sopenharmony_ci		return NULL;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (regs)
40962306a36Sopenharmony_ci		*regs = this_cpu_ptr(&__perf_regs[rctx]);
41062306a36Sopenharmony_ci	raw_data = this_cpu_ptr(perf_trace_buf[rctx]);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* zero the dead bytes from align to not leak stack to user */
41362306a36Sopenharmony_ci	memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
41462306a36Sopenharmony_ci	return raw_data;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(perf_trace_buf_alloc);
41762306a36Sopenharmony_ciNOKPROBE_SYMBOL(perf_trace_buf_alloc);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_civoid perf_trace_buf_update(void *record, u16 type)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct trace_entry *entry = record;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	tracing_generic_entry_update(entry, type, tracing_gen_ctx());
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ciNOKPROBE_SYMBOL(perf_trace_buf_update);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_TRACER
42862306a36Sopenharmony_cistatic void
42962306a36Sopenharmony_ciperf_ftrace_function_call(unsigned long ip, unsigned long parent_ip,
43062306a36Sopenharmony_ci			  struct ftrace_ops *ops,  struct ftrace_regs *fregs)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	struct ftrace_entry *entry;
43362306a36Sopenharmony_ci	struct perf_event *event;
43462306a36Sopenharmony_ci	struct hlist_head head;
43562306a36Sopenharmony_ci	struct pt_regs regs;
43662306a36Sopenharmony_ci	int rctx;
43762306a36Sopenharmony_ci	int bit;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (!rcu_is_watching())
44062306a36Sopenharmony_ci		return;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	bit = ftrace_test_recursion_trylock(ip, parent_ip);
44362306a36Sopenharmony_ci	if (bit < 0)
44462306a36Sopenharmony_ci		return;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if ((unsigned long)ops->private != smp_processor_id())
44762306a36Sopenharmony_ci		goto out;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	event = container_of(ops, struct perf_event, ftrace_ops);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/*
45262306a36Sopenharmony_ci	 * @event->hlist entry is NULL (per INIT_HLIST_NODE), and all
45362306a36Sopenharmony_ci	 * the perf code does is hlist_for_each_entry_rcu(), so we can
45462306a36Sopenharmony_ci	 * get away with simply setting the @head.first pointer in order
45562306a36Sopenharmony_ci	 * to create a singular list.
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci	head.first = &event->hlist_entry;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci#define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \
46062306a36Sopenharmony_ci		    sizeof(u64)) - sizeof(u32))
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	BUILD_BUG_ON(ENTRY_SIZE > PERF_MAX_TRACE_SIZE);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	memset(&regs, 0, sizeof(regs));
46562306a36Sopenharmony_ci	perf_fetch_caller_regs(&regs);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	entry = perf_trace_buf_alloc(ENTRY_SIZE, NULL, &rctx);
46862306a36Sopenharmony_ci	if (!entry)
46962306a36Sopenharmony_ci		goto out;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	entry->ip = ip;
47262306a36Sopenharmony_ci	entry->parent_ip = parent_ip;
47362306a36Sopenharmony_ci	perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, TRACE_FN,
47462306a36Sopenharmony_ci			      1, &regs, &head, NULL);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ciout:
47762306a36Sopenharmony_ci	ftrace_test_recursion_unlock(bit);
47862306a36Sopenharmony_ci#undef ENTRY_SIZE
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int perf_ftrace_function_register(struct perf_event *event)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct ftrace_ops *ops = &event->ftrace_ops;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	ops->func    = perf_ftrace_function_call;
48662306a36Sopenharmony_ci	ops->private = (void *)(unsigned long)nr_cpu_ids;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	return register_ftrace_function(ops);
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cistatic int perf_ftrace_function_unregister(struct perf_event *event)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct ftrace_ops *ops = &event->ftrace_ops;
49462306a36Sopenharmony_ci	int ret = unregister_ftrace_function(ops);
49562306a36Sopenharmony_ci	ftrace_free_filter(ops);
49662306a36Sopenharmony_ci	return ret;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ciint perf_ftrace_event_register(struct trace_event_call *call,
50062306a36Sopenharmony_ci			       enum trace_reg type, void *data)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct perf_event *event = data;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	switch (type) {
50562306a36Sopenharmony_ci	case TRACE_REG_REGISTER:
50662306a36Sopenharmony_ci	case TRACE_REG_UNREGISTER:
50762306a36Sopenharmony_ci		break;
50862306a36Sopenharmony_ci	case TRACE_REG_PERF_REGISTER:
50962306a36Sopenharmony_ci	case TRACE_REG_PERF_UNREGISTER:
51062306a36Sopenharmony_ci		return 0;
51162306a36Sopenharmony_ci	case TRACE_REG_PERF_OPEN:
51262306a36Sopenharmony_ci		return perf_ftrace_function_register(data);
51362306a36Sopenharmony_ci	case TRACE_REG_PERF_CLOSE:
51462306a36Sopenharmony_ci		return perf_ftrace_function_unregister(data);
51562306a36Sopenharmony_ci	case TRACE_REG_PERF_ADD:
51662306a36Sopenharmony_ci		event->ftrace_ops.private = (void *)(unsigned long)smp_processor_id();
51762306a36Sopenharmony_ci		return 1;
51862306a36Sopenharmony_ci	case TRACE_REG_PERF_DEL:
51962306a36Sopenharmony_ci		event->ftrace_ops.private = (void *)(unsigned long)nr_cpu_ids;
52062306a36Sopenharmony_ci		return 1;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	return -EINVAL;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci#endif /* CONFIG_FUNCTION_TRACER */
526