xref: /linux-6.15/kernel/trace/trace_uprobe.c (revision fd837de3)
1bcea3f96SSteven Rostedt (VMware) // SPDX-License-Identifier: GPL-2.0
2f3f096cfSSrikar Dronamraju /*
3f3f096cfSSrikar Dronamraju  * uprobes-based tracing events
4f3f096cfSSrikar Dronamraju  *
5f3f096cfSSrikar Dronamraju  * Copyright (C) IBM Corporation, 2010-2012
6f3f096cfSSrikar Dronamraju  * Author:	Srikar Dronamraju <[email protected]>
7f3f096cfSSrikar Dronamraju  */
8ea6eb5e7SAndreas Ziegler #define pr_fmt(fmt)	"trace_uprobe: " fmt
9f3f096cfSSrikar Dronamraju 
10aef2fedaSJakub Kicinski #include <linux/bpf-cgroup.h>
1117911ff3SSteven Rostedt (VMware) #include <linux/security.h>
120597c49cSMasami Hiramatsu #include <linux/ctype.h>
13f3f096cfSSrikar Dronamraju #include <linux/module.h>
14f3f096cfSSrikar Dronamraju #include <linux/uaccess.h>
15f3f096cfSSrikar Dronamraju #include <linux/uprobes.h>
16f3f096cfSSrikar Dronamraju #include <linux/namei.h>
17b2e902f0SAndy Shevchenko #include <linux/string.h>
18b2d09103SIngo Molnar #include <linux/rculist.h>
198c7dcb84SDelyan Kratunov #include <linux/filter.h>
2010cdb82aSAndrii Nakryiko #include <linux/percpu.h>
21f3f096cfSSrikar Dronamraju 
220597c49cSMasami Hiramatsu #include "trace_dynevent.h"
23f3f096cfSSrikar Dronamraju #include "trace_probe.h"
2453305928SMasami Hiramatsu #include "trace_probe_tmpl.h"
25f3f096cfSSrikar Dronamraju 
26f3f096cfSSrikar Dronamraju #define UPROBE_EVENT_SYSTEM	"uprobes"
27f3f096cfSSrikar Dronamraju 
28457d1772SOleg Nesterov struct uprobe_trace_entry_head {
29457d1772SOleg Nesterov 	struct trace_entry	ent;
30457d1772SOleg Nesterov 	unsigned long		vaddr[];
31457d1772SOleg Nesterov };
32457d1772SOleg Nesterov 
33457d1772SOleg Nesterov #define SIZEOF_TRACE_ENTRY(is_return)			\
34457d1772SOleg Nesterov 	(sizeof(struct uprobe_trace_entry_head) +	\
35457d1772SOleg Nesterov 	 sizeof(unsigned long) * (is_return ? 2 : 1))
36457d1772SOleg Nesterov 
37457d1772SOleg Nesterov #define DATAOF_TRACE_ENTRY(entry, is_return)		\
38457d1772SOleg Nesterov 	((void*)(entry) + SIZEOF_TRACE_ENTRY(is_return))
39457d1772SOleg Nesterov 
40d262271dSMasami Hiramatsu static int trace_uprobe_create(const char *raw_command);
410597c49cSMasami Hiramatsu static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev);
420597c49cSMasami Hiramatsu static int trace_uprobe_release(struct dyn_event *ev);
430597c49cSMasami Hiramatsu static bool trace_uprobe_is_busy(struct dyn_event *ev);
440597c49cSMasami Hiramatsu static bool trace_uprobe_match(const char *system, const char *event,
4530199137SMasami Hiramatsu 			int argc, const char **argv, struct dyn_event *ev);
460597c49cSMasami Hiramatsu 
470597c49cSMasami Hiramatsu static struct dyn_event_operations trace_uprobe_ops = {
480597c49cSMasami Hiramatsu 	.create = trace_uprobe_create,
490597c49cSMasami Hiramatsu 	.show = trace_uprobe_show,
500597c49cSMasami Hiramatsu 	.is_busy = trace_uprobe_is_busy,
510597c49cSMasami Hiramatsu 	.free = trace_uprobe_release,
520597c49cSMasami Hiramatsu 	.match = trace_uprobe_match,
530597c49cSMasami Hiramatsu };
540597c49cSMasami Hiramatsu 
55f3f096cfSSrikar Dronamraju /*
56f3f096cfSSrikar Dronamraju  * uprobe event core functions
57f3f096cfSSrikar Dronamraju  */
58f3f096cfSSrikar Dronamraju struct trace_uprobe {
590597c49cSMasami Hiramatsu 	struct dyn_event		devent;
60a932b738SOleg Nesterov 	struct uprobe_consumer		consumer;
610c92c7a3SSong Liu 	struct path			path;
62f3f096cfSSrikar Dronamraju 	char				*filename;
633c83a9adSOleg Nesterov 	struct uprobe			*uprobe;
64f3f096cfSSrikar Dronamraju 	unsigned long			offset;
651cc33161SRavi Bangoria 	unsigned long			ref_ctr_offset;
6610cdb82aSAndrii Nakryiko 	unsigned long __percpu		*nhits;
6714577c39SNamhyung Kim 	struct trace_probe		tp;
68f3f096cfSSrikar Dronamraju };
69f3f096cfSSrikar Dronamraju 
is_trace_uprobe(struct dyn_event * ev)700597c49cSMasami Hiramatsu static bool is_trace_uprobe(struct dyn_event *ev)
710597c49cSMasami Hiramatsu {
720597c49cSMasami Hiramatsu 	return ev->ops == &trace_uprobe_ops;
730597c49cSMasami Hiramatsu }
740597c49cSMasami Hiramatsu 
to_trace_uprobe(struct dyn_event * ev)750597c49cSMasami Hiramatsu static struct trace_uprobe *to_trace_uprobe(struct dyn_event *ev)
760597c49cSMasami Hiramatsu {
770597c49cSMasami Hiramatsu 	return container_of(ev, struct trace_uprobe, devent);
780597c49cSMasami Hiramatsu }
790597c49cSMasami Hiramatsu 
800597c49cSMasami Hiramatsu /**
810597c49cSMasami Hiramatsu  * for_each_trace_uprobe - iterate over the trace_uprobe list
820597c49cSMasami Hiramatsu  * @pos:	the struct trace_uprobe * for each entry
830597c49cSMasami Hiramatsu  * @dpos:	the struct dyn_event * to use as a loop cursor
840597c49cSMasami Hiramatsu  */
850597c49cSMasami Hiramatsu #define for_each_trace_uprobe(pos, dpos)	\
860597c49cSMasami Hiramatsu 	for_each_dyn_event(dpos)		\
870597c49cSMasami Hiramatsu 		if (is_trace_uprobe(dpos) && (pos = to_trace_uprobe(dpos)))
880597c49cSMasami Hiramatsu 
89f3f096cfSSrikar Dronamraju static int register_uprobe_event(struct trace_uprobe *tu);
90c6c2401dSSteven Rostedt (Red Hat) static int unregister_uprobe_event(struct trace_uprobe *tu);
91f3f096cfSSrikar Dronamraju 
92da09a9e0SJiri Olsa static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs,
93da09a9e0SJiri Olsa 			     __u64 *data);
94c1ae5c75SOleg Nesterov static int uretprobe_dispatcher(struct uprobe_consumer *con,
95da09a9e0SJiri Olsa 				unsigned long func, struct pt_regs *regs,
96da09a9e0SJiri Olsa 				__u64 *data);
97f3f096cfSSrikar Dronamraju 
983fd996a2SNamhyung Kim #ifdef CONFIG_STACK_GROWSUP
adjust_stack_addr(unsigned long addr,unsigned int n)993fd996a2SNamhyung Kim static unsigned long adjust_stack_addr(unsigned long addr, unsigned int n)
1003fd996a2SNamhyung Kim {
1013fd996a2SNamhyung Kim 	return addr - (n * sizeof(long));
1023fd996a2SNamhyung Kim }
1033fd996a2SNamhyung Kim #else
adjust_stack_addr(unsigned long addr,unsigned int n)1043fd996a2SNamhyung Kim static unsigned long adjust_stack_addr(unsigned long addr, unsigned int n)
1053fd996a2SNamhyung Kim {
1063fd996a2SNamhyung Kim 	return addr + (n * sizeof(long));
1073fd996a2SNamhyung Kim }
1083fd996a2SNamhyung Kim #endif
1093fd996a2SNamhyung Kim 
get_user_stack_nth(struct pt_regs * regs,unsigned int n)1103fd996a2SNamhyung Kim static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
1113fd996a2SNamhyung Kim {
1123fd996a2SNamhyung Kim 	unsigned long ret;
1133fd996a2SNamhyung Kim 	unsigned long addr = user_stack_pointer(regs);
1143fd996a2SNamhyung Kim 
1153fd996a2SNamhyung Kim 	addr = adjust_stack_addr(addr, n);
1163fd996a2SNamhyung Kim 
1173fd996a2SNamhyung Kim 	if (copy_from_user(&ret, (void __force __user *) addr, sizeof(ret)))
1183fd996a2SNamhyung Kim 		return 0;
1193fd996a2SNamhyung Kim 
1203fd996a2SNamhyung Kim 	return ret;
1213fd996a2SNamhyung Kim }
1223fd996a2SNamhyung Kim 
1233fd996a2SNamhyung Kim /*
1243fd996a2SNamhyung Kim  * Uprobes-specific fetch functions
1253fd996a2SNamhyung Kim  */
12653305928SMasami Hiramatsu static nokprobe_inline int
probe_mem_read(void * dest,void * src,size_t size)1279b960a38SMasami Hiramatsu probe_mem_read(void *dest, void *src, size_t size)
12853305928SMasami Hiramatsu {
12953305928SMasami Hiramatsu 	void __user *vaddr = (void __force __user *)src;
1303fd996a2SNamhyung Kim 
131f3f58935SMasami Hiramatsu 	return copy_from_user(dest, vaddr, size) ? -EFAULT : 0;
1325baaa59eSNamhyung Kim }
133e65f7ae7SMasami Hiramatsu 
134e65f7ae7SMasami Hiramatsu static nokprobe_inline int
probe_mem_read_user(void * dest,void * src,size_t size)135e65f7ae7SMasami Hiramatsu probe_mem_read_user(void *dest, void *src, size_t size)
136e65f7ae7SMasami Hiramatsu {
137e65f7ae7SMasami Hiramatsu 	return probe_mem_read(dest, src, size);
138e65f7ae7SMasami Hiramatsu }
139e65f7ae7SMasami Hiramatsu 
1405baaa59eSNamhyung Kim /*
1415baaa59eSNamhyung Kim  * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
1425baaa59eSNamhyung Kim  * length and relative data location.
1435baaa59eSNamhyung Kim  */
1449178412dSMasami Hiramatsu static nokprobe_inline int
fetch_store_string(unsigned long addr,void * dest,void * base)1459178412dSMasami Hiramatsu fetch_store_string(unsigned long addr, void *dest, void *base)
1465baaa59eSNamhyung Kim {
1475baaa59eSNamhyung Kim 	long ret;
1489178412dSMasami Hiramatsu 	u32 loc = *(u32 *)dest;
1499178412dSMasami Hiramatsu 	int maxlen  = get_loc_len(loc);
1509178412dSMasami Hiramatsu 	u8 *dst = get_loc_data(dest, base);
1515baaa59eSNamhyung Kim 	void __user *src = (void __force __user *) addr;
1525baaa59eSNamhyung Kim 
1539178412dSMasami Hiramatsu 	if (unlikely(!maxlen))
1549178412dSMasami Hiramatsu 		return -ENOMEM;
1555baaa59eSNamhyung Kim 
1564dd537acSMasami Hiramatsu 	if (addr == FETCH_TOKEN_COMM)
1578a3750ecSKees Cook 		ret = strscpy(dst, current->comm, maxlen);
1584dd537acSMasami Hiramatsu 	else
1595baaa59eSNamhyung Kim 		ret = strncpy_from_user(dst, src, maxlen);
1609178412dSMasami Hiramatsu 	if (ret >= 0) {
16150268a3dSMasami Hiramatsu 		if (ret == maxlen)
1629178412dSMasami Hiramatsu 			dst[ret - 1] = '\0';
1630722069aSAndreas Ziegler 		else
1640722069aSAndreas Ziegler 			/*
1650722069aSAndreas Ziegler 			 * Include the terminating null byte. In this case it
1660722069aSAndreas Ziegler 			 * was copied by strncpy_from_user but not accounted
1670722069aSAndreas Ziegler 			 * for in ret.
1680722069aSAndreas Ziegler 			 */
1690722069aSAndreas Ziegler 			ret++;
1709178412dSMasami Hiramatsu 		*(u32 *)dest = make_data_loc(ret, (void *)dst - base);
171797311bcSMasami Hiramatsu (Google) 	} else
172797311bcSMasami Hiramatsu (Google) 		*(u32 *)dest = make_data_loc(0, (void *)dst - base);
1739178412dSMasami Hiramatsu 
1749178412dSMasami Hiramatsu 	return ret;
1755baaa59eSNamhyung Kim }
1765baaa59eSNamhyung Kim 
17788903c46SMasami Hiramatsu static nokprobe_inline int
fetch_store_string_user(unsigned long addr,void * dest,void * base)17888903c46SMasami Hiramatsu fetch_store_string_user(unsigned long addr, void *dest, void *base)
17988903c46SMasami Hiramatsu {
18088903c46SMasami Hiramatsu 	return fetch_store_string(addr, dest, base);
18188903c46SMasami Hiramatsu }
18288903c46SMasami Hiramatsu 
18353305928SMasami Hiramatsu /* Return the length of string -- including null terminal byte */
1849178412dSMasami Hiramatsu static nokprobe_inline int
fetch_store_strlen(unsigned long addr)1859178412dSMasami Hiramatsu fetch_store_strlen(unsigned long addr)
1865baaa59eSNamhyung Kim {
1875baaa59eSNamhyung Kim 	int len;
1885baaa59eSNamhyung Kim 	void __user *vaddr = (void __force __user *) addr;
1895baaa59eSNamhyung Kim 
1904dd537acSMasami Hiramatsu 	if (addr == FETCH_TOKEN_COMM)
1914dd537acSMasami Hiramatsu 		len = strlen(current->comm) + 1;
1924dd537acSMasami Hiramatsu 	else
1935baaa59eSNamhyung Kim 		len = strnlen_user(vaddr, MAX_STRING_SIZE);
1945baaa59eSNamhyung Kim 
1959178412dSMasami Hiramatsu 	return (len > MAX_STRING_SIZE) ? 0 : len;
1965baaa59eSNamhyung Kim }
1973fd996a2SNamhyung Kim 
19888903c46SMasami Hiramatsu static nokprobe_inline int
fetch_store_strlen_user(unsigned long addr)19988903c46SMasami Hiramatsu fetch_store_strlen_user(unsigned long addr)
20088903c46SMasami Hiramatsu {
20188903c46SMasami Hiramatsu 	return fetch_store_strlen(addr);
20288903c46SMasami Hiramatsu }
20388903c46SMasami Hiramatsu 
translate_user_vaddr(unsigned long file_offset)20453305928SMasami Hiramatsu static unsigned long translate_user_vaddr(unsigned long file_offset)
205b7e0bf34SNamhyung Kim {
206b7e0bf34SNamhyung Kim 	unsigned long base_addr;
207b7e0bf34SNamhyung Kim 	struct uprobe_dispatch_data *udd;
208b7e0bf34SNamhyung Kim 
209b7e0bf34SNamhyung Kim 	udd = (void *) current->utask->vaddr;
210b7e0bf34SNamhyung Kim 
211b7e0bf34SNamhyung Kim 	base_addr = udd->bp_addr - udd->tu->offset;
21253305928SMasami Hiramatsu 	return base_addr + file_offset;
213b7e0bf34SNamhyung Kim }
214b7e0bf34SNamhyung Kim 
21553305928SMasami Hiramatsu /* Note that we don't verify it, since the code does not come from user space */
21653305928SMasami Hiramatsu static int
process_fetch_insn(struct fetch_insn * code,void * rec,void * edata,void * dest,void * base)21725f00e40SMasami Hiramatsu (Google) process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
21825f00e40SMasami Hiramatsu (Google) 		   void *dest, void *base)
21953305928SMasami Hiramatsu {
2208565a45dSSteven Rostedt (VMware) 	struct pt_regs *regs = rec;
22153305928SMasami Hiramatsu 	unsigned long val;
222bd78acc8SSong Chen 	int ret;
22353305928SMasami Hiramatsu 
22453305928SMasami Hiramatsu 	/* 1st stage: get value from context */
22553305928SMasami Hiramatsu 	switch (code->op) {
22653305928SMasami Hiramatsu 	case FETCH_OP_REG:
22753305928SMasami Hiramatsu 		val = regs_get_register(regs, code->param);
22853305928SMasami Hiramatsu 		break;
22953305928SMasami Hiramatsu 	case FETCH_OP_STACK:
23053305928SMasami Hiramatsu 		val = get_user_stack_nth(regs, code->param);
23153305928SMasami Hiramatsu 		break;
23253305928SMasami Hiramatsu 	case FETCH_OP_STACKP:
23353305928SMasami Hiramatsu 		val = user_stack_pointer(regs);
23453305928SMasami Hiramatsu 		break;
23553305928SMasami Hiramatsu 	case FETCH_OP_RETVAL:
23653305928SMasami Hiramatsu 		val = regs_return_value(regs);
23753305928SMasami Hiramatsu 		break;
2384dd537acSMasami Hiramatsu 	case FETCH_OP_COMM:
2394dd537acSMasami Hiramatsu 		val = FETCH_TOKEN_COMM;
2404dd537acSMasami Hiramatsu 		break;
24153305928SMasami Hiramatsu 	case FETCH_OP_FOFFS:
24253305928SMasami Hiramatsu 		val = translate_user_vaddr(code->immediate);
24353305928SMasami Hiramatsu 		break;
24453305928SMasami Hiramatsu 	default:
245bd78acc8SSong Chen 		ret = process_common_fetch_insn(code, &val);
246bd78acc8SSong Chen 		if (ret < 0)
247bd78acc8SSong Chen 			return ret;
24853305928SMasami Hiramatsu 	}
24953305928SMasami Hiramatsu 	code++;
25053305928SMasami Hiramatsu 
2519b960a38SMasami Hiramatsu 	return process_fetch_insn_bottom(code, val, dest, base);
25253305928SMasami Hiramatsu }
NOKPROBE_SYMBOL(process_fetch_insn)25353305928SMasami Hiramatsu NOKPROBE_SYMBOL(process_fetch_insn)
25453305928SMasami Hiramatsu 
255736288baSOleg Nesterov static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
256736288baSOleg Nesterov {
257736288baSOleg Nesterov 	rwlock_init(&filter->rwlock);
258736288baSOleg Nesterov 	filter->nr_systemwide = 0;
259736288baSOleg Nesterov 	INIT_LIST_HEAD(&filter->perf_events);
260736288baSOleg Nesterov }
261736288baSOleg Nesterov 
uprobe_filter_is_empty(struct trace_uprobe_filter * filter)262736288baSOleg Nesterov static inline bool uprobe_filter_is_empty(struct trace_uprobe_filter *filter)
263736288baSOleg Nesterov {
264736288baSOleg Nesterov 	return !filter->nr_systemwide && list_empty(&filter->perf_events);
265736288baSOleg Nesterov }
266736288baSOleg Nesterov 
is_ret_probe(struct trace_uprobe * tu)267c1ae5c75SOleg Nesterov static inline bool is_ret_probe(struct trace_uprobe *tu)
268c1ae5c75SOleg Nesterov {
269c1ae5c75SOleg Nesterov 	return tu->consumer.ret_handler != NULL;
270c1ae5c75SOleg Nesterov }
271c1ae5c75SOleg Nesterov 
trace_uprobe_is_busy(struct dyn_event * ev)2720597c49cSMasami Hiramatsu static bool trace_uprobe_is_busy(struct dyn_event *ev)
2730597c49cSMasami Hiramatsu {
2740597c49cSMasami Hiramatsu 	struct trace_uprobe *tu = to_trace_uprobe(ev);
2750597c49cSMasami Hiramatsu 
2760597c49cSMasami Hiramatsu 	return trace_probe_is_enabled(&tu->tp);
2770597c49cSMasami Hiramatsu }
2780597c49cSMasami Hiramatsu 
trace_uprobe_match_command_head(struct trace_uprobe * tu,int argc,const char ** argv)279ab10d69eSMasami Hiramatsu static bool trace_uprobe_match_command_head(struct trace_uprobe *tu,
280ab10d69eSMasami Hiramatsu 					    int argc, const char **argv)
281ab10d69eSMasami Hiramatsu {
282ab10d69eSMasami Hiramatsu 	char buf[MAX_ARGSTR_LEN + 1];
283ab10d69eSMasami Hiramatsu 	int len;
284ab10d69eSMasami Hiramatsu 
285ab10d69eSMasami Hiramatsu 	if (!argc)
286ab10d69eSMasami Hiramatsu 		return true;
287ab10d69eSMasami Hiramatsu 
288ab10d69eSMasami Hiramatsu 	len = strlen(tu->filename);
289ab10d69eSMasami Hiramatsu 	if (strncmp(tu->filename, argv[0], len) || argv[0][len] != ':')
290ab10d69eSMasami Hiramatsu 		return false;
291ab10d69eSMasami Hiramatsu 
292ab10d69eSMasami Hiramatsu 	if (tu->ref_ctr_offset == 0)
293ab10d69eSMasami Hiramatsu 		snprintf(buf, sizeof(buf), "0x%0*lx",
294ab10d69eSMasami Hiramatsu 				(int)(sizeof(void *) * 2), tu->offset);
295ab10d69eSMasami Hiramatsu 	else
296ab10d69eSMasami Hiramatsu 		snprintf(buf, sizeof(buf), "0x%0*lx(0x%lx)",
297ab10d69eSMasami Hiramatsu 				(int)(sizeof(void *) * 2), tu->offset,
298ab10d69eSMasami Hiramatsu 				tu->ref_ctr_offset);
299ab10d69eSMasami Hiramatsu 	if (strcmp(buf, &argv[0][len + 1]))
300ab10d69eSMasami Hiramatsu 		return false;
301ab10d69eSMasami Hiramatsu 
302ab10d69eSMasami Hiramatsu 	argc--; argv++;
303ab10d69eSMasami Hiramatsu 
304ab10d69eSMasami Hiramatsu 	return trace_probe_match_command_args(&tu->tp, argc, argv);
305ab10d69eSMasami Hiramatsu }
306ab10d69eSMasami Hiramatsu 
trace_uprobe_match(const char * system,const char * event,int argc,const char ** argv,struct dyn_event * ev)3070597c49cSMasami Hiramatsu static bool trace_uprobe_match(const char *system, const char *event,
30830199137SMasami Hiramatsu 			int argc, const char **argv, struct dyn_event *ev)
3090597c49cSMasami Hiramatsu {
3100597c49cSMasami Hiramatsu 	struct trace_uprobe *tu = to_trace_uprobe(ev);
3110597c49cSMasami Hiramatsu 
31295c104c3SLinyu Yuan 	return (event[0] == '\0' ||
31395c104c3SLinyu Yuan 		strcmp(trace_probe_name(&tu->tp), event) == 0) &&
314ab10d69eSMasami Hiramatsu 	   (!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0) &&
315ab10d69eSMasami Hiramatsu 	   trace_uprobe_match_command_head(tu, argc, argv);
3160597c49cSMasami Hiramatsu }
3170597c49cSMasami Hiramatsu 
31860d53e2cSMasami Hiramatsu static nokprobe_inline struct trace_uprobe *
trace_uprobe_primary_from_call(struct trace_event_call * call)31960d53e2cSMasami Hiramatsu trace_uprobe_primary_from_call(struct trace_event_call *call)
32060d53e2cSMasami Hiramatsu {
32160d53e2cSMasami Hiramatsu 	struct trace_probe *tp;
32260d53e2cSMasami Hiramatsu 
32360d53e2cSMasami Hiramatsu 	tp = trace_probe_primary_from_call(call);
32460d53e2cSMasami Hiramatsu 	if (WARN_ON_ONCE(!tp))
32560d53e2cSMasami Hiramatsu 		return NULL;
32660d53e2cSMasami Hiramatsu 
32760d53e2cSMasami Hiramatsu 	return container_of(tp, struct trace_uprobe, tp);
32860d53e2cSMasami Hiramatsu }
32960d53e2cSMasami Hiramatsu 
330f3f096cfSSrikar Dronamraju /*
331f3f096cfSSrikar Dronamraju  * Allocate new trace_uprobe and initialize it (including uprobes).
332f3f096cfSSrikar Dronamraju  */
333f3f096cfSSrikar Dronamraju static struct trace_uprobe *
alloc_trace_uprobe(const char * group,const char * event,int nargs,bool is_ret)334c1ae5c75SOleg Nesterov alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
335f3f096cfSSrikar Dronamraju {
336f3f096cfSSrikar Dronamraju 	struct trace_uprobe *tu;
337455b2899SMasami Hiramatsu 	int ret;
338f3f096cfSSrikar Dronamraju 
339845cbf3eSSteven Rostedt (VMware) 	tu = kzalloc(struct_size(tu, tp.args, nargs), GFP_KERNEL);
340f3f096cfSSrikar Dronamraju 	if (!tu)
341f3f096cfSSrikar Dronamraju 		return ERR_PTR(-ENOMEM);
342f3f096cfSSrikar Dronamraju 
34310cdb82aSAndrii Nakryiko 	tu->nhits = alloc_percpu(unsigned long);
34410cdb82aSAndrii Nakryiko 	if (!tu->nhits) {
34510cdb82aSAndrii Nakryiko 		ret = -ENOMEM;
34610cdb82aSAndrii Nakryiko 		goto error;
34710cdb82aSAndrii Nakryiko 	}
34810cdb82aSAndrii Nakryiko 
349035ba760SMasami Hiramatsu (Google) 	ret = trace_probe_init(&tu->tp, event, group, true, nargs);
350455b2899SMasami Hiramatsu 	if (ret < 0)
351f3f096cfSSrikar Dronamraju 		goto error;
352f3f096cfSSrikar Dronamraju 
3530597c49cSMasami Hiramatsu 	dyn_event_init(&tu->devent, &trace_uprobe_ops);
354a932b738SOleg Nesterov 	tu->consumer.handler = uprobe_dispatcher;
355c1ae5c75SOleg Nesterov 	if (is_ret)
356c1ae5c75SOleg Nesterov 		tu->consumer.ret_handler = uretprobe_dispatcher;
357b61387cbSMasami Hiramatsu 	init_trace_uprobe_filter(tu->tp.event->filter);
358f3f096cfSSrikar Dronamraju 	return tu;
359f3f096cfSSrikar Dronamraju 
360f3f096cfSSrikar Dronamraju error:
36110cdb82aSAndrii Nakryiko 	free_percpu(tu->nhits);
362f3f096cfSSrikar Dronamraju 	kfree(tu);
363f3f096cfSSrikar Dronamraju 
364455b2899SMasami Hiramatsu 	return ERR_PTR(ret);
365f3f096cfSSrikar Dronamraju }
366f3f096cfSSrikar Dronamraju 
free_trace_uprobe(struct trace_uprobe * tu)367f3f096cfSSrikar Dronamraju static void free_trace_uprobe(struct trace_uprobe *tu)
368f3f096cfSSrikar Dronamraju {
3690597c49cSMasami Hiramatsu 	if (!tu)
3700597c49cSMasami Hiramatsu 		return;
3710597c49cSMasami Hiramatsu 
3720c92c7a3SSong Liu 	path_put(&tu->path);
373455b2899SMasami Hiramatsu 	trace_probe_cleanup(&tu->tp);
374f3f096cfSSrikar Dronamraju 	kfree(tu->filename);
37510cdb82aSAndrii Nakryiko 	free_percpu(tu->nhits);
376f3f096cfSSrikar Dronamraju 	kfree(tu);
377f3f096cfSSrikar Dronamraju }
378f3f096cfSSrikar Dronamraju 
find_probe_event(const char * event,const char * group)379f3f096cfSSrikar Dronamraju static struct trace_uprobe *find_probe_event(const char *event, const char *group)
380f3f096cfSSrikar Dronamraju {
3810597c49cSMasami Hiramatsu 	struct dyn_event *pos;
382f3f096cfSSrikar Dronamraju 	struct trace_uprobe *tu;
383f3f096cfSSrikar Dronamraju 
3840597c49cSMasami Hiramatsu 	for_each_trace_uprobe(tu, pos)
385b55ce203SMasami Hiramatsu 		if (strcmp(trace_probe_name(&tu->tp), event) == 0 &&
386b55ce203SMasami Hiramatsu 		    strcmp(trace_probe_group_name(&tu->tp), group) == 0)
387f3f096cfSSrikar Dronamraju 			return tu;
388f3f096cfSSrikar Dronamraju 
389f3f096cfSSrikar Dronamraju 	return NULL;
390f3f096cfSSrikar Dronamraju }
391f3f096cfSSrikar Dronamraju 
3920597c49cSMasami Hiramatsu /* Unregister a trace_uprobe and probe_event */
unregister_trace_uprobe(struct trace_uprobe * tu)393c6c2401dSSteven Rostedt (Red Hat) static int unregister_trace_uprobe(struct trace_uprobe *tu)
394f3f096cfSSrikar Dronamraju {
395c6c2401dSSteven Rostedt (Red Hat) 	int ret;
396c6c2401dSSteven Rostedt (Red Hat) 
39741af3cf5SMasami Hiramatsu 	if (trace_probe_has_sibling(&tu->tp))
39841af3cf5SMasami Hiramatsu 		goto unreg;
39941af3cf5SMasami Hiramatsu 
4001d18538eSSteven Rostedt (VMware) 	/* If there's a reference to the dynamic event */
4011d18538eSSteven Rostedt (VMware) 	if (trace_event_dyn_busy(trace_probe_event_call(&tu->tp)))
4021d18538eSSteven Rostedt (VMware) 		return -EBUSY;
4031d18538eSSteven Rostedt (VMware) 
404c6c2401dSSteven Rostedt (Red Hat) 	ret = unregister_uprobe_event(tu);
405c6c2401dSSteven Rostedt (Red Hat) 	if (ret)
406c6c2401dSSteven Rostedt (Red Hat) 		return ret;
407c6c2401dSSteven Rostedt (Red Hat) 
40841af3cf5SMasami Hiramatsu unreg:
4090597c49cSMasami Hiramatsu 	dyn_event_remove(&tu->devent);
41041af3cf5SMasami Hiramatsu 	trace_probe_unlink(&tu->tp);
411f3f096cfSSrikar Dronamraju 	free_trace_uprobe(tu);
412c6c2401dSSteven Rostedt (Red Hat) 	return 0;
413f3f096cfSSrikar Dronamraju }
414f3f096cfSSrikar Dronamraju 
trace_uprobe_has_same_uprobe(struct trace_uprobe * orig,struct trace_uprobe * comp)415fe60b0ceSMasami Hiramatsu static bool trace_uprobe_has_same_uprobe(struct trace_uprobe *orig,
416fe60b0ceSMasami Hiramatsu 					 struct trace_uprobe *comp)
417fe60b0ceSMasami Hiramatsu {
418fe60b0ceSMasami Hiramatsu 	struct trace_probe_event *tpe = orig->tp.event;
419fe60b0ceSMasami Hiramatsu 	struct inode *comp_inode = d_real_inode(comp->path.dentry);
420fe60b0ceSMasami Hiramatsu 	int i;
421fe60b0ceSMasami Hiramatsu 
422e161c6bfSJiri Olsa 	list_for_each_entry(orig, &tpe->probes, tp.list) {
423fe60b0ceSMasami Hiramatsu 		if (comp_inode != d_real_inode(orig->path.dentry) ||
424fe60b0ceSMasami Hiramatsu 		    comp->offset != orig->offset)
425fe60b0ceSMasami Hiramatsu 			continue;
426fe60b0ceSMasami Hiramatsu 
427fe60b0ceSMasami Hiramatsu 		/*
428fe60b0ceSMasami Hiramatsu 		 * trace_probe_compare_arg_type() ensured that nr_args and
429fe60b0ceSMasami Hiramatsu 		 * each argument name and type are same. Let's compare comm.
430fe60b0ceSMasami Hiramatsu 		 */
431fe60b0ceSMasami Hiramatsu 		for (i = 0; i < orig->tp.nr_args; i++) {
432fe60b0ceSMasami Hiramatsu 			if (strcmp(orig->tp.args[i].comm,
433fe60b0ceSMasami Hiramatsu 				   comp->tp.args[i].comm))
434f8d7ab2bSSrikar Dronamraju 				break;
435fe60b0ceSMasami Hiramatsu 		}
436fe60b0ceSMasami Hiramatsu 
437f8d7ab2bSSrikar Dronamraju 		if (i == orig->tp.nr_args)
438fe60b0ceSMasami Hiramatsu 			return true;
439fe60b0ceSMasami Hiramatsu 	}
440fe60b0ceSMasami Hiramatsu 
441fe60b0ceSMasami Hiramatsu 	return false;
442fe60b0ceSMasami Hiramatsu }
443fe60b0ceSMasami Hiramatsu 
append_trace_uprobe(struct trace_uprobe * tu,struct trace_uprobe * to)44441af3cf5SMasami Hiramatsu static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprobe *to)
44541af3cf5SMasami Hiramatsu {
44641af3cf5SMasami Hiramatsu 	int ret;
44741af3cf5SMasami Hiramatsu 
448fe60b0ceSMasami Hiramatsu 	ret = trace_probe_compare_arg_type(&tu->tp, &to->tp);
449fe60b0ceSMasami Hiramatsu 	if (ret) {
450fe60b0ceSMasami Hiramatsu 		/* Note that argument starts index = 2 */
451fe60b0ceSMasami Hiramatsu 		trace_probe_log_set_index(ret + 1);
452fe60b0ceSMasami Hiramatsu 		trace_probe_log_err(0, DIFF_ARG_TYPE);
453fe60b0ceSMasami Hiramatsu 		return -EEXIST;
454fe60b0ceSMasami Hiramatsu 	}
455fe60b0ceSMasami Hiramatsu 	if (trace_uprobe_has_same_uprobe(to, tu)) {
456fe60b0ceSMasami Hiramatsu 		trace_probe_log_set_index(0);
457fe60b0ceSMasami Hiramatsu 		trace_probe_log_err(0, SAME_PROBE);
458fe60b0ceSMasami Hiramatsu 		return -EEXIST;
459fe60b0ceSMasami Hiramatsu 	}
460fe60b0ceSMasami Hiramatsu 
46141af3cf5SMasami Hiramatsu 	/* Append to existing event */
46241af3cf5SMasami Hiramatsu 	ret = trace_probe_append(&tu->tp, &to->tp);
46341af3cf5SMasami Hiramatsu 	if (!ret)
4648b0e6c74SSteven Rostedt (VMware) 		dyn_event_add(&tu->devent, trace_probe_event_call(&tu->tp));
46541af3cf5SMasami Hiramatsu 
46641af3cf5SMasami Hiramatsu 	return ret;
46741af3cf5SMasami Hiramatsu }
46841af3cf5SMasami Hiramatsu 
469ccea8727SRavi Bangoria /*
470ccea8727SRavi Bangoria  * Uprobe with multiple reference counter is not allowed. i.e.
471ccea8727SRavi Bangoria  * If inode and offset matches, reference counter offset *must*
472ccea8727SRavi Bangoria  * match as well. Though, there is one exception: If user is
473ccea8727SRavi Bangoria  * replacing old trace_uprobe with new one(same group/event),
474ccea8727SRavi Bangoria  * then we allow same uprobe with new reference counter as far
475ccea8727SRavi Bangoria  * as the new one does not conflict with any other existing
476ccea8727SRavi Bangoria  * ones.
477ccea8727SRavi Bangoria  */
validate_ref_ctr_offset(struct trace_uprobe * new)47841af3cf5SMasami Hiramatsu static int validate_ref_ctr_offset(struct trace_uprobe *new)
479ccea8727SRavi Bangoria {
4800597c49cSMasami Hiramatsu 	struct dyn_event *pos;
48141af3cf5SMasami Hiramatsu 	struct trace_uprobe *tmp;
482ccea8727SRavi Bangoria 	struct inode *new_inode = d_real_inode(new->path.dentry);
483ccea8727SRavi Bangoria 
4840597c49cSMasami Hiramatsu 	for_each_trace_uprobe(tmp, pos) {
48541af3cf5SMasami Hiramatsu 		if (new_inode == d_real_inode(tmp->path.dentry) &&
486ccea8727SRavi Bangoria 		    new->offset == tmp->offset &&
487ccea8727SRavi Bangoria 		    new->ref_ctr_offset != tmp->ref_ctr_offset) {
488ccea8727SRavi Bangoria 			pr_warn("Reference counter offset mismatch.");
48941af3cf5SMasami Hiramatsu 			return -EINVAL;
490ccea8727SRavi Bangoria 		}
491ccea8727SRavi Bangoria 	}
49241af3cf5SMasami Hiramatsu 	return 0;
493ccea8727SRavi Bangoria }
494ccea8727SRavi Bangoria 
495f3f096cfSSrikar Dronamraju /* Register a trace_uprobe and probe_event */
register_trace_uprobe(struct trace_uprobe * tu)496f3f096cfSSrikar Dronamraju static int register_trace_uprobe(struct trace_uprobe *tu)
497f3f096cfSSrikar Dronamraju {
49814577c39SNamhyung Kim 	struct trace_uprobe *old_tu;
499f3f096cfSSrikar Dronamraju 	int ret;
500f3f096cfSSrikar Dronamraju 
501f8821732SMasami Hiramatsu (Google) 	guard(mutex)(&event_mutex);
502f3f096cfSSrikar Dronamraju 
50341af3cf5SMasami Hiramatsu 	ret = validate_ref_ctr_offset(tu);
504c6c2401dSSteven Rostedt (Red Hat) 	if (ret)
505f8821732SMasami Hiramatsu (Google) 		return ret;
50641af3cf5SMasami Hiramatsu 
50741af3cf5SMasami Hiramatsu 	/* register as an event */
50841af3cf5SMasami Hiramatsu 	old_tu = find_probe_event(trace_probe_name(&tu->tp),
50941af3cf5SMasami Hiramatsu 				  trace_probe_group_name(&tu->tp));
51041af3cf5SMasami Hiramatsu 	if (old_tu) {
51141af3cf5SMasami Hiramatsu 		if (is_ret_probe(tu) != is_ret_probe(old_tu)) {
51241af3cf5SMasami Hiramatsu 			trace_probe_log_set_index(0);
51341af3cf5SMasami Hiramatsu 			trace_probe_log_err(0, DIFF_PROBE_TYPE);
514f8821732SMasami Hiramatsu (Google) 			return -EEXIST;
51541af3cf5SMasami Hiramatsu 		}
516f8821732SMasami Hiramatsu (Google) 		return append_trace_uprobe(tu, old_tu);
517c6c2401dSSteven Rostedt (Red Hat) 	}
518f3f096cfSSrikar Dronamraju 
519f3f096cfSSrikar Dronamraju 	ret = register_uprobe_event(tu);
520f3f096cfSSrikar Dronamraju 	if (ret) {
5218e242060SMasami Hiramatsu 		if (ret == -EEXIST) {
5228e242060SMasami Hiramatsu 			trace_probe_log_set_index(0);
5238e242060SMasami Hiramatsu 			trace_probe_log_err(0, EVENT_EXIST);
5248e242060SMasami Hiramatsu 		} else
525a395d6a7SJoe Perches 			pr_warn("Failed to register probe event(%d)\n", ret);
526f8821732SMasami Hiramatsu (Google) 		return ret;
527f3f096cfSSrikar Dronamraju 	}
528f3f096cfSSrikar Dronamraju 
5298b0e6c74SSteven Rostedt (VMware) 	dyn_event_add(&tu->devent, trace_probe_event_call(&tu->tp));
530f3f096cfSSrikar Dronamraju 
531f3f096cfSSrikar Dronamraju 	return ret;
532f3f096cfSSrikar Dronamraju }
533f3f096cfSSrikar Dronamraju 
534f3f096cfSSrikar Dronamraju /*
535f3f096cfSSrikar Dronamraju  * Argument syntax:
53695c104c3SLinyu Yuan  *  - Add uprobe: p|r[:[GRP/][EVENT]] PATH:OFFSET[%return][(REF)] [FETCHARGS]
537f3f096cfSSrikar Dronamraju  */
__trace_uprobe_create(int argc,const char ** argv)538d262271dSMasami Hiramatsu static int __trace_uprobe_create(int argc, const char **argv)
539f3f096cfSSrikar Dronamraju {
540f3f096cfSSrikar Dronamraju 	struct trace_uprobe *tu;
5410597c49cSMasami Hiramatsu 	const char *event = NULL, *group = UPROBE_EVENT_SYSTEM;
5420597c49cSMasami Hiramatsu 	char *arg, *filename, *rctr, *rctr_end, *tmp;
543f3f096cfSSrikar Dronamraju 	char buf[MAX_EVENT_NAME_LEN];
54495c104c3SLinyu Yuan 	char gbuf[MAX_EVENT_NAME_LEN];
545007517a0SSteven Rostedt (VMware) 	enum probe_print_type ptype;
546f3f096cfSSrikar Dronamraju 	struct path path;
5471cc33161SRavi Bangoria 	unsigned long offset, ref_ctr_offset;
5480597c49cSMasami Hiramatsu 	bool is_return = false;
549f3f096cfSSrikar Dronamraju 	int i, ret;
550f3f096cfSSrikar Dronamraju 
5511cc33161SRavi Bangoria 	ref_ctr_offset = 0;
552f3f096cfSSrikar Dronamraju 
553f01098c7SEiichi Tsukata 	switch (argv[0][0]) {
554f01098c7SEiichi Tsukata 	case 'r':
5554ee5a52eSOleg Nesterov 		is_return = true;
556f01098c7SEiichi Tsukata 		break;
557f01098c7SEiichi Tsukata 	case 'p':
558f01098c7SEiichi Tsukata 		break;
559f01098c7SEiichi Tsukata 	default:
560f01098c7SEiichi Tsukata 		return -ECANCELED;
561f01098c7SEiichi Tsukata 	}
562f01098c7SEiichi Tsukata 
563f01098c7SEiichi Tsukata 	if (argc < 2)
5640597c49cSMasami Hiramatsu 		return -ECANCELED;
56557faaa04SMasami Hiramatsu (Google) 
56657faaa04SMasami Hiramatsu (Google) 	trace_probe_log_init("trace_uprobe", argc, argv);
56757faaa04SMasami Hiramatsu (Google) 
56857faaa04SMasami Hiramatsu (Google) 	if (argc - 2 > MAX_TRACE_ARGS) {
56957faaa04SMasami Hiramatsu (Google) 		trace_probe_log_set_index(2);
57057faaa04SMasami Hiramatsu (Google) 		trace_probe_log_err(0, TOO_MANY_ARGS);
57173f35080SMikel Rychliski 		return -E2BIG;
57257faaa04SMasami Hiramatsu (Google) 	}
573f3f096cfSSrikar Dronamraju 
5740597c49cSMasami Hiramatsu 	if (argv[0][1] == ':')
575f3f096cfSSrikar Dronamraju 		event = &argv[0][2];
576f3f096cfSSrikar Dronamraju 
5770597c49cSMasami Hiramatsu 	if (!strchr(argv[1], '/'))
5780597c49cSMasami Hiramatsu 		return -ECANCELED;
579f3f096cfSSrikar Dronamraju 
5800597c49cSMasami Hiramatsu 	filename = kstrdup(argv[1], GFP_KERNEL);
5810597c49cSMasami Hiramatsu 	if (!filename)
5820597c49cSMasami Hiramatsu 		return -ENOMEM;
583f3f096cfSSrikar Dronamraju 
5846496bb72SKenny Yu 	/* Find the last occurrence, in case the path contains ':' too. */
5850597c49cSMasami Hiramatsu 	arg = strrchr(filename, ':');
5860597c49cSMasami Hiramatsu 	if (!arg || !isdigit(arg[1])) {
5870597c49cSMasami Hiramatsu 		kfree(filename);
5880597c49cSMasami Hiramatsu 		return -ECANCELED;
5890597c49cSMasami Hiramatsu 	}
590f3f096cfSSrikar Dronamraju 
591ab105a4fSMasami Hiramatsu 	trace_probe_log_set_index(1);	/* filename is the 2nd argument */
592ab105a4fSMasami Hiramatsu 
593f3f096cfSSrikar Dronamraju 	*arg++ = '\0';
594f3f096cfSSrikar Dronamraju 	ret = kern_path(filename, LOOKUP_FOLLOW, &path);
5950597c49cSMasami Hiramatsu 	if (ret) {
596ab105a4fSMasami Hiramatsu 		trace_probe_log_err(0, FILE_NOT_FOUND);
5970597c49cSMasami Hiramatsu 		kfree(filename);
598ab105a4fSMasami Hiramatsu 		trace_probe_log_clear();
5990c92c7a3SSong Liu 		return ret;
6000597c49cSMasami Hiramatsu 	}
6010c92c7a3SSong Liu 	if (!d_is_reg(path.dentry)) {
602ab105a4fSMasami Hiramatsu 		trace_probe_log_err(0, NO_REGULAR_FILE);
603d24d7dbfSJovi Zhang 		ret = -EINVAL;
604d24d7dbfSJovi Zhang 		goto fail_address_parse;
605d24d7dbfSJovi Zhang 	}
606f3f096cfSSrikar Dronamraju 
6071cc33161SRavi Bangoria 	/* Parse reference counter offset if specified. */
6081cc33161SRavi Bangoria 	rctr = strchr(arg, '(');
6091cc33161SRavi Bangoria 	if (rctr) {
6101cc33161SRavi Bangoria 		rctr_end = strchr(rctr, ')');
611ab105a4fSMasami Hiramatsu 		if (!rctr_end) {
6121cc33161SRavi Bangoria 			ret = -EINVAL;
613ab105a4fSMasami Hiramatsu 			rctr_end = rctr + strlen(rctr);
614ab105a4fSMasami Hiramatsu 			trace_probe_log_err(rctr_end - filename,
615ab105a4fSMasami Hiramatsu 					    REFCNT_OPEN_BRACE);
616ab105a4fSMasami Hiramatsu 			goto fail_address_parse;
617ab105a4fSMasami Hiramatsu 		} else if (rctr_end[1] != '\0') {
618ab105a4fSMasami Hiramatsu 			ret = -EINVAL;
619ab105a4fSMasami Hiramatsu 			trace_probe_log_err(rctr_end + 1 - filename,
620ab105a4fSMasami Hiramatsu 					    BAD_REFCNT_SUFFIX);
6211cc33161SRavi Bangoria 			goto fail_address_parse;
6221cc33161SRavi Bangoria 		}
6231cc33161SRavi Bangoria 
6241cc33161SRavi Bangoria 		*rctr++ = '\0';
6251cc33161SRavi Bangoria 		*rctr_end = '\0';
6261cc33161SRavi Bangoria 		ret = kstrtoul(rctr, 0, &ref_ctr_offset);
6271cc33161SRavi Bangoria 		if (ret) {
628ab105a4fSMasami Hiramatsu 			trace_probe_log_err(rctr - filename, BAD_REFCNT);
6291cc33161SRavi Bangoria 			goto fail_address_parse;
6301cc33161SRavi Bangoria 		}
6311cc33161SRavi Bangoria 	}
6321cc33161SRavi Bangoria 
6333dd3aae3SMasami Hiramatsu 	/* Check if there is %return suffix */
6343dd3aae3SMasami Hiramatsu 	tmp = strchr(arg, '%');
6353dd3aae3SMasami Hiramatsu 	if (tmp) {
6363dd3aae3SMasami Hiramatsu 		if (!strcmp(tmp, "%return")) {
6373dd3aae3SMasami Hiramatsu 			*tmp = '\0';
6383dd3aae3SMasami Hiramatsu 			is_return = true;
6393dd3aae3SMasami Hiramatsu 		} else {
6403dd3aae3SMasami Hiramatsu 			trace_probe_log_err(tmp - filename, BAD_ADDR_SUFFIX);
6413dd3aae3SMasami Hiramatsu 			ret = -EINVAL;
6423dd3aae3SMasami Hiramatsu 			goto fail_address_parse;
6433dd3aae3SMasami Hiramatsu 		}
6443dd3aae3SMasami Hiramatsu 	}
6453dd3aae3SMasami Hiramatsu 
6461cc33161SRavi Bangoria 	/* Parse uprobe offset. */
64784d7ed79SOleg Nesterov 	ret = kstrtoul(arg, 0, &offset);
648ab105a4fSMasami Hiramatsu 	if (ret) {
649ab105a4fSMasami Hiramatsu 		trace_probe_log_err(arg - filename, BAD_UPROBE_OFFS);
65084d7ed79SOleg Nesterov 		goto fail_address_parse;
651ab105a4fSMasami Hiramatsu 	}
652f3f096cfSSrikar Dronamraju 
653f3f096cfSSrikar Dronamraju 	/* setup a probe */
654ab105a4fSMasami Hiramatsu 	trace_probe_log_set_index(0);
6550597c49cSMasami Hiramatsu 	if (event) {
65695c104c3SLinyu Yuan 		ret = traceprobe_parse_event_name(&event, &group, gbuf,
657ab105a4fSMasami Hiramatsu 						  event - argv[0]);
6580597c49cSMasami Hiramatsu 		if (ret)
6590597c49cSMasami Hiramatsu 			goto fail_address_parse;
66095c104c3SLinyu Yuan 	}
66195c104c3SLinyu Yuan 
66295c104c3SLinyu Yuan 	if (!event) {
663b2e902f0SAndy Shevchenko 		char *tail;
664f3f096cfSSrikar Dronamraju 		char *ptr;
665f3f096cfSSrikar Dronamraju 
666b2e902f0SAndy Shevchenko 		tail = kstrdup(kbasename(filename), GFP_KERNEL);
667b2e902f0SAndy Shevchenko 		if (!tail) {
668f3f096cfSSrikar Dronamraju 			ret = -ENOMEM;
669f3f096cfSSrikar Dronamraju 			goto fail_address_parse;
670f3f096cfSSrikar Dronamraju 		}
671f3f096cfSSrikar Dronamraju 
672f3f096cfSSrikar Dronamraju 		ptr = strpbrk(tail, ".-_");
673f3f096cfSSrikar Dronamraju 		if (ptr)
674f3f096cfSSrikar Dronamraju 			*ptr = '\0';
675f3f096cfSSrikar Dronamraju 
676f3f096cfSSrikar Dronamraju 		snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_0x%lx", 'p', tail, offset);
677f3f096cfSSrikar Dronamraju 		event = buf;
678f3f096cfSSrikar Dronamraju 		kfree(tail);
679f3f096cfSSrikar Dronamraju 	}
680f3f096cfSSrikar Dronamraju 
681ab105a4fSMasami Hiramatsu 	argc -= 2;
682ab105a4fSMasami Hiramatsu 	argv += 2;
683ab105a4fSMasami Hiramatsu 
6844ee5a52eSOleg Nesterov 	tu = alloc_trace_uprobe(group, event, argc, is_return);
685f3f096cfSSrikar Dronamraju 	if (IS_ERR(tu)) {
686f3f096cfSSrikar Dronamraju 		ret = PTR_ERR(tu);
687a039480eSMasami Hiramatsu 		/* This must return -ENOMEM otherwise there is a bug */
688a039480eSMasami Hiramatsu 		WARN_ON_ONCE(ret != -ENOMEM);
689f3f096cfSSrikar Dronamraju 		goto fail_address_parse;
690f3f096cfSSrikar Dronamraju 	}
691f3f096cfSSrikar Dronamraju 	tu->offset = offset;
6921cc33161SRavi Bangoria 	tu->ref_ctr_offset = ref_ctr_offset;
6930c92c7a3SSong Liu 	tu->path = path;
6940597c49cSMasami Hiramatsu 	tu->filename = filename;
695f3f096cfSSrikar Dronamraju 
6960597c49cSMasami Hiramatsu 	/* parse arguments */
69773f35080SMikel Rychliski 	for (i = 0; i < argc; i++) {
6981b8b0cd7SMasami Hiramatsu (Google) 		struct traceprobe_parse_context ctx = {
6991b8b0cd7SMasami Hiramatsu (Google) 			.flags = (is_return ? TPARG_FL_RETURN : 0) | TPARG_FL_USER,
7001b8b0cd7SMasami Hiramatsu (Google) 		};
7011b8b0cd7SMasami Hiramatsu (Google) 
702ab105a4fSMasami Hiramatsu 		trace_probe_log_set_index(i + 2);
7031b8b0cd7SMasami Hiramatsu (Google) 		ret = traceprobe_parse_probe_arg(&tu->tp, i, argv[i], &ctx);
704b1d1e904SMasami Hiramatsu (Google) 		traceprobe_finish_parse(&ctx);
705d00bbea9SMasami Hiramatsu 		if (ret)
706f3f096cfSSrikar Dronamraju 			goto error;
707f3f096cfSSrikar Dronamraju 	}
708f3f096cfSSrikar Dronamraju 
709007517a0SSteven Rostedt (VMware) 	ptype = is_ret_probe(tu) ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
710007517a0SSteven Rostedt (VMware) 	ret = traceprobe_set_print_fmt(&tu->tp, ptype);
711b4d4b96bSMasami Hiramatsu 	if (ret < 0)
712b4d4b96bSMasami Hiramatsu 		goto error;
713b4d4b96bSMasami Hiramatsu 
714f3f096cfSSrikar Dronamraju 	ret = register_trace_uprobe(tu);
715ab105a4fSMasami Hiramatsu 	if (!ret)
716ab105a4fSMasami Hiramatsu 		goto out;
717f3f096cfSSrikar Dronamraju 
718f3f096cfSSrikar Dronamraju error:
719f3f096cfSSrikar Dronamraju 	free_trace_uprobe(tu);
720ab105a4fSMasami Hiramatsu out:
721ab105a4fSMasami Hiramatsu 	trace_probe_log_clear();
722f3f096cfSSrikar Dronamraju 	return ret;
723f3f096cfSSrikar Dronamraju 
724f3f096cfSSrikar Dronamraju fail_address_parse:
725ab105a4fSMasami Hiramatsu 	trace_probe_log_clear();
7260c92c7a3SSong Liu 	path_put(&path);
7270597c49cSMasami Hiramatsu 	kfree(filename);
728f3f096cfSSrikar Dronamraju 
729f3f096cfSSrikar Dronamraju 	return ret;
730f3f096cfSSrikar Dronamraju }
731f3f096cfSSrikar Dronamraju 
trace_uprobe_create(const char * raw_command)732d262271dSMasami Hiramatsu int trace_uprobe_create(const char *raw_command)
733d262271dSMasami Hiramatsu {
734d262271dSMasami Hiramatsu 	return trace_probe_create(raw_command, __trace_uprobe_create);
735d262271dSMasami Hiramatsu }
736d262271dSMasami Hiramatsu 
create_or_delete_trace_uprobe(const char * raw_command)737d262271dSMasami Hiramatsu static int create_or_delete_trace_uprobe(const char *raw_command)
738f3f096cfSSrikar Dronamraju {
7390597c49cSMasami Hiramatsu 	int ret;
740f3f096cfSSrikar Dronamraju 
741d262271dSMasami Hiramatsu 	if (raw_command[0] == '-')
742d262271dSMasami Hiramatsu 		return dyn_event_release(raw_command, &trace_uprobe_ops);
7430597c49cSMasami Hiramatsu 
744*fd837de3SMasami Hiramatsu (Google) 	ret = dyn_event_create(raw_command, &trace_uprobe_ops);
7450597c49cSMasami Hiramatsu 	return ret == -ECANCELED ? -EINVAL : ret;
746547cd9eaSMasami Hiramatsu }
7470597c49cSMasami Hiramatsu 
trace_uprobe_release(struct dyn_event * ev)7480597c49cSMasami Hiramatsu static int trace_uprobe_release(struct dyn_event *ev)
7490597c49cSMasami Hiramatsu {
7500597c49cSMasami Hiramatsu 	struct trace_uprobe *tu = to_trace_uprobe(ev);
7510597c49cSMasami Hiramatsu 
7520597c49cSMasami Hiramatsu 	return unregister_trace_uprobe(tu);
753f3f096cfSSrikar Dronamraju }
754f3f096cfSSrikar Dronamraju 
755f3f096cfSSrikar Dronamraju /* Probes listing interfaces */
trace_uprobe_show(struct seq_file * m,struct dyn_event * ev)7560597c49cSMasami Hiramatsu static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
757f3f096cfSSrikar Dronamraju {
7580597c49cSMasami Hiramatsu 	struct trace_uprobe *tu = to_trace_uprobe(ev);
7593ede82ddSOleg Nesterov 	char c = is_ret_probe(tu) ? 'r' : 'p';
760f3f096cfSSrikar Dronamraju 	int i;
761f3f096cfSSrikar Dronamraju 
762b55ce203SMasami Hiramatsu 	seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, trace_probe_group_name(&tu->tp),
763b55ce203SMasami Hiramatsu 			trace_probe_name(&tu->tp), tu->filename,
764a64b2c01SRavi Bangoria 			(int)(sizeof(void *) * 2), tu->offset);
765f3f096cfSSrikar Dronamraju 
7661cc33161SRavi Bangoria 	if (tu->ref_ctr_offset)
7671cc33161SRavi Bangoria 		seq_printf(m, "(0x%lx)", tu->ref_ctr_offset);
7681cc33161SRavi Bangoria 
76914577c39SNamhyung Kim 	for (i = 0; i < tu->tp.nr_args; i++)
77014577c39SNamhyung Kim 		seq_printf(m, " %s=%s", tu->tp.args[i].name, tu->tp.args[i].comm);
771f3f096cfSSrikar Dronamraju 
772fa6f0cc7SRasmus Villemoes 	seq_putc(m, '\n');
773f3f096cfSSrikar Dronamraju 	return 0;
774f3f096cfSSrikar Dronamraju }
775f3f096cfSSrikar Dronamraju 
probes_seq_show(struct seq_file * m,void * v)7760597c49cSMasami Hiramatsu static int probes_seq_show(struct seq_file *m, void *v)
7770597c49cSMasami Hiramatsu {
7780597c49cSMasami Hiramatsu 	struct dyn_event *ev = v;
7790597c49cSMasami Hiramatsu 
7800597c49cSMasami Hiramatsu 	if (!is_trace_uprobe(ev))
7810597c49cSMasami Hiramatsu 		return 0;
7820597c49cSMasami Hiramatsu 
7830597c49cSMasami Hiramatsu 	return trace_uprobe_show(m, ev);
7840597c49cSMasami Hiramatsu }
7850597c49cSMasami Hiramatsu 
786f3f096cfSSrikar Dronamraju static const struct seq_operations probes_seq_op = {
7870597c49cSMasami Hiramatsu 	.start  = dyn_event_seq_start,
7880597c49cSMasami Hiramatsu 	.next   = dyn_event_seq_next,
7890597c49cSMasami Hiramatsu 	.stop   = dyn_event_seq_stop,
790f3f096cfSSrikar Dronamraju 	.show   = probes_seq_show
791f3f096cfSSrikar Dronamraju };
792f3f096cfSSrikar Dronamraju 
probes_open(struct inode * inode,struct file * file)793f3f096cfSSrikar Dronamraju static int probes_open(struct inode *inode, struct file *file)
794f3f096cfSSrikar Dronamraju {
795c6c2401dSSteven Rostedt (Red Hat) 	int ret;
796c6c2401dSSteven Rostedt (Red Hat) 
79717911ff3SSteven Rostedt (VMware) 	ret = security_locked_down(LOCKDOWN_TRACEFS);
79817911ff3SSteven Rostedt (VMware) 	if (ret)
79917911ff3SSteven Rostedt (VMware) 		return ret;
80017911ff3SSteven Rostedt (VMware) 
801c6c2401dSSteven Rostedt (Red Hat) 	if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
8020597c49cSMasami Hiramatsu 		ret = dyn_events_release_all(&trace_uprobe_ops);
803c6c2401dSSteven Rostedt (Red Hat) 		if (ret)
804c6c2401dSSteven Rostedt (Red Hat) 			return ret;
805c6c2401dSSteven Rostedt (Red Hat) 	}
806f3f096cfSSrikar Dronamraju 
807f3f096cfSSrikar Dronamraju 	return seq_open(file, &probes_seq_op);
808f3f096cfSSrikar Dronamraju }
809f3f096cfSSrikar Dronamraju 
probes_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)810f3f096cfSSrikar Dronamraju static ssize_t probes_write(struct file *file, const char __user *buffer,
811f3f096cfSSrikar Dronamraju 			    size_t count, loff_t *ppos)
812f3f096cfSSrikar Dronamraju {
8130597c49cSMasami Hiramatsu 	return trace_parse_run_command(file, buffer, count, ppos,
8140597c49cSMasami Hiramatsu 					create_or_delete_trace_uprobe);
815f3f096cfSSrikar Dronamraju }
816f3f096cfSSrikar Dronamraju 
817f3f096cfSSrikar Dronamraju static const struct file_operations uprobe_events_ops = {
818f3f096cfSSrikar Dronamraju 	.owner		= THIS_MODULE,
819f3f096cfSSrikar Dronamraju 	.open		= probes_open,
820f3f096cfSSrikar Dronamraju 	.read		= seq_read,
821f3f096cfSSrikar Dronamraju 	.llseek		= seq_lseek,
822f3f096cfSSrikar Dronamraju 	.release	= seq_release,
823f3f096cfSSrikar Dronamraju 	.write		= probes_write,
824f3f096cfSSrikar Dronamraju };
825f3f096cfSSrikar Dronamraju 
826f3f096cfSSrikar Dronamraju /* Probes profiling interfaces */
probes_profile_seq_show(struct seq_file * m,void * v)827f3f096cfSSrikar Dronamraju static int probes_profile_seq_show(struct seq_file *m, void *v)
828f3f096cfSSrikar Dronamraju {
8290597c49cSMasami Hiramatsu 	struct dyn_event *ev = v;
8300597c49cSMasami Hiramatsu 	struct trace_uprobe *tu;
83110cdb82aSAndrii Nakryiko 	unsigned long nhits;
83210cdb82aSAndrii Nakryiko 	int cpu;
833f3f096cfSSrikar Dronamraju 
8340597c49cSMasami Hiramatsu 	if (!is_trace_uprobe(ev))
8350597c49cSMasami Hiramatsu 		return 0;
8360597c49cSMasami Hiramatsu 
8370597c49cSMasami Hiramatsu 	tu = to_trace_uprobe(ev);
83810cdb82aSAndrii Nakryiko 
83910cdb82aSAndrii Nakryiko 	nhits = 0;
84010cdb82aSAndrii Nakryiko 	for_each_possible_cpu(cpu) {
84110cdb82aSAndrii Nakryiko 		nhits += per_cpu(*tu->nhits, cpu);
84210cdb82aSAndrii Nakryiko 	}
84310cdb82aSAndrii Nakryiko 
844de7b2973SMathieu Desnoyers 	seq_printf(m, "  %s %-44s %15lu\n", tu->filename,
84510cdb82aSAndrii Nakryiko 		   trace_probe_name(&tu->tp), nhits);
846f3f096cfSSrikar Dronamraju 	return 0;
847f3f096cfSSrikar Dronamraju }
848f3f096cfSSrikar Dronamraju 
849f3f096cfSSrikar Dronamraju static const struct seq_operations profile_seq_op = {
8500597c49cSMasami Hiramatsu 	.start  = dyn_event_seq_start,
8510597c49cSMasami Hiramatsu 	.next   = dyn_event_seq_next,
8520597c49cSMasami Hiramatsu 	.stop   = dyn_event_seq_stop,
853f3f096cfSSrikar Dronamraju 	.show	= probes_profile_seq_show
854f3f096cfSSrikar Dronamraju };
855f3f096cfSSrikar Dronamraju 
profile_open(struct inode * inode,struct file * file)856f3f096cfSSrikar Dronamraju static int profile_open(struct inode *inode, struct file *file)
857f3f096cfSSrikar Dronamraju {
85817911ff3SSteven Rostedt (VMware) 	int ret;
85917911ff3SSteven Rostedt (VMware) 
86017911ff3SSteven Rostedt (VMware) 	ret = security_locked_down(LOCKDOWN_TRACEFS);
86117911ff3SSteven Rostedt (VMware) 	if (ret)
86217911ff3SSteven Rostedt (VMware) 		return ret;
86317911ff3SSteven Rostedt (VMware) 
864f3f096cfSSrikar Dronamraju 	return seq_open(file, &profile_seq_op);
865f3f096cfSSrikar Dronamraju }
866f3f096cfSSrikar Dronamraju 
867f3f096cfSSrikar Dronamraju static const struct file_operations uprobe_profile_ops = {
868f3f096cfSSrikar Dronamraju 	.owner		= THIS_MODULE,
869f3f096cfSSrikar Dronamraju 	.open		= profile_open,
870f3f096cfSSrikar Dronamraju 	.read		= seq_read,
871f3f096cfSSrikar Dronamraju 	.llseek		= seq_lseek,
872f3f096cfSSrikar Dronamraju 	.release	= seq_release,
873f3f096cfSSrikar Dronamraju };
874f3f096cfSSrikar Dronamraju 
875dcad1a20SNamhyung Kim struct uprobe_cpu_buffer {
876dcad1a20SNamhyung Kim 	struct mutex mutex;
877dcad1a20SNamhyung Kim 	void *buf;
8783eaea21bSAndrii Nakryiko 	int dsize;
879dcad1a20SNamhyung Kim };
880dcad1a20SNamhyung Kim static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer;
881dcad1a20SNamhyung Kim static int uprobe_buffer_refcnt;
882373b9338SQiao Ma #define MAX_UCB_BUFFER_SIZE PAGE_SIZE
883dcad1a20SNamhyung Kim 
uprobe_buffer_init(void)884dcad1a20SNamhyung Kim static int uprobe_buffer_init(void)
885dcad1a20SNamhyung Kim {
886dcad1a20SNamhyung Kim 	int cpu, err_cpu;
887dcad1a20SNamhyung Kim 
888dcad1a20SNamhyung Kim 	uprobe_cpu_buffer = alloc_percpu(struct uprobe_cpu_buffer);
889dcad1a20SNamhyung Kim 	if (uprobe_cpu_buffer == NULL)
890dcad1a20SNamhyung Kim 		return -ENOMEM;
891dcad1a20SNamhyung Kim 
892dcad1a20SNamhyung Kim 	for_each_possible_cpu(cpu) {
893dcad1a20SNamhyung Kim 		struct page *p = alloc_pages_node(cpu_to_node(cpu),
894dcad1a20SNamhyung Kim 						  GFP_KERNEL, 0);
895dcad1a20SNamhyung Kim 		if (p == NULL) {
896dcad1a20SNamhyung Kim 			err_cpu = cpu;
897dcad1a20SNamhyung Kim 			goto err;
898dcad1a20SNamhyung Kim 		}
899dcad1a20SNamhyung Kim 		per_cpu_ptr(uprobe_cpu_buffer, cpu)->buf = page_address(p);
900dcad1a20SNamhyung Kim 		mutex_init(&per_cpu_ptr(uprobe_cpu_buffer, cpu)->mutex);
901dcad1a20SNamhyung Kim 	}
902dcad1a20SNamhyung Kim 
903dcad1a20SNamhyung Kim 	return 0;
904dcad1a20SNamhyung Kim 
905dcad1a20SNamhyung Kim err:
906dcad1a20SNamhyung Kim 	for_each_possible_cpu(cpu) {
907dcad1a20SNamhyung Kim 		if (cpu == err_cpu)
908dcad1a20SNamhyung Kim 			break;
909dcad1a20SNamhyung Kim 		free_page((unsigned long)per_cpu_ptr(uprobe_cpu_buffer, cpu)->buf);
910dcad1a20SNamhyung Kim 	}
911dcad1a20SNamhyung Kim 
912dcad1a20SNamhyung Kim 	free_percpu(uprobe_cpu_buffer);
913dcad1a20SNamhyung Kim 	return -ENOMEM;
914dcad1a20SNamhyung Kim }
915dcad1a20SNamhyung Kim 
uprobe_buffer_enable(void)916dcad1a20SNamhyung Kim static int uprobe_buffer_enable(void)
917dcad1a20SNamhyung Kim {
918dcad1a20SNamhyung Kim 	int ret = 0;
919dcad1a20SNamhyung Kim 
920dcad1a20SNamhyung Kim 	BUG_ON(!mutex_is_locked(&event_mutex));
921dcad1a20SNamhyung Kim 
922dcad1a20SNamhyung Kim 	if (uprobe_buffer_refcnt++ == 0) {
923dcad1a20SNamhyung Kim 		ret = uprobe_buffer_init();
924dcad1a20SNamhyung Kim 		if (ret < 0)
925dcad1a20SNamhyung Kim 			uprobe_buffer_refcnt--;
926dcad1a20SNamhyung Kim 	}
927dcad1a20SNamhyung Kim 
928dcad1a20SNamhyung Kim 	return ret;
929dcad1a20SNamhyung Kim }
930dcad1a20SNamhyung Kim 
uprobe_buffer_disable(void)931dcad1a20SNamhyung Kim static void uprobe_buffer_disable(void)
932dcad1a20SNamhyung Kim {
9336ea6215fSzhangwei(Jovi) 	int cpu;
9346ea6215fSzhangwei(Jovi) 
935dcad1a20SNamhyung Kim 	BUG_ON(!mutex_is_locked(&event_mutex));
936dcad1a20SNamhyung Kim 
937dcad1a20SNamhyung Kim 	if (--uprobe_buffer_refcnt == 0) {
9386ea6215fSzhangwei(Jovi) 		for_each_possible_cpu(cpu)
9396ea6215fSzhangwei(Jovi) 			free_page((unsigned long)per_cpu_ptr(uprobe_cpu_buffer,
9406ea6215fSzhangwei(Jovi) 							     cpu)->buf);
9416ea6215fSzhangwei(Jovi) 
942dcad1a20SNamhyung Kim 		free_percpu(uprobe_cpu_buffer);
943dcad1a20SNamhyung Kim 		uprobe_cpu_buffer = NULL;
944dcad1a20SNamhyung Kim 	}
945dcad1a20SNamhyung Kim }
946dcad1a20SNamhyung Kim 
uprobe_buffer_get(void)947dcad1a20SNamhyung Kim static struct uprobe_cpu_buffer *uprobe_buffer_get(void)
948dcad1a20SNamhyung Kim {
949dcad1a20SNamhyung Kim 	struct uprobe_cpu_buffer *ucb;
950dcad1a20SNamhyung Kim 	int cpu;
951dcad1a20SNamhyung Kim 
952dcad1a20SNamhyung Kim 	cpu = raw_smp_processor_id();
953dcad1a20SNamhyung Kim 	ucb = per_cpu_ptr(uprobe_cpu_buffer, cpu);
954dcad1a20SNamhyung Kim 
955dcad1a20SNamhyung Kim 	/*
956dcad1a20SNamhyung Kim 	 * Use per-cpu buffers for fastest access, but we might migrate
957dcad1a20SNamhyung Kim 	 * so the mutex makes sure we have sole access to it.
958dcad1a20SNamhyung Kim 	 */
959dcad1a20SNamhyung Kim 	mutex_lock(&ucb->mutex);
960dcad1a20SNamhyung Kim 
961dcad1a20SNamhyung Kim 	return ucb;
962dcad1a20SNamhyung Kim }
963dcad1a20SNamhyung Kim 
uprobe_buffer_put(struct uprobe_cpu_buffer * ucb)964dcad1a20SNamhyung Kim static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb)
965dcad1a20SNamhyung Kim {
9661b8f85deSAndrii Nakryiko 	if (!ucb)
9671b8f85deSAndrii Nakryiko 		return;
968dcad1a20SNamhyung Kim 	mutex_unlock(&ucb->mutex);
969dcad1a20SNamhyung Kim }
970dcad1a20SNamhyung Kim 
prepare_uprobe_buffer(struct trace_uprobe * tu,struct pt_regs * regs,struct uprobe_cpu_buffer ** ucbp)9713eaea21bSAndrii Nakryiko static struct uprobe_cpu_buffer *prepare_uprobe_buffer(struct trace_uprobe *tu,
9721b8f85deSAndrii Nakryiko 						       struct pt_regs *regs,
9731b8f85deSAndrii Nakryiko 						       struct uprobe_cpu_buffer **ucbp)
9743eaea21bSAndrii Nakryiko {
9753eaea21bSAndrii Nakryiko 	struct uprobe_cpu_buffer *ucb;
9763eaea21bSAndrii Nakryiko 	int dsize, esize;
9773eaea21bSAndrii Nakryiko 
9781b8f85deSAndrii Nakryiko 	if (*ucbp)
9791b8f85deSAndrii Nakryiko 		return *ucbp;
9801b8f85deSAndrii Nakryiko 
9813eaea21bSAndrii Nakryiko 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
9823eaea21bSAndrii Nakryiko 	dsize = __get_data_size(&tu->tp, regs, NULL);
9833eaea21bSAndrii Nakryiko 
9843eaea21bSAndrii Nakryiko 	ucb = uprobe_buffer_get();
9853eaea21bSAndrii Nakryiko 	ucb->dsize = tu->tp.size + dsize;
9863eaea21bSAndrii Nakryiko 
987373b9338SQiao Ma 	if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) {
988373b9338SQiao Ma 		ucb->dsize = MAX_UCB_BUFFER_SIZE;
989373b9338SQiao Ma 		dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size;
990373b9338SQiao Ma 	}
991373b9338SQiao Ma 
9923eaea21bSAndrii Nakryiko 	store_trace_args(ucb->buf, &tu->tp, regs, NULL, esize, dsize);
9933eaea21bSAndrii Nakryiko 
9941b8f85deSAndrii Nakryiko 	*ucbp = ucb;
9953eaea21bSAndrii Nakryiko 	return ucb;
9963eaea21bSAndrii Nakryiko }
9973eaea21bSAndrii Nakryiko 
__uprobe_trace_func(struct trace_uprobe * tu,unsigned long func,struct pt_regs * regs,struct uprobe_cpu_buffer * ucb,struct trace_event_file * trace_file)998a43b9704SNamhyung Kim static void __uprobe_trace_func(struct trace_uprobe *tu,
999dd9fa555SNamhyung Kim 				unsigned long func, struct pt_regs *regs,
100069964673SAndrii Nakryiko 				struct uprobe_cpu_buffer *ucb,
10017f1d2f82SSteven Rostedt (Red Hat) 				struct trace_event_file *trace_file)
1002f3f096cfSSrikar Dronamraju {
1003f3f096cfSSrikar Dronamraju 	struct uprobe_trace_entry_head *entry;
1004b7d5eb26SSteven Rostedt (VMware) 	struct trace_event_buffer fbuffer;
1005457d1772SOleg Nesterov 	void *data;
1006dd9fa555SNamhyung Kim 	int size, esize;
1007e3dc9f89SMasami Hiramatsu 	struct trace_event_call *call = trace_probe_event_call(&tu->tp);
1008f3f096cfSSrikar Dronamraju 
10097f1d2f82SSteven Rostedt (Red Hat) 	WARN_ON(call != trace_file->event_call);
101070ed91c6Szhangwei(Jovi) 
101109a5059aSSteven Rostedt (Red Hat) 	if (trace_trigger_soft_disabled(trace_file))
1012ca3b1620SNamhyung Kim 		return;
1013ca3b1620SNamhyung Kim 
1014dd9fa555SNamhyung Kim 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
10153eaea21bSAndrii Nakryiko 	size = esize + ucb->dsize;
1016b7d5eb26SSteven Rostedt (VMware) 	entry = trace_event_buffer_reserve(&fbuffer, trace_file, size);
1017b7d5eb26SSteven Rostedt (VMware) 	if (!entry)
1018dd9fa555SNamhyung Kim 		return;
1019dcad1a20SNamhyung Kim 
1020393a736cSOleg Nesterov 	if (is_ret_probe(tu)) {
1021393a736cSOleg Nesterov 		entry->vaddr[0] = func;
1022393a736cSOleg Nesterov 		entry->vaddr[1] = instruction_pointer(regs);
1023393a736cSOleg Nesterov 		data = DATAOF_TRACE_ENTRY(entry, true);
1024393a736cSOleg Nesterov 	} else {
1025457d1772SOleg Nesterov 		entry->vaddr[0] = instruction_pointer(regs);
1026457d1772SOleg Nesterov 		data = DATAOF_TRACE_ENTRY(entry, false);
1027393a736cSOleg Nesterov 	}
1028393a736cSOleg Nesterov 
10293eaea21bSAndrii Nakryiko 	memcpy(data, ucb->buf, ucb->dsize);
1030f3f096cfSSrikar Dronamraju 
1031b7d5eb26SSteven Rostedt (VMware) 	trace_event_buffer_commit(&fbuffer);
1032a51cc604SOleg Nesterov }
1033f42d24a1SOleg Nesterov 
1034a51cc604SOleg Nesterov /* uprobe handler */
uprobe_trace_func(struct trace_uprobe * tu,struct pt_regs * regs,struct uprobe_cpu_buffer ** ucbp)1035dd9fa555SNamhyung Kim static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
10361b8f85deSAndrii Nakryiko 			     struct uprobe_cpu_buffer **ucbp)
1037a51cc604SOleg Nesterov {
103870ed91c6Szhangwei(Jovi) 	struct event_file_link *link;
103969964673SAndrii Nakryiko 	struct uprobe_cpu_buffer *ucb;
104070ed91c6Szhangwei(Jovi) 
104170ed91c6Szhangwei(Jovi) 	if (is_ret_probe(tu))
104270ed91c6Szhangwei(Jovi) 		return 0;
104370ed91c6Szhangwei(Jovi) 
104469964673SAndrii Nakryiko 	ucb = prepare_uprobe_buffer(tu, regs, ucbp);
104569964673SAndrii Nakryiko 
104670ed91c6Szhangwei(Jovi) 	rcu_read_lock();
1047b5f935eeSMasami Hiramatsu 	trace_probe_for_each_link_rcu(link, &tu->tp)
104869964673SAndrii Nakryiko 		__uprobe_trace_func(tu, 0, regs, ucb, link->file);
104970ed91c6Szhangwei(Jovi) 	rcu_read_unlock();
105070ed91c6Szhangwei(Jovi) 
1051f42d24a1SOleg Nesterov 	return 0;
1052f3f096cfSSrikar Dronamraju }
1053f3f096cfSSrikar Dronamraju 
uretprobe_trace_func(struct trace_uprobe * tu,unsigned long func,struct pt_regs * regs,struct uprobe_cpu_buffer ** ucbp)1054c1ae5c75SOleg Nesterov static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
1055dd9fa555SNamhyung Kim 				 struct pt_regs *regs,
10561b8f85deSAndrii Nakryiko 				 struct uprobe_cpu_buffer **ucbp)
1057c1ae5c75SOleg Nesterov {
105870ed91c6Szhangwei(Jovi) 	struct event_file_link *link;
105969964673SAndrii Nakryiko 	struct uprobe_cpu_buffer *ucb;
106069964673SAndrii Nakryiko 
106169964673SAndrii Nakryiko 	ucb = prepare_uprobe_buffer(tu, regs, ucbp);
106270ed91c6Szhangwei(Jovi) 
106370ed91c6Szhangwei(Jovi) 	rcu_read_lock();
1064b5f935eeSMasami Hiramatsu 	trace_probe_for_each_link_rcu(link, &tu->tp)
106569964673SAndrii Nakryiko 		__uprobe_trace_func(tu, func, regs, ucb, link->file);
106670ed91c6Szhangwei(Jovi) 	rcu_read_unlock();
1067c1ae5c75SOleg Nesterov }
1068c1ae5c75SOleg Nesterov 
1069f3f096cfSSrikar Dronamraju /* Event entry printers */
1070f3f096cfSSrikar Dronamraju static enum print_line_t
print_uprobe_event(struct trace_iterator * iter,int flags,struct trace_event * event)1071f3f096cfSSrikar Dronamraju print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event)
1072f3f096cfSSrikar Dronamraju {
1073457d1772SOleg Nesterov 	struct uprobe_trace_entry_head *entry;
1074f3f096cfSSrikar Dronamraju 	struct trace_seq *s = &iter->seq;
1075f3f096cfSSrikar Dronamraju 	struct trace_uprobe *tu;
1076f3f096cfSSrikar Dronamraju 	u8 *data;
1077f3f096cfSSrikar Dronamraju 
1078457d1772SOleg Nesterov 	entry = (struct uprobe_trace_entry_head *)iter->ent;
107960d53e2cSMasami Hiramatsu 	tu = trace_uprobe_primary_from_call(
108060d53e2cSMasami Hiramatsu 		container_of(event, struct trace_event_call, event));
108160d53e2cSMasami Hiramatsu 	if (unlikely(!tu))
108260d53e2cSMasami Hiramatsu 		goto out;
1083f3f096cfSSrikar Dronamraju 
10843ede82ddSOleg Nesterov 	if (is_ret_probe(tu)) {
10858579a107SSteven Rostedt (Red Hat) 		trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
1086b55ce203SMasami Hiramatsu 				 trace_probe_name(&tu->tp),
10878579a107SSteven Rostedt (Red Hat) 				 entry->vaddr[1], entry->vaddr[0]);
10883ede82ddSOleg Nesterov 		data = DATAOF_TRACE_ENTRY(entry, true);
10893ede82ddSOleg Nesterov 	} else {
10908579a107SSteven Rostedt (Red Hat) 		trace_seq_printf(s, "%s: (0x%lx)",
1091b55ce203SMasami Hiramatsu 				 trace_probe_name(&tu->tp),
10928579a107SSteven Rostedt (Red Hat) 				 entry->vaddr[0]);
1093457d1772SOleg Nesterov 		data = DATAOF_TRACE_ENTRY(entry, false);
10943ede82ddSOleg Nesterov 	}
10953ede82ddSOleg Nesterov 
1096196b6389SSong Chen 	if (trace_probe_print_args(s, tu->tp.args, tu->tp.nr_args, data, entry) < 0)
10978579a107SSteven Rostedt (Red Hat) 		goto out;
1098f3f096cfSSrikar Dronamraju 
10998579a107SSteven Rostedt (Red Hat) 	trace_seq_putc(s, '\n');
1100f3f096cfSSrikar Dronamraju 
11018579a107SSteven Rostedt (Red Hat)  out:
11028579a107SSteven Rostedt (Red Hat) 	return trace_handle_return(s);
1103f3f096cfSSrikar Dronamraju }
1104f3f096cfSSrikar Dronamraju 
110559da880aSAndrii Nakryiko typedef bool (*filter_func_t)(struct uprobe_consumer *self, struct mm_struct *mm);
110631ba3348SOleg Nesterov 
trace_uprobe_enable(struct trace_uprobe * tu,filter_func_t filter)110760d53e2cSMasami Hiramatsu static int trace_uprobe_enable(struct trace_uprobe *tu, filter_func_t filter)
1108f3f096cfSSrikar Dronamraju {
11093c83a9adSOleg Nesterov 	struct inode *inode = d_real_inode(tu->path.dentry);
11103c83a9adSOleg Nesterov 	struct uprobe *uprobe;
1111f3f096cfSSrikar Dronamraju 
111260d53e2cSMasami Hiramatsu 	tu->consumer.filter = filter;
11133c83a9adSOleg Nesterov 	uprobe = uprobe_register(inode, tu->offset, tu->ref_ctr_offset, &tu->consumer);
11143c83a9adSOleg Nesterov 	if (IS_ERR(uprobe))
11153c83a9adSOleg Nesterov 		return PTR_ERR(uprobe);
111660d53e2cSMasami Hiramatsu 
11173c83a9adSOleg Nesterov 	tu->uprobe = uprobe;
11183c83a9adSOleg Nesterov 	return 0;
111960d53e2cSMasami Hiramatsu }
112060d53e2cSMasami Hiramatsu 
__probe_event_disable(struct trace_probe * tp)112160d53e2cSMasami Hiramatsu static void __probe_event_disable(struct trace_probe *tp)
112260d53e2cSMasami Hiramatsu {
112360d53e2cSMasami Hiramatsu 	struct trace_uprobe *tu;
112404b01625SPeter Zijlstra 	bool sync = false;
112560d53e2cSMasami Hiramatsu 
112699c9a923SMasami Hiramatsu 	tu = container_of(tp, struct trace_uprobe, tp);
1127b61387cbSMasami Hiramatsu 	WARN_ON(!uprobe_filter_is_empty(tu->tp.event->filter));
112899c9a923SMasami Hiramatsu 
1129e161c6bfSJiri Olsa 	list_for_each_entry(tu, trace_probe_probe_list(tp), tp.list) {
11303c83a9adSOleg Nesterov 		if (!tu->uprobe)
113160d53e2cSMasami Hiramatsu 			continue;
113260d53e2cSMasami Hiramatsu 
113304b01625SPeter Zijlstra 		uprobe_unregister_nosync(tu->uprobe, &tu->consumer);
113404b01625SPeter Zijlstra 		sync = true;
11353c83a9adSOleg Nesterov 		tu->uprobe = NULL;
113660d53e2cSMasami Hiramatsu 	}
113704b01625SPeter Zijlstra 	if (sync)
113804b01625SPeter Zijlstra 		uprobe_unregister_sync();
113960d53e2cSMasami Hiramatsu }
114060d53e2cSMasami Hiramatsu 
probe_event_enable(struct trace_event_call * call,struct trace_event_file * file,filter_func_t filter)114160d53e2cSMasami Hiramatsu static int probe_event_enable(struct trace_event_call *call,
114260d53e2cSMasami Hiramatsu 			struct trace_event_file *file, filter_func_t filter)
114360d53e2cSMasami Hiramatsu {
1144e161c6bfSJiri Olsa 	struct trace_probe *tp;
114560d53e2cSMasami Hiramatsu 	struct trace_uprobe *tu;
114660d53e2cSMasami Hiramatsu 	bool enabled;
114760d53e2cSMasami Hiramatsu 	int ret;
114860d53e2cSMasami Hiramatsu 
114960d53e2cSMasami Hiramatsu 	tp = trace_probe_primary_from_call(call);
115060d53e2cSMasami Hiramatsu 	if (WARN_ON_ONCE(!tp))
115160d53e2cSMasami Hiramatsu 		return -ENODEV;
115260d53e2cSMasami Hiramatsu 	enabled = trace_probe_is_enabled(tp);
115360d53e2cSMasami Hiramatsu 
115460d53e2cSMasami Hiramatsu 	/* This may also change "enabled" state */
115570ed91c6Szhangwei(Jovi) 	if (file) {
115660d53e2cSMasami Hiramatsu 		if (trace_probe_test_flag(tp, TP_FLAG_PROFILE))
115748212542SOleg Nesterov 			return -EINTR;
115848212542SOleg Nesterov 
115960d53e2cSMasami Hiramatsu 		ret = trace_probe_add_file(tp, file);
1160b5f935eeSMasami Hiramatsu 		if (ret < 0)
1161b5f935eeSMasami Hiramatsu 			return ret;
116248212542SOleg Nesterov 	} else {
116360d53e2cSMasami Hiramatsu 		if (trace_probe_test_flag(tp, TP_FLAG_TRACE))
116448212542SOleg Nesterov 			return -EINTR;
116548212542SOleg Nesterov 
116660d53e2cSMasami Hiramatsu 		trace_probe_set_flag(tp, TP_FLAG_PROFILE);
116748212542SOleg Nesterov 	}
116870ed91c6Szhangwei(Jovi) 
116960d53e2cSMasami Hiramatsu 	tu = container_of(tp, struct trace_uprobe, tp);
1170b61387cbSMasami Hiramatsu 	WARN_ON(!uprobe_filter_is_empty(tu->tp.event->filter));
1171736288baSOleg Nesterov 
117270ed91c6Szhangwei(Jovi) 	if (enabled)
117370ed91c6Szhangwei(Jovi) 		return 0;
117470ed91c6Szhangwei(Jovi) 
1175fb6bab6aSOleg Nesterov 	ret = uprobe_buffer_enable();
1176fb6bab6aSOleg Nesterov 	if (ret)
1177fb6bab6aSOleg Nesterov 		goto err_flags;
1178fb6bab6aSOleg Nesterov 
1179e161c6bfSJiri Olsa 	list_for_each_entry(tu, trace_probe_probe_list(tp), tp.list) {
118060d53e2cSMasami Hiramatsu 		ret = trace_uprobe_enable(tu, filter);
118160d53e2cSMasami Hiramatsu 		if (ret) {
118260d53e2cSMasami Hiramatsu 			__probe_event_disable(tp);
1183fb6bab6aSOleg Nesterov 			goto err_buffer;
118460d53e2cSMasami Hiramatsu 		}
118560d53e2cSMasami Hiramatsu 	}
1186fb6bab6aSOleg Nesterov 
1187fb6bab6aSOleg Nesterov 	return 0;
1188fb6bab6aSOleg Nesterov 
1189fb6bab6aSOleg Nesterov  err_buffer:
1190fb6bab6aSOleg Nesterov 	uprobe_buffer_disable();
1191fb6bab6aSOleg Nesterov 
1192fb6bab6aSOleg Nesterov  err_flags:
1193b5f935eeSMasami Hiramatsu 	if (file)
119460d53e2cSMasami Hiramatsu 		trace_probe_remove_file(tp, file);
1195b5f935eeSMasami Hiramatsu 	else
119660d53e2cSMasami Hiramatsu 		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
1197b5f935eeSMasami Hiramatsu 
11984161824fSOleg Nesterov 	return ret;
1199f3f096cfSSrikar Dronamraju }
1200f3f096cfSSrikar Dronamraju 
probe_event_disable(struct trace_event_call * call,struct trace_event_file * file)120160d53e2cSMasami Hiramatsu static void probe_event_disable(struct trace_event_call *call,
120260d53e2cSMasami Hiramatsu 				struct trace_event_file *file)
1203f3f096cfSSrikar Dronamraju {
120460d53e2cSMasami Hiramatsu 	struct trace_probe *tp;
120560d53e2cSMasami Hiramatsu 
120660d53e2cSMasami Hiramatsu 	tp = trace_probe_primary_from_call(call);
120760d53e2cSMasami Hiramatsu 	if (WARN_ON_ONCE(!tp))
120860d53e2cSMasami Hiramatsu 		return;
120960d53e2cSMasami Hiramatsu 
121060d53e2cSMasami Hiramatsu 	if (!trace_probe_is_enabled(tp))
1211f3f096cfSSrikar Dronamraju 		return;
1212f3f096cfSSrikar Dronamraju 
121370ed91c6Szhangwei(Jovi) 	if (file) {
121460d53e2cSMasami Hiramatsu 		if (trace_probe_remove_file(tp, file) < 0)
121570ed91c6Szhangwei(Jovi) 			return;
121670ed91c6Szhangwei(Jovi) 
121760d53e2cSMasami Hiramatsu 		if (trace_probe_is_enabled(tp))
121870ed91c6Szhangwei(Jovi) 			return;
1219b5f935eeSMasami Hiramatsu 	} else
122060d53e2cSMasami Hiramatsu 		trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
122170ed91c6Szhangwei(Jovi) 
122260d53e2cSMasami Hiramatsu 	__probe_event_disable(tp);
1223dcad1a20SNamhyung Kim 	uprobe_buffer_disable();
1224f3f096cfSSrikar Dronamraju }
1225f3f096cfSSrikar Dronamraju 
uprobe_event_define_fields(struct trace_event_call * event_call)12262425bcb9SSteven Rostedt (Red Hat) static int uprobe_event_define_fields(struct trace_event_call *event_call)
1227f3f096cfSSrikar Dronamraju {
1228eeb07b06SMasami Hiramatsu 	int ret, size;
1229f3f096cfSSrikar Dronamraju 	struct uprobe_trace_entry_head field;
123060d53e2cSMasami Hiramatsu 	struct trace_uprobe *tu;
123160d53e2cSMasami Hiramatsu 
123260d53e2cSMasami Hiramatsu 	tu = trace_uprobe_primary_from_call(event_call);
123360d53e2cSMasami Hiramatsu 	if (unlikely(!tu))
123460d53e2cSMasami Hiramatsu 		return -ENODEV;
1235f3f096cfSSrikar Dronamraju 
12364d1298e2SOleg Nesterov 	if (is_ret_probe(tu)) {
12374d1298e2SOleg Nesterov 		DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_FUNC, 0);
12384d1298e2SOleg Nesterov 		DEFINE_FIELD(unsigned long, vaddr[1], FIELD_STRING_RETIP, 0);
12394d1298e2SOleg Nesterov 		size = SIZEOF_TRACE_ENTRY(true);
12404d1298e2SOleg Nesterov 	} else {
1241457d1772SOleg Nesterov 		DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_IP, 0);
1242457d1772SOleg Nesterov 		size = SIZEOF_TRACE_ENTRY(false);
12434d1298e2SOleg Nesterov 	}
124414577c39SNamhyung Kim 
1245eeb07b06SMasami Hiramatsu 	return traceprobe_define_arg_fields(event_call, size, &tu->tp);
1246f3f096cfSSrikar Dronamraju }
1247f3f096cfSSrikar Dronamraju 
1248f3f096cfSSrikar Dronamraju #ifdef CONFIG_PERF_EVENTS
124931ba3348SOleg Nesterov static bool
__uprobe_perf_filter(struct trace_uprobe_filter * filter,struct mm_struct * mm)125031ba3348SOleg Nesterov __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm)
125131ba3348SOleg Nesterov {
125231ba3348SOleg Nesterov 	struct perf_event *event;
125331ba3348SOleg Nesterov 
125431ba3348SOleg Nesterov 	list_for_each_entry(event, &filter->perf_events, hw.tp_list) {
125550f16a8bSPeter Zijlstra 		if (event->hw.target->mm == mm)
125631ba3348SOleg Nesterov 			return true;
125731ba3348SOleg Nesterov 	}
125831ba3348SOleg Nesterov 
125931ba3348SOleg Nesterov 	return false;
126031ba3348SOleg Nesterov }
126131ba3348SOleg Nesterov 
1262b2fe8ba6SOleg Nesterov static inline bool
trace_uprobe_filter_event(struct trace_uprobe_filter * filter,struct perf_event * event)126399c9a923SMasami Hiramatsu trace_uprobe_filter_event(struct trace_uprobe_filter *filter,
126499c9a923SMasami Hiramatsu 			  struct perf_event *event)
1265b2fe8ba6SOleg Nesterov {
126699c9a923SMasami Hiramatsu 	return __uprobe_perf_filter(filter, event->hw.target->mm);
1267b2fe8ba6SOleg Nesterov }
1268b2fe8ba6SOleg Nesterov 
trace_uprobe_filter_remove(struct trace_uprobe_filter * filter,struct perf_event * event)126999c9a923SMasami Hiramatsu static bool trace_uprobe_filter_remove(struct trace_uprobe_filter *filter,
127099c9a923SMasami Hiramatsu 				       struct perf_event *event)
1271ce5f36a5SOleg Nesterov {
1272ce5f36a5SOleg Nesterov 	bool done;
1273ce5f36a5SOleg Nesterov 
127499c9a923SMasami Hiramatsu 	write_lock(&filter->rwlock);
127550f16a8bSPeter Zijlstra 	if (event->hw.target) {
1276ce5f36a5SOleg Nesterov 		list_del(&event->hw.tp_list);
127799c9a923SMasami Hiramatsu 		done = filter->nr_systemwide ||
127850f16a8bSPeter Zijlstra 			(event->hw.target->flags & PF_EXITING) ||
127999c9a923SMasami Hiramatsu 			trace_uprobe_filter_event(filter, event);
1280ce5f36a5SOleg Nesterov 	} else {
128199c9a923SMasami Hiramatsu 		filter->nr_systemwide--;
128299c9a923SMasami Hiramatsu 		done = filter->nr_systemwide;
1283ce5f36a5SOleg Nesterov 	}
128499c9a923SMasami Hiramatsu 	write_unlock(&filter->rwlock);
1285ce5f36a5SOleg Nesterov 
128699c9a923SMasami Hiramatsu 	return done;
1287ce5f36a5SOleg Nesterov }
1288ce5f36a5SOleg Nesterov 
128999c9a923SMasami Hiramatsu /* This returns true if the filter always covers target mm */
trace_uprobe_filter_add(struct trace_uprobe_filter * filter,struct perf_event * event)129099c9a923SMasami Hiramatsu static bool trace_uprobe_filter_add(struct trace_uprobe_filter *filter,
129199c9a923SMasami Hiramatsu 				    struct perf_event *event)
1292736288baSOleg Nesterov {
1293b2fe8ba6SOleg Nesterov 	bool done;
1294b2fe8ba6SOleg Nesterov 
129599c9a923SMasami Hiramatsu 	write_lock(&filter->rwlock);
129650f16a8bSPeter Zijlstra 	if (event->hw.target) {
1297b2fe8ba6SOleg Nesterov 		/*
1298b2fe8ba6SOleg Nesterov 		 * event->parent != NULL means copy_process(), we can avoid
1299b2fe8ba6SOleg Nesterov 		 * uprobe_apply(). current->mm must be probed and we can rely
1300b2fe8ba6SOleg Nesterov 		 * on dup_mmap() which preserves the already installed bp's.
1301b2fe8ba6SOleg Nesterov 		 *
1302b2fe8ba6SOleg Nesterov 		 * attr.enable_on_exec means that exec/mmap will install the
1303b2fe8ba6SOleg Nesterov 		 * breakpoints we need.
1304b2fe8ba6SOleg Nesterov 		 */
130599c9a923SMasami Hiramatsu 		done = filter->nr_systemwide ||
1306b2fe8ba6SOleg Nesterov 			event->parent || event->attr.enable_on_exec ||
130799c9a923SMasami Hiramatsu 			trace_uprobe_filter_event(filter, event);
130899c9a923SMasami Hiramatsu 		list_add(&event->hw.tp_list, &filter->perf_events);
1309b2fe8ba6SOleg Nesterov 	} else {
131099c9a923SMasami Hiramatsu 		done = filter->nr_systemwide;
131199c9a923SMasami Hiramatsu 		filter->nr_systemwide++;
1312b2fe8ba6SOleg Nesterov 	}
131399c9a923SMasami Hiramatsu 	write_unlock(&filter->rwlock);
1314736288baSOleg Nesterov 
131599c9a923SMasami Hiramatsu 	return done;
1316736288baSOleg Nesterov }
1317736288baSOleg Nesterov 
uprobe_perf_close(struct trace_event_call * call,struct perf_event * event)131899c9a923SMasami Hiramatsu static int uprobe_perf_close(struct trace_event_call *call,
131999c9a923SMasami Hiramatsu 			     struct perf_event *event)
132060d53e2cSMasami Hiramatsu {
1321e161c6bfSJiri Olsa 	struct trace_probe *tp;
132260d53e2cSMasami Hiramatsu 	struct trace_uprobe *tu;
132360d53e2cSMasami Hiramatsu 	int ret = 0;
132460d53e2cSMasami Hiramatsu 
132560d53e2cSMasami Hiramatsu 	tp = trace_probe_primary_from_call(call);
132660d53e2cSMasami Hiramatsu 	if (WARN_ON_ONCE(!tp))
132760d53e2cSMasami Hiramatsu 		return -ENODEV;
132860d53e2cSMasami Hiramatsu 
132999c9a923SMasami Hiramatsu 	tu = container_of(tp, struct trace_uprobe, tp);
1330b61387cbSMasami Hiramatsu 	if (trace_uprobe_filter_remove(tu->tp.event->filter, event))
133199c9a923SMasami Hiramatsu 		return 0;
133299c9a923SMasami Hiramatsu 
1333e161c6bfSJiri Olsa 	list_for_each_entry(tu, trace_probe_probe_list(tp), tp.list) {
13343c83a9adSOleg Nesterov 		ret = uprobe_apply(tu->uprobe, &tu->consumer, false);
133560d53e2cSMasami Hiramatsu 		if (ret)
133660d53e2cSMasami Hiramatsu 			break;
133760d53e2cSMasami Hiramatsu 	}
133860d53e2cSMasami Hiramatsu 
133960d53e2cSMasami Hiramatsu 	return ret;
134060d53e2cSMasami Hiramatsu }
134199c9a923SMasami Hiramatsu 
uprobe_perf_open(struct trace_event_call * call,struct perf_event * event)134299c9a923SMasami Hiramatsu static int uprobe_perf_open(struct trace_event_call *call,
134399c9a923SMasami Hiramatsu 			    struct perf_event *event)
134499c9a923SMasami Hiramatsu {
1345e161c6bfSJiri Olsa 	struct trace_probe *tp;
134699c9a923SMasami Hiramatsu 	struct trace_uprobe *tu;
134799c9a923SMasami Hiramatsu 	int err = 0;
134899c9a923SMasami Hiramatsu 
134999c9a923SMasami Hiramatsu 	tp = trace_probe_primary_from_call(call);
135099c9a923SMasami Hiramatsu 	if (WARN_ON_ONCE(!tp))
135199c9a923SMasami Hiramatsu 		return -ENODEV;
135299c9a923SMasami Hiramatsu 
135399c9a923SMasami Hiramatsu 	tu = container_of(tp, struct trace_uprobe, tp);
1354b61387cbSMasami Hiramatsu 	if (trace_uprobe_filter_add(tu->tp.event->filter, event))
135599c9a923SMasami Hiramatsu 		return 0;
135699c9a923SMasami Hiramatsu 
1357e161c6bfSJiri Olsa 	list_for_each_entry(tu, trace_probe_probe_list(tp), tp.list) {
13583c83a9adSOleg Nesterov 		err = uprobe_apply(tu->uprobe, &tu->consumer, true);
135999c9a923SMasami Hiramatsu 		if (err) {
136099c9a923SMasami Hiramatsu 			uprobe_perf_close(call, event);
136199c9a923SMasami Hiramatsu 			break;
136299c9a923SMasami Hiramatsu 		}
136399c9a923SMasami Hiramatsu 	}
136499c9a923SMasami Hiramatsu 
136599c9a923SMasami Hiramatsu 	return err;
136699c9a923SMasami Hiramatsu }
136799c9a923SMasami Hiramatsu 
uprobe_perf_filter(struct uprobe_consumer * uc,struct mm_struct * mm)136859da880aSAndrii Nakryiko static bool uprobe_perf_filter(struct uprobe_consumer *uc, struct mm_struct *mm)
136931ba3348SOleg Nesterov {
137099c9a923SMasami Hiramatsu 	struct trace_uprobe_filter *filter;
137131ba3348SOleg Nesterov 	struct trace_uprobe *tu;
137231ba3348SOleg Nesterov 	int ret;
137331ba3348SOleg Nesterov 
137431ba3348SOleg Nesterov 	tu = container_of(uc, struct trace_uprobe, consumer);
1375b61387cbSMasami Hiramatsu 	filter = tu->tp.event->filter;
137699c9a923SMasami Hiramatsu 
1377cdf355ccSAndrii Nakryiko 	/*
1378cdf355ccSAndrii Nakryiko 	 * speculative short-circuiting check to avoid unnecessarily taking
1379cdf355ccSAndrii Nakryiko 	 * filter->rwlock below, if the uprobe has system-wide consumer
1380cdf355ccSAndrii Nakryiko 	 */
1381cdf355ccSAndrii Nakryiko 	if (READ_ONCE(filter->nr_systemwide))
1382cdf355ccSAndrii Nakryiko 		return true;
1383cdf355ccSAndrii Nakryiko 
138499c9a923SMasami Hiramatsu 	read_lock(&filter->rwlock);
138599c9a923SMasami Hiramatsu 	ret = __uprobe_perf_filter(filter, mm);
138699c9a923SMasami Hiramatsu 	read_unlock(&filter->rwlock);
138731ba3348SOleg Nesterov 
138831ba3348SOleg Nesterov 	return ret;
138931ba3348SOleg Nesterov }
139031ba3348SOleg Nesterov 
__uprobe_perf_func(struct trace_uprobe * tu,unsigned long func,struct pt_regs * regs,struct uprobe_cpu_buffer ** ucbp)1391a43b9704SNamhyung Kim static void __uprobe_perf_func(struct trace_uprobe *tu,
1392dd9fa555SNamhyung Kim 			       unsigned long func, struct pt_regs *regs,
13931b8f85deSAndrii Nakryiko 			       struct uprobe_cpu_buffer **ucbp)
1394f3f096cfSSrikar Dronamraju {
1395e3dc9f89SMasami Hiramatsu 	struct trace_event_call *call = trace_probe_event_call(&tu->tp);
1396f3f096cfSSrikar Dronamraju 	struct uprobe_trace_entry_head *entry;
13971b8f85deSAndrii Nakryiko 	struct uprobe_cpu_buffer *ucb;
1398f3f096cfSSrikar Dronamraju 	struct hlist_head *head;
1399457d1772SOleg Nesterov 	void *data;
1400dd9fa555SNamhyung Kim 	int size, esize;
1401dcad1a20SNamhyung Kim 	int rctx;
1402f3f096cfSSrikar Dronamraju 
1403aca80dd9SDelyan Kratunov #ifdef CONFIG_BPF_EVENTS
140470ed0706SAlexei Starovoitov 	if (bpf_prog_array_valid(call)) {
14057d0d6736SJann Horn 		const struct bpf_prog_array *array;
140670ed0706SAlexei Starovoitov 		u32 ret;
140770ed0706SAlexei Starovoitov 
14087d0d6736SJann Horn 		rcu_read_lock_trace();
14097d0d6736SJann Horn 		array = rcu_dereference_check(call->prog_array, rcu_read_lock_trace_held());
14107d0d6736SJann Horn 		ret = bpf_prog_run_array_uprobe(array, regs, bpf_prog_run);
14117d0d6736SJann Horn 		rcu_read_unlock_trace();
141270ed0706SAlexei Starovoitov 		if (!ret)
141304a22faeSWang Nan 			return;
141470ed0706SAlexei Starovoitov 	}
1415aca80dd9SDelyan Kratunov #endif /* CONFIG_BPF_EVENTS */
141604a22faeSWang Nan 
1417dcad1a20SNamhyung Kim 	esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
1418dcad1a20SNamhyung Kim 
14191b8f85deSAndrii Nakryiko 	ucb = prepare_uprobe_buffer(tu, regs, ucbp);
14203eaea21bSAndrii Nakryiko 	size = esize + ucb->dsize;
1421dcad1a20SNamhyung Kim 	size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32);
1422dcad1a20SNamhyung Kim 	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
1423dcad1a20SNamhyung Kim 		return;
1424dcad1a20SNamhyung Kim 
1425f3f096cfSSrikar Dronamraju 	preempt_disable();
1426515619f2SOleg Nesterov 	head = this_cpu_ptr(call->perf_events);
1427515619f2SOleg Nesterov 	if (hlist_empty(head))
1428515619f2SOleg Nesterov 		goto out;
1429515619f2SOleg Nesterov 
14301e1dcd93SAlexei Starovoitov 	entry = perf_trace_buf_alloc(size, NULL, &rctx);
1431f3f096cfSSrikar Dronamraju 	if (!entry)
1432f3f096cfSSrikar Dronamraju 		goto out;
1433f3f096cfSSrikar Dronamraju 
1434393a736cSOleg Nesterov 	if (is_ret_probe(tu)) {
1435393a736cSOleg Nesterov 		entry->vaddr[0] = func;
143632520b2cSOleg Nesterov 		entry->vaddr[1] = instruction_pointer(regs);
1437393a736cSOleg Nesterov 		data = DATAOF_TRACE_ENTRY(entry, true);
1438393a736cSOleg Nesterov 	} else {
143932520b2cSOleg Nesterov 		entry->vaddr[0] = instruction_pointer(regs);
1440457d1772SOleg Nesterov 		data = DATAOF_TRACE_ENTRY(entry, false);
1441393a736cSOleg Nesterov 	}
1442393a736cSOleg Nesterov 
14433eaea21bSAndrii Nakryiko 	memcpy(data, ucb->buf, ucb->dsize);
144414577c39SNamhyung Kim 
14453eaea21bSAndrii Nakryiko 	if (size - esize > ucb->dsize)
14463eaea21bSAndrii Nakryiko 		memset(data + ucb->dsize, 0, size - esize - ucb->dsize);
1447f3f096cfSSrikar Dronamraju 
14481e1dcd93SAlexei Starovoitov 	perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
14498fd0fbbeSPeter Zijlstra 			      head, NULL);
1450f3f096cfSSrikar Dronamraju  out:
1451f3f096cfSSrikar Dronamraju 	preempt_enable();
1452a51cc604SOleg Nesterov }
1453a51cc604SOleg Nesterov 
1454a51cc604SOleg Nesterov /* uprobe profile handler */
uprobe_perf_func(struct trace_uprobe * tu,struct pt_regs * regs,struct uprobe_cpu_buffer ** ucbp)1455dd9fa555SNamhyung Kim static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs,
14561b8f85deSAndrii Nakryiko 			    struct uprobe_cpu_buffer **ucbp)
1457a51cc604SOleg Nesterov {
145859da880aSAndrii Nakryiko 	if (!uprobe_perf_filter(&tu->consumer, current->mm))
1459a51cc604SOleg Nesterov 		return UPROBE_HANDLER_REMOVE;
1460a51cc604SOleg Nesterov 
1461393a736cSOleg Nesterov 	if (!is_ret_probe(tu))
14621b8f85deSAndrii Nakryiko 		__uprobe_perf_func(tu, 0, regs, ucbp);
1463f42d24a1SOleg Nesterov 	return 0;
1464f3f096cfSSrikar Dronamraju }
1465c1ae5c75SOleg Nesterov 
uretprobe_perf_func(struct trace_uprobe * tu,unsigned long func,struct pt_regs * regs,struct uprobe_cpu_buffer ** ucbp)1466c1ae5c75SOleg Nesterov static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func,
1467dd9fa555SNamhyung Kim 				struct pt_regs *regs,
14681b8f85deSAndrii Nakryiko 				struct uprobe_cpu_buffer **ucbp)
1469c1ae5c75SOleg Nesterov {
14701b8f85deSAndrii Nakryiko 	__uprobe_perf_func(tu, func, regs, ucbp);
1471c1ae5c75SOleg Nesterov }
147241bdc4b4SYonghong Song 
bpf_get_uprobe_info(const struct perf_event * event,u32 * fd_type,const char ** filename,u64 * probe_offset,u64 * probe_addr,bool perf_type_tracepoint)147341bdc4b4SYonghong Song int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type,
147441bdc4b4SYonghong Song 			const char **filename, u64 *probe_offset,
14755125e757SYafang Shao 			u64 *probe_addr, bool perf_type_tracepoint)
147641bdc4b4SYonghong Song {
147741bdc4b4SYonghong Song 	const char *pevent = trace_event_name(event->tp_event);
147841bdc4b4SYonghong Song 	const char *group = event->tp_event->class->system;
147941bdc4b4SYonghong Song 	struct trace_uprobe *tu;
148041bdc4b4SYonghong Song 
148141bdc4b4SYonghong Song 	if (perf_type_tracepoint)
148241bdc4b4SYonghong Song 		tu = find_probe_event(pevent, group);
148341bdc4b4SYonghong Song 	else
148422d5bd68SJean-Philippe Brucker 		tu = trace_uprobe_primary_from_call(event->tp_event);
148541bdc4b4SYonghong Song 	if (!tu)
148641bdc4b4SYonghong Song 		return -EINVAL;
148741bdc4b4SYonghong Song 
148841bdc4b4SYonghong Song 	*fd_type = is_ret_probe(tu) ? BPF_FD_TYPE_URETPROBE
148941bdc4b4SYonghong Song 				    : BPF_FD_TYPE_UPROBE;
149041bdc4b4SYonghong Song 	*filename = tu->filename;
149141bdc4b4SYonghong Song 	*probe_offset = tu->offset;
14925125e757SYafang Shao 	*probe_addr = 0;
149341bdc4b4SYonghong Song 	return 0;
149441bdc4b4SYonghong Song }
1495f3f096cfSSrikar Dronamraju #endif	/* CONFIG_PERF_EVENTS */
1496f3f096cfSSrikar Dronamraju 
149770ed91c6Szhangwei(Jovi) static int
trace_uprobe_register(struct trace_event_call * event,enum trace_reg type,void * data)14982425bcb9SSteven Rostedt (Red Hat) trace_uprobe_register(struct trace_event_call *event, enum trace_reg type,
149970ed91c6Szhangwei(Jovi) 		      void *data)
1500f3f096cfSSrikar Dronamraju {
15017f1d2f82SSteven Rostedt (Red Hat) 	struct trace_event_file *file = data;
1502f3f096cfSSrikar Dronamraju 
1503f3f096cfSSrikar Dronamraju 	switch (type) {
1504f3f096cfSSrikar Dronamraju 	case TRACE_REG_REGISTER:
150560d53e2cSMasami Hiramatsu 		return probe_event_enable(event, file, NULL);
1506f3f096cfSSrikar Dronamraju 
1507f3f096cfSSrikar Dronamraju 	case TRACE_REG_UNREGISTER:
150860d53e2cSMasami Hiramatsu 		probe_event_disable(event, file);
1509f3f096cfSSrikar Dronamraju 		return 0;
1510f3f096cfSSrikar Dronamraju 
1511f3f096cfSSrikar Dronamraju #ifdef CONFIG_PERF_EVENTS
1512f3f096cfSSrikar Dronamraju 	case TRACE_REG_PERF_REGISTER:
151360d53e2cSMasami Hiramatsu 		return probe_event_enable(event, NULL, uprobe_perf_filter);
1514f3f096cfSSrikar Dronamraju 
1515f3f096cfSSrikar Dronamraju 	case TRACE_REG_PERF_UNREGISTER:
151660d53e2cSMasami Hiramatsu 		probe_event_disable(event, NULL);
1517f3f096cfSSrikar Dronamraju 		return 0;
1518736288baSOleg Nesterov 
1519736288baSOleg Nesterov 	case TRACE_REG_PERF_OPEN:
152099c9a923SMasami Hiramatsu 		return uprobe_perf_open(event, data);
1521736288baSOleg Nesterov 
1522736288baSOleg Nesterov 	case TRACE_REG_PERF_CLOSE:
152399c9a923SMasami Hiramatsu 		return uprobe_perf_close(event, data);
1524736288baSOleg Nesterov 
1525f3f096cfSSrikar Dronamraju #endif
1526f3f096cfSSrikar Dronamraju 	default:
1527f3f096cfSSrikar Dronamraju 		return 0;
1528f3f096cfSSrikar Dronamraju 	}
1529f3f096cfSSrikar Dronamraju }
1530f3f096cfSSrikar Dronamraju 
uprobe_dispatcher(struct uprobe_consumer * con,struct pt_regs * regs,__u64 * data)1531da09a9e0SJiri Olsa static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs,
1532da09a9e0SJiri Olsa 			     __u64 *data)
1533f3f096cfSSrikar Dronamraju {
1534f3f096cfSSrikar Dronamraju 	struct trace_uprobe *tu;
1535b7e0bf34SNamhyung Kim 	struct uprobe_dispatch_data udd;
15361b8f85deSAndrii Nakryiko 	struct uprobe_cpu_buffer *ucb = NULL;
1537f42d24a1SOleg Nesterov 	int ret = 0;
1538f3f096cfSSrikar Dronamraju 
1539a932b738SOleg Nesterov 	tu = container_of(con, struct trace_uprobe, consumer);
154010cdb82aSAndrii Nakryiko 
154110cdb82aSAndrii Nakryiko 	this_cpu_inc(*tu->nhits);
1542f3f096cfSSrikar Dronamraju 
1543b7e0bf34SNamhyung Kim 	udd.tu = tu;
1544b7e0bf34SNamhyung Kim 	udd.bp_addr = instruction_pointer(regs);
1545b7e0bf34SNamhyung Kim 
1546b7e0bf34SNamhyung Kim 	current->utask->vaddr = (unsigned long) &udd;
1547b7e0bf34SNamhyung Kim 
1548dd9fa555SNamhyung Kim 	if (WARN_ON_ONCE(!uprobe_cpu_buffer))
1549dd9fa555SNamhyung Kim 		return 0;
1550dd9fa555SNamhyung Kim 
1551747774d6SMasami Hiramatsu 	if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
15521b8f85deSAndrii Nakryiko 		ret |= uprobe_trace_func(tu, regs, &ucb);
1553f3f096cfSSrikar Dronamraju 
1554f3f096cfSSrikar Dronamraju #ifdef CONFIG_PERF_EVENTS
1555747774d6SMasami Hiramatsu 	if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
15561b8f85deSAndrii Nakryiko 		ret |= uprobe_perf_func(tu, regs, &ucb);
1557f3f096cfSSrikar Dronamraju #endif
1558dd9fa555SNamhyung Kim 	uprobe_buffer_put(ucb);
1559f42d24a1SOleg Nesterov 	return ret;
1560f3f096cfSSrikar Dronamraju }
1561f3f096cfSSrikar Dronamraju 
uretprobe_dispatcher(struct uprobe_consumer * con,unsigned long func,struct pt_regs * regs,__u64 * data)1562c1ae5c75SOleg Nesterov static int uretprobe_dispatcher(struct uprobe_consumer *con,
1563da09a9e0SJiri Olsa 				unsigned long func, struct pt_regs *regs,
1564da09a9e0SJiri Olsa 				__u64 *data)
1565c1ae5c75SOleg Nesterov {
1566c1ae5c75SOleg Nesterov 	struct trace_uprobe *tu;
1567b7e0bf34SNamhyung Kim 	struct uprobe_dispatch_data udd;
15681b8f85deSAndrii Nakryiko 	struct uprobe_cpu_buffer *ucb = NULL;
1569c1ae5c75SOleg Nesterov 
1570c1ae5c75SOleg Nesterov 	tu = container_of(con, struct trace_uprobe, consumer);
1571c1ae5c75SOleg Nesterov 
1572b7e0bf34SNamhyung Kim 	udd.tu = tu;
1573b7e0bf34SNamhyung Kim 	udd.bp_addr = func;
1574b7e0bf34SNamhyung Kim 
1575b7e0bf34SNamhyung Kim 	current->utask->vaddr = (unsigned long) &udd;
1576b7e0bf34SNamhyung Kim 
1577dd9fa555SNamhyung Kim 	if (WARN_ON_ONCE(!uprobe_cpu_buffer))
1578dd9fa555SNamhyung Kim 		return 0;
1579dd9fa555SNamhyung Kim 
1580747774d6SMasami Hiramatsu 	if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
15811b8f85deSAndrii Nakryiko 		uretprobe_trace_func(tu, func, regs, &ucb);
1582c1ae5c75SOleg Nesterov 
1583c1ae5c75SOleg Nesterov #ifdef CONFIG_PERF_EVENTS
1584747774d6SMasami Hiramatsu 	if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
15851b8f85deSAndrii Nakryiko 		uretprobe_perf_func(tu, func, regs, &ucb);
1586c1ae5c75SOleg Nesterov #endif
1587dd9fa555SNamhyung Kim 	uprobe_buffer_put(ucb);
1588c1ae5c75SOleg Nesterov 	return 0;
1589c1ae5c75SOleg Nesterov }
1590c1ae5c75SOleg Nesterov 
1591f3f096cfSSrikar Dronamraju static struct trace_event_functions uprobe_funcs = {
1592f3f096cfSSrikar Dronamraju 	.trace		= print_uprobe_event
1593f3f096cfSSrikar Dronamraju };
1594f3f096cfSSrikar Dronamraju 
159504ae87a5SPeter Zijlstra static struct trace_event_fields uprobe_fields_array[] = {
159604ae87a5SPeter Zijlstra 	{ .type = TRACE_FUNCTION_TYPE,
159704ae87a5SPeter Zijlstra 	  .define_fields = uprobe_event_define_fields },
159804ae87a5SPeter Zijlstra 	{}
159904ae87a5SPeter Zijlstra };
160004ae87a5SPeter Zijlstra 
init_trace_event_call(struct trace_uprobe * tu)1601e3dc9f89SMasami Hiramatsu static inline void init_trace_event_call(struct trace_uprobe *tu)
1602f3f096cfSSrikar Dronamraju {
1603e3dc9f89SMasami Hiramatsu 	struct trace_event_call *call = trace_probe_event_call(&tu->tp);
1604f3f096cfSSrikar Dronamraju 	call->event.funcs = &uprobe_funcs;
160504ae87a5SPeter Zijlstra 	call->class->fields_array = uprobe_fields_array;
1606f3f096cfSSrikar Dronamraju 
16079fd2e48bSSong Liu 	call->flags = TRACE_EVENT_FL_UPROBE | TRACE_EVENT_FL_CAP_ANY;
160833ea4b24SSong Liu 	call->class->reg = trace_uprobe_register;
160933ea4b24SSong Liu }
161033ea4b24SSong Liu 
register_uprobe_event(struct trace_uprobe * tu)161133ea4b24SSong Liu static int register_uprobe_event(struct trace_uprobe *tu)
161233ea4b24SSong Liu {
1613e3dc9f89SMasami Hiramatsu 	init_trace_event_call(tu);
161433ea4b24SSong Liu 
161546e5376dSMasami Hiramatsu 	return trace_probe_register_event_call(&tu->tp);
1616f3f096cfSSrikar Dronamraju }
1617f3f096cfSSrikar Dronamraju 
unregister_uprobe_event(struct trace_uprobe * tu)1618c6c2401dSSteven Rostedt (Red Hat) static int unregister_uprobe_event(struct trace_uprobe *tu)
1619f3f096cfSSrikar Dronamraju {
162046e5376dSMasami Hiramatsu 	return trace_probe_unregister_event_call(&tu->tp);
1621f3f096cfSSrikar Dronamraju }
1622f3f096cfSSrikar Dronamraju 
162333ea4b24SSong Liu #ifdef CONFIG_PERF_EVENTS
162433ea4b24SSong Liu struct trace_event_call *
create_local_trace_uprobe(char * name,unsigned long offs,unsigned long ref_ctr_offset,bool is_return)1625a6ca88b2SSong Liu create_local_trace_uprobe(char *name, unsigned long offs,
1626a6ca88b2SSong Liu 			  unsigned long ref_ctr_offset, bool is_return)
162733ea4b24SSong Liu {
1628007517a0SSteven Rostedt (VMware) 	enum probe_print_type ptype;
162933ea4b24SSong Liu 	struct trace_uprobe *tu;
163033ea4b24SSong Liu 	struct path path;
163133ea4b24SSong Liu 	int ret;
163233ea4b24SSong Liu 
163333ea4b24SSong Liu 	ret = kern_path(name, LOOKUP_FOLLOW, &path);
163433ea4b24SSong Liu 	if (ret)
163533ea4b24SSong Liu 		return ERR_PTR(ret);
163633ea4b24SSong Liu 
16370c92c7a3SSong Liu 	if (!d_is_reg(path.dentry)) {
163833ea4b24SSong Liu 		path_put(&path);
163933ea4b24SSong Liu 		return ERR_PTR(-EINVAL);
164033ea4b24SSong Liu 	}
164133ea4b24SSong Liu 
164233ea4b24SSong Liu 	/*
16430597c49cSMasami Hiramatsu 	 * local trace_kprobes are not added to dyn_event, so they are never
164433ea4b24SSong Liu 	 * searched in find_trace_kprobe(). Therefore, there is no concern of
164533ea4b24SSong Liu 	 * duplicated name "DUMMY_EVENT" here.
164633ea4b24SSong Liu 	 */
164733ea4b24SSong Liu 	tu = alloc_trace_uprobe(UPROBE_EVENT_SYSTEM, "DUMMY_EVENT", 0,
164833ea4b24SSong Liu 				is_return);
164933ea4b24SSong Liu 
165033ea4b24SSong Liu 	if (IS_ERR(tu)) {
165133ea4b24SSong Liu 		pr_info("Failed to allocate trace_uprobe.(%d)\n",
165233ea4b24SSong Liu 			(int)PTR_ERR(tu));
16530c92c7a3SSong Liu 		path_put(&path);
165433ea4b24SSong Liu 		return ERR_CAST(tu);
165533ea4b24SSong Liu 	}
165633ea4b24SSong Liu 
165733ea4b24SSong Liu 	tu->offset = offs;
16580c92c7a3SSong Liu 	tu->path = path;
1659a6ca88b2SSong Liu 	tu->ref_ctr_offset = ref_ctr_offset;
166033ea4b24SSong Liu 	tu->filename = kstrdup(name, GFP_KERNEL);
16618c722424SXiaoke Wang 	if (!tu->filename) {
16628c722424SXiaoke Wang 		ret = -ENOMEM;
16638c722424SXiaoke Wang 		goto error;
16648c722424SXiaoke Wang 	}
16658c722424SXiaoke Wang 
1666e3dc9f89SMasami Hiramatsu 	init_trace_event_call(tu);
166733ea4b24SSong Liu 
1668007517a0SSteven Rostedt (VMware) 	ptype = is_ret_probe(tu) ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL;
1669007517a0SSteven Rostedt (VMware) 	if (traceprobe_set_print_fmt(&tu->tp, ptype) < 0) {
167033ea4b24SSong Liu 		ret = -ENOMEM;
167133ea4b24SSong Liu 		goto error;
167233ea4b24SSong Liu 	}
167333ea4b24SSong Liu 
1674e3dc9f89SMasami Hiramatsu 	return trace_probe_event_call(&tu->tp);
167533ea4b24SSong Liu error:
167633ea4b24SSong Liu 	free_trace_uprobe(tu);
167733ea4b24SSong Liu 	return ERR_PTR(ret);
167833ea4b24SSong Liu }
167933ea4b24SSong Liu 
destroy_local_trace_uprobe(struct trace_event_call * event_call)168033ea4b24SSong Liu void destroy_local_trace_uprobe(struct trace_event_call *event_call)
168133ea4b24SSong Liu {
168233ea4b24SSong Liu 	struct trace_uprobe *tu;
168333ea4b24SSong Liu 
168460d53e2cSMasami Hiramatsu 	tu = trace_uprobe_primary_from_call(event_call);
168533ea4b24SSong Liu 
168633ea4b24SSong Liu 	free_trace_uprobe(tu);
168733ea4b24SSong Liu }
168833ea4b24SSong Liu #endif /* CONFIG_PERF_EVENTS */
168933ea4b24SSong Liu 
169039bcdd6aSBhaskar Chowdhury /* Make a trace interface for controlling probe points */
init_uprobe_trace(void)1691f3f096cfSSrikar Dronamraju static __init int init_uprobe_trace(void)
1692f3f096cfSSrikar Dronamraju {
16930597c49cSMasami Hiramatsu 	int ret;
16940597c49cSMasami Hiramatsu 
16950597c49cSMasami Hiramatsu 	ret = dyn_event_register(&trace_uprobe_ops);
16960597c49cSMasami Hiramatsu 	if (ret)
16970597c49cSMasami Hiramatsu 		return ret;
1698f3f096cfSSrikar Dronamraju 
169922c36b18SWei Yang 	ret = tracing_init_dentry();
170022c36b18SWei Yang 	if (ret)
1701f3f096cfSSrikar Dronamraju 		return 0;
1702f3f096cfSSrikar Dronamraju 
170321ccc9cdSSteven Rostedt (VMware) 	trace_create_file("uprobe_events", TRACE_MODE_WRITE, NULL,
1704f3f096cfSSrikar Dronamraju 				    NULL, &uprobe_events_ops);
1705f3f096cfSSrikar Dronamraju 	/* Profile interface */
170621ccc9cdSSteven Rostedt (VMware) 	trace_create_file("uprobe_profile", TRACE_MODE_READ, NULL,
1707f3f096cfSSrikar Dronamraju 				    NULL, &uprobe_profile_ops);
1708f3f096cfSSrikar Dronamraju 	return 0;
1709f3f096cfSSrikar Dronamraju }
1710f3f096cfSSrikar Dronamraju 
1711f3f096cfSSrikar Dronamraju fs_initcall(init_uprobe_trace);
1712