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