1334e5519SMasami Hiramatsu (Google) // SPDX-License-Identifier: GPL-2.0
2334e5519SMasami Hiramatsu (Google) /*
3334e5519SMasami Hiramatsu (Google) * Fprobe-based tracing events
4334e5519SMasami Hiramatsu (Google) * Copyright (C) 2022 Google LLC.
5334e5519SMasami Hiramatsu (Google) */
6334e5519SMasami Hiramatsu (Google) #define pr_fmt(fmt) "trace_fprobe: " fmt
725f00e40SMasami Hiramatsu (Google) #include <asm/ptrace.h>
8334e5519SMasami Hiramatsu (Google)
9334e5519SMasami Hiramatsu (Google) #include <linux/fprobe.h>
10334e5519SMasami Hiramatsu (Google) #include <linux/module.h>
11334e5519SMasami Hiramatsu (Google) #include <linux/rculist.h>
12334e5519SMasami Hiramatsu (Google) #include <linux/security.h>
13e2d0d7b2SMasami Hiramatsu (Google) #include <linux/tracepoint.h>
14334e5519SMasami Hiramatsu (Google) #include <linux/uaccess.h>
15334e5519SMasami Hiramatsu (Google)
16334e5519SMasami Hiramatsu (Google) #include "trace_dynevent.h"
17334e5519SMasami Hiramatsu (Google) #include "trace_probe.h"
18334e5519SMasami Hiramatsu (Google) #include "trace_probe_kernel.h"
19334e5519SMasami Hiramatsu (Google) #include "trace_probe_tmpl.h"
20334e5519SMasami Hiramatsu (Google)
21334e5519SMasami Hiramatsu (Google) #define FPROBE_EVENT_SYSTEM "fprobes"
22e2d0d7b2SMasami Hiramatsu (Google) #define TRACEPOINT_EVENT_SYSTEM "tracepoints"
23334e5519SMasami Hiramatsu (Google) #define RETHOOK_MAXACTIVE_MAX 4096
2457a7e6deSMasami Hiramatsu (Google) #define TRACEPOINT_STUB ERR_PTR(-ENOENT)
25334e5519SMasami Hiramatsu (Google)
26334e5519SMasami Hiramatsu (Google) static int trace_fprobe_create(const char *raw_command);
27334e5519SMasami Hiramatsu (Google) static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev);
28334e5519SMasami Hiramatsu (Google) static int trace_fprobe_release(struct dyn_event *ev);
29334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_is_busy(struct dyn_event *ev);
30334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_match(const char *system, const char *event,
31334e5519SMasami Hiramatsu (Google) int argc, const char **argv, struct dyn_event *ev);
32334e5519SMasami Hiramatsu (Google)
33334e5519SMasami Hiramatsu (Google) static struct dyn_event_operations trace_fprobe_ops = {
34334e5519SMasami Hiramatsu (Google) .create = trace_fprobe_create,
35334e5519SMasami Hiramatsu (Google) .show = trace_fprobe_show,
36334e5519SMasami Hiramatsu (Google) .is_busy = trace_fprobe_is_busy,
37334e5519SMasami Hiramatsu (Google) .free = trace_fprobe_release,
38334e5519SMasami Hiramatsu (Google) .match = trace_fprobe_match,
39334e5519SMasami Hiramatsu (Google) };
40334e5519SMasami Hiramatsu (Google)
41334e5519SMasami Hiramatsu (Google) /*
42334e5519SMasami Hiramatsu (Google) * Fprobe event core functions
43334e5519SMasami Hiramatsu (Google) */
44334e5519SMasami Hiramatsu (Google) struct trace_fprobe {
45334e5519SMasami Hiramatsu (Google) struct dyn_event devent;
46334e5519SMasami Hiramatsu (Google) struct fprobe fp;
47334e5519SMasami Hiramatsu (Google) const char *symbol;
48e2d0d7b2SMasami Hiramatsu (Google) struct tracepoint *tpoint;
49e2d0d7b2SMasami Hiramatsu (Google) struct module *mod;
50334e5519SMasami Hiramatsu (Google) struct trace_probe tp;
51334e5519SMasami Hiramatsu (Google) };
52334e5519SMasami Hiramatsu (Google)
is_trace_fprobe(struct dyn_event * ev)53334e5519SMasami Hiramatsu (Google) static bool is_trace_fprobe(struct dyn_event *ev)
54334e5519SMasami Hiramatsu (Google) {
55334e5519SMasami Hiramatsu (Google) return ev->ops == &trace_fprobe_ops;
56334e5519SMasami Hiramatsu (Google) }
57334e5519SMasami Hiramatsu (Google)
to_trace_fprobe(struct dyn_event * ev)58334e5519SMasami Hiramatsu (Google) static struct trace_fprobe *to_trace_fprobe(struct dyn_event *ev)
59334e5519SMasami Hiramatsu (Google) {
60334e5519SMasami Hiramatsu (Google) return container_of(ev, struct trace_fprobe, devent);
61334e5519SMasami Hiramatsu (Google) }
62334e5519SMasami Hiramatsu (Google)
63334e5519SMasami Hiramatsu (Google) /**
64334e5519SMasami Hiramatsu (Google) * for_each_trace_fprobe - iterate over the trace_fprobe list
65334e5519SMasami Hiramatsu (Google) * @pos: the struct trace_fprobe * for each entry
66334e5519SMasami Hiramatsu (Google) * @dpos: the struct dyn_event * to use as a loop cursor
67334e5519SMasami Hiramatsu (Google) */
68334e5519SMasami Hiramatsu (Google) #define for_each_trace_fprobe(pos, dpos) \
69334e5519SMasami Hiramatsu (Google) for_each_dyn_event(dpos) \
70334e5519SMasami Hiramatsu (Google) if (is_trace_fprobe(dpos) && (pos = to_trace_fprobe(dpos)))
71334e5519SMasami Hiramatsu (Google)
trace_fprobe_is_return(struct trace_fprobe * tf)72334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_is_return(struct trace_fprobe *tf)
73334e5519SMasami Hiramatsu (Google) {
74334e5519SMasami Hiramatsu (Google) return tf->fp.exit_handler != NULL;
75334e5519SMasami Hiramatsu (Google) }
76334e5519SMasami Hiramatsu (Google)
trace_fprobe_is_tracepoint(struct trace_fprobe * tf)77e2d0d7b2SMasami Hiramatsu (Google) static bool trace_fprobe_is_tracepoint(struct trace_fprobe *tf)
78e2d0d7b2SMasami Hiramatsu (Google) {
79e2d0d7b2SMasami Hiramatsu (Google) return tf->tpoint != NULL;
80e2d0d7b2SMasami Hiramatsu (Google) }
81e2d0d7b2SMasami Hiramatsu (Google)
trace_fprobe_symbol(struct trace_fprobe * tf)82334e5519SMasami Hiramatsu (Google) static const char *trace_fprobe_symbol(struct trace_fprobe *tf)
83334e5519SMasami Hiramatsu (Google) {
84334e5519SMasami Hiramatsu (Google) return tf->symbol ? tf->symbol : "unknown";
85334e5519SMasami Hiramatsu (Google) }
86334e5519SMasami Hiramatsu (Google)
trace_fprobe_is_busy(struct dyn_event * ev)87334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_is_busy(struct dyn_event *ev)
88334e5519SMasami Hiramatsu (Google) {
89334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf = to_trace_fprobe(ev);
90334e5519SMasami Hiramatsu (Google)
91334e5519SMasami Hiramatsu (Google) return trace_probe_is_enabled(&tf->tp);
92334e5519SMasami Hiramatsu (Google) }
93334e5519SMasami Hiramatsu (Google)
trace_fprobe_match_command_head(struct trace_fprobe * tf,int argc,const char ** argv)94334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_match_command_head(struct trace_fprobe *tf,
95334e5519SMasami Hiramatsu (Google) int argc, const char **argv)
96334e5519SMasami Hiramatsu (Google) {
97334e5519SMasami Hiramatsu (Google) char buf[MAX_ARGSTR_LEN + 1];
98334e5519SMasami Hiramatsu (Google)
99334e5519SMasami Hiramatsu (Google) if (!argc)
100334e5519SMasami Hiramatsu (Google) return true;
101334e5519SMasami Hiramatsu (Google)
102334e5519SMasami Hiramatsu (Google) snprintf(buf, sizeof(buf), "%s", trace_fprobe_symbol(tf));
103334e5519SMasami Hiramatsu (Google) if (strcmp(buf, argv[0]))
104334e5519SMasami Hiramatsu (Google) return false;
105334e5519SMasami Hiramatsu (Google) argc--; argv++;
106334e5519SMasami Hiramatsu (Google)
107334e5519SMasami Hiramatsu (Google) return trace_probe_match_command_args(&tf->tp, argc, argv);
108334e5519SMasami Hiramatsu (Google) }
109334e5519SMasami Hiramatsu (Google)
trace_fprobe_match(const char * system,const char * event,int argc,const char ** argv,struct dyn_event * ev)110334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_match(const char *system, const char *event,
111334e5519SMasami Hiramatsu (Google) int argc, const char **argv, struct dyn_event *ev)
112334e5519SMasami Hiramatsu (Google) {
113334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf = to_trace_fprobe(ev);
114334e5519SMasami Hiramatsu (Google)
115334e5519SMasami Hiramatsu (Google) if (event[0] != '\0' && strcmp(trace_probe_name(&tf->tp), event))
116334e5519SMasami Hiramatsu (Google) return false;
117334e5519SMasami Hiramatsu (Google)
118334e5519SMasami Hiramatsu (Google) if (system && strcmp(trace_probe_group_name(&tf->tp), system))
119334e5519SMasami Hiramatsu (Google) return false;
120334e5519SMasami Hiramatsu (Google)
121334e5519SMasami Hiramatsu (Google) return trace_fprobe_match_command_head(tf, argc, argv);
122334e5519SMasami Hiramatsu (Google) }
123334e5519SMasami Hiramatsu (Google)
trace_fprobe_is_registered(struct trace_fprobe * tf)124334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_is_registered(struct trace_fprobe *tf)
125334e5519SMasami Hiramatsu (Google) {
126334e5519SMasami Hiramatsu (Google) return fprobe_is_registered(&tf->fp);
127334e5519SMasami Hiramatsu (Google) }
128334e5519SMasami Hiramatsu (Google)
129334e5519SMasami Hiramatsu (Google) /*
130334e5519SMasami Hiramatsu (Google) * Note that we don't verify the fetch_insn code, since it does not come
131334e5519SMasami Hiramatsu (Google) * from user space.
132334e5519SMasami Hiramatsu (Google) */
133334e5519SMasami Hiramatsu (Google) static int
process_fetch_insn(struct fetch_insn * code,void * rec,void * edata,void * dest,void * base)13425f00e40SMasami Hiramatsu (Google) process_fetch_insn(struct fetch_insn *code, void *rec, void *edata,
13525f00e40SMasami Hiramatsu (Google) void *dest, void *base)
136334e5519SMasami Hiramatsu (Google) {
1370566cefeSMasami Hiramatsu (Google) struct ftrace_regs *fregs = rec;
138334e5519SMasami Hiramatsu (Google) unsigned long val;
139334e5519SMasami Hiramatsu (Google) int ret;
140334e5519SMasami Hiramatsu (Google)
141334e5519SMasami Hiramatsu (Google) retry:
142334e5519SMasami Hiramatsu (Google) /* 1st stage: get value from context */
143334e5519SMasami Hiramatsu (Google) switch (code->op) {
144334e5519SMasami Hiramatsu (Google) case FETCH_OP_STACK:
1450566cefeSMasami Hiramatsu (Google) val = ftrace_regs_get_kernel_stack_nth(fregs, code->param);
146334e5519SMasami Hiramatsu (Google) break;
147334e5519SMasami Hiramatsu (Google) case FETCH_OP_STACKP:
1480566cefeSMasami Hiramatsu (Google) val = ftrace_regs_get_stack_pointer(fregs);
149334e5519SMasami Hiramatsu (Google) break;
150334e5519SMasami Hiramatsu (Google) case FETCH_OP_RETVAL:
1510566cefeSMasami Hiramatsu (Google) val = ftrace_regs_get_return_value(fregs);
152334e5519SMasami Hiramatsu (Google) break;
153334e5519SMasami Hiramatsu (Google) #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
154334e5519SMasami Hiramatsu (Google) case FETCH_OP_ARG:
1550566cefeSMasami Hiramatsu (Google) val = ftrace_regs_get_argument(fregs, code->param);
156334e5519SMasami Hiramatsu (Google) break;
15725f00e40SMasami Hiramatsu (Google) case FETCH_OP_EDATA:
15825f00e40SMasami Hiramatsu (Google) val = *(unsigned long *)((unsigned long)edata + code->offset);
15925f00e40SMasami Hiramatsu (Google) break;
160334e5519SMasami Hiramatsu (Google) #endif
161334e5519SMasami Hiramatsu (Google) case FETCH_NOP_SYMBOL: /* Ignore a place holder */
162334e5519SMasami Hiramatsu (Google) code++;
163334e5519SMasami Hiramatsu (Google) goto retry;
164334e5519SMasami Hiramatsu (Google) default:
165334e5519SMasami Hiramatsu (Google) ret = process_common_fetch_insn(code, &val);
166334e5519SMasami Hiramatsu (Google) if (ret < 0)
167334e5519SMasami Hiramatsu (Google) return ret;
168334e5519SMasami Hiramatsu (Google) }
169334e5519SMasami Hiramatsu (Google) code++;
170334e5519SMasami Hiramatsu (Google)
171334e5519SMasami Hiramatsu (Google) return process_fetch_insn_bottom(code, val, dest, base);
172334e5519SMasami Hiramatsu (Google) }
NOKPROBE_SYMBOL(process_fetch_insn)173334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(process_fetch_insn)
174334e5519SMasami Hiramatsu (Google)
175334e5519SMasami Hiramatsu (Google) /* function entry handler */
176334e5519SMasami Hiramatsu (Google) static nokprobe_inline void
177334e5519SMasami Hiramatsu (Google) __fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
1780566cefeSMasami Hiramatsu (Google) struct ftrace_regs *fregs,
179334e5519SMasami Hiramatsu (Google) struct trace_event_file *trace_file)
180334e5519SMasami Hiramatsu (Google) {
181334e5519SMasami Hiramatsu (Google) struct fentry_trace_entry_head *entry;
182334e5519SMasami Hiramatsu (Google) struct trace_event_call *call = trace_probe_event_call(&tf->tp);
183334e5519SMasami Hiramatsu (Google) struct trace_event_buffer fbuffer;
184334e5519SMasami Hiramatsu (Google) int dsize;
185334e5519SMasami Hiramatsu (Google)
186334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(call != trace_file->event_call))
187334e5519SMasami Hiramatsu (Google) return;
188334e5519SMasami Hiramatsu (Google)
189334e5519SMasami Hiramatsu (Google) if (trace_trigger_soft_disabled(trace_file))
190334e5519SMasami Hiramatsu (Google) return;
191334e5519SMasami Hiramatsu (Google)
1920566cefeSMasami Hiramatsu (Google) dsize = __get_data_size(&tf->tp, fregs, NULL);
193334e5519SMasami Hiramatsu (Google)
194334e5519SMasami Hiramatsu (Google) entry = trace_event_buffer_reserve(&fbuffer, trace_file,
195334e5519SMasami Hiramatsu (Google) sizeof(*entry) + tf->tp.size + dsize);
196334e5519SMasami Hiramatsu (Google) if (!entry)
197334e5519SMasami Hiramatsu (Google) return;
198334e5519SMasami Hiramatsu (Google)
1990566cefeSMasami Hiramatsu (Google) fbuffer.regs = ftrace_get_regs(fregs);
200334e5519SMasami Hiramatsu (Google) entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
201334e5519SMasami Hiramatsu (Google) entry->ip = entry_ip;
2020566cefeSMasami Hiramatsu (Google) store_trace_args(&entry[1], &tf->tp, fregs, NULL, sizeof(*entry), dsize);
203334e5519SMasami Hiramatsu (Google)
204334e5519SMasami Hiramatsu (Google) trace_event_buffer_commit(&fbuffer);
205334e5519SMasami Hiramatsu (Google) }
206334e5519SMasami Hiramatsu (Google)
207334e5519SMasami Hiramatsu (Google) static void
fentry_trace_func(struct trace_fprobe * tf,unsigned long entry_ip,struct ftrace_regs * fregs)208334e5519SMasami Hiramatsu (Google) fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
2090566cefeSMasami Hiramatsu (Google) struct ftrace_regs *fregs)
210334e5519SMasami Hiramatsu (Google) {
211334e5519SMasami Hiramatsu (Google) struct event_file_link *link;
212334e5519SMasami Hiramatsu (Google)
213334e5519SMasami Hiramatsu (Google) trace_probe_for_each_link_rcu(link, &tf->tp)
2140566cefeSMasami Hiramatsu (Google) __fentry_trace_func(tf, entry_ip, fregs, link->file);
215334e5519SMasami Hiramatsu (Google) }
216334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(fentry_trace_func);
217334e5519SMasami Hiramatsu (Google)
2180566cefeSMasami Hiramatsu (Google) static nokprobe_inline
store_fprobe_entry_data(void * edata,struct trace_probe * tp,struct ftrace_regs * fregs)2190566cefeSMasami Hiramatsu (Google) void store_fprobe_entry_data(void *edata, struct trace_probe *tp, struct ftrace_regs *fregs)
2200566cefeSMasami Hiramatsu (Google) {
2210566cefeSMasami Hiramatsu (Google) struct probe_entry_arg *earg = tp->entry_arg;
2220566cefeSMasami Hiramatsu (Google) unsigned long val = 0;
2230566cefeSMasami Hiramatsu (Google) int i;
2240566cefeSMasami Hiramatsu (Google)
2250566cefeSMasami Hiramatsu (Google) if (!earg)
2260566cefeSMasami Hiramatsu (Google) return;
2270566cefeSMasami Hiramatsu (Google)
2280566cefeSMasami Hiramatsu (Google) for (i = 0; i < earg->size; i++) {
2290566cefeSMasami Hiramatsu (Google) struct fetch_insn *code = &earg->code[i];
2300566cefeSMasami Hiramatsu (Google)
2310566cefeSMasami Hiramatsu (Google) switch (code->op) {
2320566cefeSMasami Hiramatsu (Google) case FETCH_OP_ARG:
2330566cefeSMasami Hiramatsu (Google) val = ftrace_regs_get_argument(fregs, code->param);
2340566cefeSMasami Hiramatsu (Google) break;
2350566cefeSMasami Hiramatsu (Google) case FETCH_OP_ST_EDATA:
2360566cefeSMasami Hiramatsu (Google) *(unsigned long *)((unsigned long)edata + code->offset) = val;
2370566cefeSMasami Hiramatsu (Google) break;
2380566cefeSMasami Hiramatsu (Google) case FETCH_OP_END:
2390566cefeSMasami Hiramatsu (Google) goto end;
2400566cefeSMasami Hiramatsu (Google) default:
2410566cefeSMasami Hiramatsu (Google) break;
2420566cefeSMasami Hiramatsu (Google) }
2430566cefeSMasami Hiramatsu (Google) }
2440566cefeSMasami Hiramatsu (Google) end:
2450566cefeSMasami Hiramatsu (Google) return;
2460566cefeSMasami Hiramatsu (Google) }
2470566cefeSMasami Hiramatsu (Google)
2487e37b6bcSMasami Hiramatsu (Google) /* function exit handler */
trace_fprobe_entry_handler(struct fprobe * fp,unsigned long entry_ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * entry_data)24925f00e40SMasami Hiramatsu (Google) static int trace_fprobe_entry_handler(struct fprobe *fp, unsigned long entry_ip,
25046bc0823SMasami Hiramatsu (Google) unsigned long ret_ip, struct ftrace_regs *fregs,
25125f00e40SMasami Hiramatsu (Google) void *entry_data)
25225f00e40SMasami Hiramatsu (Google) {
25325f00e40SMasami Hiramatsu (Google) struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
25425f00e40SMasami Hiramatsu (Google)
2550566cefeSMasami Hiramatsu (Google) if (tf->tp.entry_arg)
2560566cefeSMasami Hiramatsu (Google) store_fprobe_entry_data(entry_data, &tf->tp, fregs);
25725f00e40SMasami Hiramatsu (Google)
25825f00e40SMasami Hiramatsu (Google) return 0;
25925f00e40SMasami Hiramatsu (Google) }
NOKPROBE_SYMBOL(trace_fprobe_entry_handler)26025f00e40SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(trace_fprobe_entry_handler)
26125f00e40SMasami Hiramatsu (Google)
262334e5519SMasami Hiramatsu (Google) static nokprobe_inline void
263334e5519SMasami Hiramatsu (Google) __fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
2640566cefeSMasami Hiramatsu (Google) unsigned long ret_ip, struct ftrace_regs *fregs,
26525f00e40SMasami Hiramatsu (Google) void *entry_data, struct trace_event_file *trace_file)
266334e5519SMasami Hiramatsu (Google) {
267334e5519SMasami Hiramatsu (Google) struct fexit_trace_entry_head *entry;
268334e5519SMasami Hiramatsu (Google) struct trace_event_buffer fbuffer;
269334e5519SMasami Hiramatsu (Google) struct trace_event_call *call = trace_probe_event_call(&tf->tp);
270334e5519SMasami Hiramatsu (Google) int dsize;
271334e5519SMasami Hiramatsu (Google)
272334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(call != trace_file->event_call))
273334e5519SMasami Hiramatsu (Google) return;
274334e5519SMasami Hiramatsu (Google)
275334e5519SMasami Hiramatsu (Google) if (trace_trigger_soft_disabled(trace_file))
276334e5519SMasami Hiramatsu (Google) return;
277334e5519SMasami Hiramatsu (Google)
2780566cefeSMasami Hiramatsu (Google) dsize = __get_data_size(&tf->tp, fregs, entry_data);
279334e5519SMasami Hiramatsu (Google)
280334e5519SMasami Hiramatsu (Google) entry = trace_event_buffer_reserve(&fbuffer, trace_file,
281334e5519SMasami Hiramatsu (Google) sizeof(*entry) + tf->tp.size + dsize);
282334e5519SMasami Hiramatsu (Google) if (!entry)
283334e5519SMasami Hiramatsu (Google) return;
284334e5519SMasami Hiramatsu (Google)
2850566cefeSMasami Hiramatsu (Google) fbuffer.regs = ftrace_get_regs(fregs);
286334e5519SMasami Hiramatsu (Google) entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
287334e5519SMasami Hiramatsu (Google) entry->func = entry_ip;
288334e5519SMasami Hiramatsu (Google) entry->ret_ip = ret_ip;
2890566cefeSMasami Hiramatsu (Google) store_trace_args(&entry[1], &tf->tp, fregs, entry_data, sizeof(*entry), dsize);
290334e5519SMasami Hiramatsu (Google)
291334e5519SMasami Hiramatsu (Google) trace_event_buffer_commit(&fbuffer);
292334e5519SMasami Hiramatsu (Google) }
293334e5519SMasami Hiramatsu (Google)
294334e5519SMasami Hiramatsu (Google) static void
fexit_trace_func(struct trace_fprobe * tf,unsigned long entry_ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * entry_data)295334e5519SMasami Hiramatsu (Google) fexit_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
2960566cefeSMasami Hiramatsu (Google) unsigned long ret_ip, struct ftrace_regs *fregs, void *entry_data)
297334e5519SMasami Hiramatsu (Google) {
298334e5519SMasami Hiramatsu (Google) struct event_file_link *link;
299334e5519SMasami Hiramatsu (Google)
300334e5519SMasami Hiramatsu (Google) trace_probe_for_each_link_rcu(link, &tf->tp)
3010566cefeSMasami Hiramatsu (Google) __fexit_trace_func(tf, entry_ip, ret_ip, fregs, entry_data, link->file);
302334e5519SMasami Hiramatsu (Google) }
303334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(fexit_trace_func);
304334e5519SMasami Hiramatsu (Google)
305334e5519SMasami Hiramatsu (Google) #ifdef CONFIG_PERF_EVENTS
306334e5519SMasami Hiramatsu (Google)
fentry_perf_func(struct trace_fprobe * tf,unsigned long entry_ip,struct ftrace_regs * fregs)307334e5519SMasami Hiramatsu (Google) static int fentry_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
3080566cefeSMasami Hiramatsu (Google) struct ftrace_regs *fregs)
309334e5519SMasami Hiramatsu (Google) {
310334e5519SMasami Hiramatsu (Google) struct trace_event_call *call = trace_probe_event_call(&tf->tp);
311334e5519SMasami Hiramatsu (Google) struct fentry_trace_entry_head *entry;
312334e5519SMasami Hiramatsu (Google) struct hlist_head *head;
313334e5519SMasami Hiramatsu (Google) int size, __size, dsize;
3140566cefeSMasami Hiramatsu (Google) struct pt_regs *regs;
315334e5519SMasami Hiramatsu (Google) int rctx;
316334e5519SMasami Hiramatsu (Google)
317334e5519SMasami Hiramatsu (Google) head = this_cpu_ptr(call->perf_events);
318334e5519SMasami Hiramatsu (Google) if (hlist_empty(head))
319334e5519SMasami Hiramatsu (Google) return 0;
320334e5519SMasami Hiramatsu (Google)
3210566cefeSMasami Hiramatsu (Google) dsize = __get_data_size(&tf->tp, fregs, NULL);
322334e5519SMasami Hiramatsu (Google) __size = sizeof(*entry) + tf->tp.size + dsize;
323334e5519SMasami Hiramatsu (Google) size = ALIGN(__size + sizeof(u32), sizeof(u64));
324334e5519SMasami Hiramatsu (Google) size -= sizeof(u32);
325334e5519SMasami Hiramatsu (Google)
3260566cefeSMasami Hiramatsu (Google) entry = perf_trace_buf_alloc(size, ®s, &rctx);
327334e5519SMasami Hiramatsu (Google) if (!entry)
328334e5519SMasami Hiramatsu (Google) return 0;
329334e5519SMasami Hiramatsu (Google)
3300566cefeSMasami Hiramatsu (Google) regs = ftrace_fill_perf_regs(fregs, regs);
3310566cefeSMasami Hiramatsu (Google)
332334e5519SMasami Hiramatsu (Google) entry->ip = entry_ip;
333334e5519SMasami Hiramatsu (Google) memset(&entry[1], 0, dsize);
3340566cefeSMasami Hiramatsu (Google) store_trace_args(&entry[1], &tf->tp, fregs, NULL, sizeof(*entry), dsize);
335334e5519SMasami Hiramatsu (Google) perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
336334e5519SMasami Hiramatsu (Google) head, NULL);
337334e5519SMasami Hiramatsu (Google) return 0;
338334e5519SMasami Hiramatsu (Google) }
339334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(fentry_perf_func);
340334e5519SMasami Hiramatsu (Google)
341334e5519SMasami Hiramatsu (Google) static void
fexit_perf_func(struct trace_fprobe * tf,unsigned long entry_ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * entry_data)342334e5519SMasami Hiramatsu (Google) fexit_perf_func(struct trace_fprobe *tf, unsigned long entry_ip,
3430566cefeSMasami Hiramatsu (Google) unsigned long ret_ip, struct ftrace_regs *fregs,
34425f00e40SMasami Hiramatsu (Google) void *entry_data)
345334e5519SMasami Hiramatsu (Google) {
346334e5519SMasami Hiramatsu (Google) struct trace_event_call *call = trace_probe_event_call(&tf->tp);
347334e5519SMasami Hiramatsu (Google) struct fexit_trace_entry_head *entry;
348334e5519SMasami Hiramatsu (Google) struct hlist_head *head;
349334e5519SMasami Hiramatsu (Google) int size, __size, dsize;
3500566cefeSMasami Hiramatsu (Google) struct pt_regs *regs;
351334e5519SMasami Hiramatsu (Google) int rctx;
352334e5519SMasami Hiramatsu (Google)
353334e5519SMasami Hiramatsu (Google) head = this_cpu_ptr(call->perf_events);
354334e5519SMasami Hiramatsu (Google) if (hlist_empty(head))
355334e5519SMasami Hiramatsu (Google) return;
356334e5519SMasami Hiramatsu (Google)
3570566cefeSMasami Hiramatsu (Google) dsize = __get_data_size(&tf->tp, fregs, entry_data);
358334e5519SMasami Hiramatsu (Google) __size = sizeof(*entry) + tf->tp.size + dsize;
359334e5519SMasami Hiramatsu (Google) size = ALIGN(__size + sizeof(u32), sizeof(u64));
360334e5519SMasami Hiramatsu (Google) size -= sizeof(u32);
361334e5519SMasami Hiramatsu (Google)
3620566cefeSMasami Hiramatsu (Google) entry = perf_trace_buf_alloc(size, ®s, &rctx);
363334e5519SMasami Hiramatsu (Google) if (!entry)
364334e5519SMasami Hiramatsu (Google) return;
365334e5519SMasami Hiramatsu (Google)
3660566cefeSMasami Hiramatsu (Google) regs = ftrace_fill_perf_regs(fregs, regs);
3670566cefeSMasami Hiramatsu (Google)
368334e5519SMasami Hiramatsu (Google) entry->func = entry_ip;
369334e5519SMasami Hiramatsu (Google) entry->ret_ip = ret_ip;
3700566cefeSMasami Hiramatsu (Google) store_trace_args(&entry[1], &tf->tp, fregs, entry_data, sizeof(*entry), dsize);
371334e5519SMasami Hiramatsu (Google) perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs,
372334e5519SMasami Hiramatsu (Google) head, NULL);
373334e5519SMasami Hiramatsu (Google) }
374334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(fexit_perf_func);
375334e5519SMasami Hiramatsu (Google) #endif /* CONFIG_PERF_EVENTS */
376334e5519SMasami Hiramatsu (Google)
fentry_dispatcher(struct fprobe * fp,unsigned long entry_ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * entry_data)377334e5519SMasami Hiramatsu (Google) static int fentry_dispatcher(struct fprobe *fp, unsigned long entry_ip,
37846bc0823SMasami Hiramatsu (Google) unsigned long ret_ip, struct ftrace_regs *fregs,
379334e5519SMasami Hiramatsu (Google) void *entry_data)
380334e5519SMasami Hiramatsu (Google) {
381334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
382334e5519SMasami Hiramatsu (Google) int ret = 0;
383334e5519SMasami Hiramatsu (Google)
384334e5519SMasami Hiramatsu (Google) if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE))
3850566cefeSMasami Hiramatsu (Google) fentry_trace_func(tf, entry_ip, fregs);
3860566cefeSMasami Hiramatsu (Google)
387334e5519SMasami Hiramatsu (Google) #ifdef CONFIG_PERF_EVENTS
388334e5519SMasami Hiramatsu (Google) if (trace_probe_test_flag(&tf->tp, TP_FLAG_PROFILE))
3890566cefeSMasami Hiramatsu (Google) ret = fentry_perf_func(tf, entry_ip, fregs);
390334e5519SMasami Hiramatsu (Google) #endif
391334e5519SMasami Hiramatsu (Google) return ret;
392334e5519SMasami Hiramatsu (Google) }
393334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(fentry_dispatcher);
394334e5519SMasami Hiramatsu (Google)
fexit_dispatcher(struct fprobe * fp,unsigned long entry_ip,unsigned long ret_ip,struct ftrace_regs * fregs,void * entry_data)395334e5519SMasami Hiramatsu (Google) static void fexit_dispatcher(struct fprobe *fp, unsigned long entry_ip,
396762abbc0SMasami Hiramatsu (Google) unsigned long ret_ip, struct ftrace_regs *fregs,
397334e5519SMasami Hiramatsu (Google) void *entry_data)
398334e5519SMasami Hiramatsu (Google) {
399334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf = container_of(fp, struct trace_fprobe, fp);
400334e5519SMasami Hiramatsu (Google)
401334e5519SMasami Hiramatsu (Google) if (trace_probe_test_flag(&tf->tp, TP_FLAG_TRACE))
4020566cefeSMasami Hiramatsu (Google) fexit_trace_func(tf, entry_ip, ret_ip, fregs, entry_data);
403334e5519SMasami Hiramatsu (Google) #ifdef CONFIG_PERF_EVENTS
404334e5519SMasami Hiramatsu (Google) if (trace_probe_test_flag(&tf->tp, TP_FLAG_PROFILE))
4050566cefeSMasami Hiramatsu (Google) fexit_perf_func(tf, entry_ip, ret_ip, fregs, entry_data);
406334e5519SMasami Hiramatsu (Google) #endif
407334e5519SMasami Hiramatsu (Google) }
408334e5519SMasami Hiramatsu (Google) NOKPROBE_SYMBOL(fexit_dispatcher);
409334e5519SMasami Hiramatsu (Google)
free_trace_fprobe(struct trace_fprobe * tf)410334e5519SMasami Hiramatsu (Google) static void free_trace_fprobe(struct trace_fprobe *tf)
411334e5519SMasami Hiramatsu (Google) {
412334e5519SMasami Hiramatsu (Google) if (tf) {
413334e5519SMasami Hiramatsu (Google) trace_probe_cleanup(&tf->tp);
414334e5519SMasami Hiramatsu (Google) kfree(tf->symbol);
415334e5519SMasami Hiramatsu (Google) kfree(tf);
416334e5519SMasami Hiramatsu (Google) }
417334e5519SMasami Hiramatsu (Google) }
418334e5519SMasami Hiramatsu (Google)
41982756372SMasami Hiramatsu (Google) /* Since alloc_trace_fprobe() can return error, check the pointer is ERR too. */
42082756372SMasami Hiramatsu (Google) DEFINE_FREE(free_trace_fprobe, struct trace_fprobe *, if (!IS_ERR_OR_NULL(_T)) free_trace_fprobe(_T))
42182756372SMasami Hiramatsu (Google)
422334e5519SMasami Hiramatsu (Google) /*
423334e5519SMasami Hiramatsu (Google) * Allocate new trace_probe and initialize it (including fprobe).
424334e5519SMasami Hiramatsu (Google) */
alloc_trace_fprobe(const char * group,const char * event,const char * symbol,struct tracepoint * tpoint,struct module * mod,int nargs,bool is_return)425334e5519SMasami Hiramatsu (Google) static struct trace_fprobe *alloc_trace_fprobe(const char *group,
426334e5519SMasami Hiramatsu (Google) const char *event,
427334e5519SMasami Hiramatsu (Google) const char *symbol,
428b576e097SMasami Hiramatsu (Google) struct tracepoint *tpoint,
42967e9a9eeSMasami Hiramatsu (Google) struct module *mod,
430334e5519SMasami Hiramatsu (Google) int nargs, bool is_return)
431334e5519SMasami Hiramatsu (Google) {
43282756372SMasami Hiramatsu (Google) struct trace_fprobe *tf __free(free_trace_fprobe) = NULL;
433334e5519SMasami Hiramatsu (Google) int ret = -ENOMEM;
434334e5519SMasami Hiramatsu (Google)
435334e5519SMasami Hiramatsu (Google) tf = kzalloc(struct_size(tf, tp.args, nargs), GFP_KERNEL);
436334e5519SMasami Hiramatsu (Google) if (!tf)
437334e5519SMasami Hiramatsu (Google) return ERR_PTR(ret);
438334e5519SMasami Hiramatsu (Google)
439334e5519SMasami Hiramatsu (Google) tf->symbol = kstrdup(symbol, GFP_KERNEL);
440334e5519SMasami Hiramatsu (Google) if (!tf->symbol)
44182756372SMasami Hiramatsu (Google) return ERR_PTR(-ENOMEM);
442334e5519SMasami Hiramatsu (Google)
443334e5519SMasami Hiramatsu (Google) if (is_return)
444334e5519SMasami Hiramatsu (Google) tf->fp.exit_handler = fexit_dispatcher;
445334e5519SMasami Hiramatsu (Google) else
446334e5519SMasami Hiramatsu (Google) tf->fp.entry_handler = fentry_dispatcher;
447334e5519SMasami Hiramatsu (Google)
448b576e097SMasami Hiramatsu (Google) tf->tpoint = tpoint;
44967e9a9eeSMasami Hiramatsu (Google) tf->mod = mod;
450334e5519SMasami Hiramatsu (Google)
451035ba760SMasami Hiramatsu (Google) ret = trace_probe_init(&tf->tp, event, group, false, nargs);
452334e5519SMasami Hiramatsu (Google) if (ret < 0)
45382756372SMasami Hiramatsu (Google) return ERR_PTR(ret);
454334e5519SMasami Hiramatsu (Google)
455334e5519SMasami Hiramatsu (Google) dyn_event_init(&tf->devent, &trace_fprobe_ops);
45682756372SMasami Hiramatsu (Google) return_ptr(tf);
457334e5519SMasami Hiramatsu (Google) }
458334e5519SMasami Hiramatsu (Google)
find_trace_fprobe(const char * event,const char * group)459334e5519SMasami Hiramatsu (Google) static struct trace_fprobe *find_trace_fprobe(const char *event,
460334e5519SMasami Hiramatsu (Google) const char *group)
461334e5519SMasami Hiramatsu (Google) {
462334e5519SMasami Hiramatsu (Google) struct dyn_event *pos;
463334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf;
464334e5519SMasami Hiramatsu (Google)
465334e5519SMasami Hiramatsu (Google) for_each_trace_fprobe(tf, pos)
466334e5519SMasami Hiramatsu (Google) if (strcmp(trace_probe_name(&tf->tp), event) == 0 &&
467334e5519SMasami Hiramatsu (Google) strcmp(trace_probe_group_name(&tf->tp), group) == 0)
468334e5519SMasami Hiramatsu (Google) return tf;
469334e5519SMasami Hiramatsu (Google) return NULL;
470334e5519SMasami Hiramatsu (Google) }
471334e5519SMasami Hiramatsu (Google)
__enable_trace_fprobe(struct trace_fprobe * tf)472334e5519SMasami Hiramatsu (Google) static inline int __enable_trace_fprobe(struct trace_fprobe *tf)
473334e5519SMasami Hiramatsu (Google) {
474334e5519SMasami Hiramatsu (Google) if (trace_fprobe_is_registered(tf))
475334e5519SMasami Hiramatsu (Google) enable_fprobe(&tf->fp);
476334e5519SMasami Hiramatsu (Google)
477334e5519SMasami Hiramatsu (Google) return 0;
478334e5519SMasami Hiramatsu (Google) }
479334e5519SMasami Hiramatsu (Google)
__disable_trace_fprobe(struct trace_probe * tp)480334e5519SMasami Hiramatsu (Google) static void __disable_trace_fprobe(struct trace_probe *tp)
481334e5519SMasami Hiramatsu (Google) {
482334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf;
483334e5519SMasami Hiramatsu (Google)
484334e5519SMasami Hiramatsu (Google) list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list) {
485334e5519SMasami Hiramatsu (Google) if (!trace_fprobe_is_registered(tf))
486334e5519SMasami Hiramatsu (Google) continue;
487334e5519SMasami Hiramatsu (Google) disable_fprobe(&tf->fp);
488334e5519SMasami Hiramatsu (Google) }
489334e5519SMasami Hiramatsu (Google) }
490334e5519SMasami Hiramatsu (Google)
491334e5519SMasami Hiramatsu (Google) /*
492334e5519SMasami Hiramatsu (Google) * Enable trace_probe
493334e5519SMasami Hiramatsu (Google) * if the file is NULL, enable "perf" handler, or enable "trace" handler.
494334e5519SMasami Hiramatsu (Google) */
enable_trace_fprobe(struct trace_event_call * call,struct trace_event_file * file)495334e5519SMasami Hiramatsu (Google) static int enable_trace_fprobe(struct trace_event_call *call,
496334e5519SMasami Hiramatsu (Google) struct trace_event_file *file)
497334e5519SMasami Hiramatsu (Google) {
498334e5519SMasami Hiramatsu (Google) struct trace_probe *tp;
499334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf;
500334e5519SMasami Hiramatsu (Google) bool enabled;
501334e5519SMasami Hiramatsu (Google) int ret = 0;
502334e5519SMasami Hiramatsu (Google)
503334e5519SMasami Hiramatsu (Google) tp = trace_probe_primary_from_call(call);
504334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(!tp))
505334e5519SMasami Hiramatsu (Google) return -ENODEV;
506334e5519SMasami Hiramatsu (Google) enabled = trace_probe_is_enabled(tp);
507334e5519SMasami Hiramatsu (Google)
508334e5519SMasami Hiramatsu (Google) /* This also changes "enabled" state */
509334e5519SMasami Hiramatsu (Google) if (file) {
510334e5519SMasami Hiramatsu (Google) ret = trace_probe_add_file(tp, file);
511334e5519SMasami Hiramatsu (Google) if (ret)
512334e5519SMasami Hiramatsu (Google) return ret;
513334e5519SMasami Hiramatsu (Google) } else
514334e5519SMasami Hiramatsu (Google) trace_probe_set_flag(tp, TP_FLAG_PROFILE);
515334e5519SMasami Hiramatsu (Google)
516334e5519SMasami Hiramatsu (Google) if (!enabled) {
517334e5519SMasami Hiramatsu (Google) list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list) {
518334e5519SMasami Hiramatsu (Google) /* TODO: check the fprobe is gone */
519334e5519SMasami Hiramatsu (Google) __enable_trace_fprobe(tf);
520334e5519SMasami Hiramatsu (Google) }
521334e5519SMasami Hiramatsu (Google) }
522334e5519SMasami Hiramatsu (Google)
523334e5519SMasami Hiramatsu (Google) return 0;
524334e5519SMasami Hiramatsu (Google) }
525334e5519SMasami Hiramatsu (Google)
526334e5519SMasami Hiramatsu (Google) /*
527334e5519SMasami Hiramatsu (Google) * Disable trace_probe
528334e5519SMasami Hiramatsu (Google) * if the file is NULL, disable "perf" handler, or disable "trace" handler.
529334e5519SMasami Hiramatsu (Google) */
disable_trace_fprobe(struct trace_event_call * call,struct trace_event_file * file)530334e5519SMasami Hiramatsu (Google) static int disable_trace_fprobe(struct trace_event_call *call,
531334e5519SMasami Hiramatsu (Google) struct trace_event_file *file)
532334e5519SMasami Hiramatsu (Google) {
533334e5519SMasami Hiramatsu (Google) struct trace_probe *tp;
534334e5519SMasami Hiramatsu (Google)
535334e5519SMasami Hiramatsu (Google) tp = trace_probe_primary_from_call(call);
536334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(!tp))
537334e5519SMasami Hiramatsu (Google) return -ENODEV;
538334e5519SMasami Hiramatsu (Google)
539334e5519SMasami Hiramatsu (Google) if (file) {
540334e5519SMasami Hiramatsu (Google) if (!trace_probe_get_file_link(tp, file))
541334e5519SMasami Hiramatsu (Google) return -ENOENT;
542334e5519SMasami Hiramatsu (Google) if (!trace_probe_has_single_file(tp))
543334e5519SMasami Hiramatsu (Google) goto out;
544334e5519SMasami Hiramatsu (Google) trace_probe_clear_flag(tp, TP_FLAG_TRACE);
545334e5519SMasami Hiramatsu (Google) } else
546334e5519SMasami Hiramatsu (Google) trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
547334e5519SMasami Hiramatsu (Google)
548334e5519SMasami Hiramatsu (Google) if (!trace_probe_is_enabled(tp))
549334e5519SMasami Hiramatsu (Google) __disable_trace_fprobe(tp);
550334e5519SMasami Hiramatsu (Google)
551334e5519SMasami Hiramatsu (Google) out:
552334e5519SMasami Hiramatsu (Google) if (file)
553334e5519SMasami Hiramatsu (Google) /*
554334e5519SMasami Hiramatsu (Google) * Synchronization is done in below function. For perf event,
555334e5519SMasami Hiramatsu (Google) * file == NULL and perf_trace_event_unreg() calls
556334e5519SMasami Hiramatsu (Google) * tracepoint_synchronize_unregister() to ensure synchronize
557334e5519SMasami Hiramatsu (Google) * event. We don't need to care about it.
558334e5519SMasami Hiramatsu (Google) */
559334e5519SMasami Hiramatsu (Google) trace_probe_remove_file(tp, file);
560334e5519SMasami Hiramatsu (Google)
561334e5519SMasami Hiramatsu (Google) return 0;
562334e5519SMasami Hiramatsu (Google) }
563334e5519SMasami Hiramatsu (Google)
564334e5519SMasami Hiramatsu (Google) /* Event entry printers */
565334e5519SMasami Hiramatsu (Google) static enum print_line_t
print_fentry_event(struct trace_iterator * iter,int flags,struct trace_event * event)566334e5519SMasami Hiramatsu (Google) print_fentry_event(struct trace_iterator *iter, int flags,
567334e5519SMasami Hiramatsu (Google) struct trace_event *event)
568334e5519SMasami Hiramatsu (Google) {
569334e5519SMasami Hiramatsu (Google) struct fentry_trace_entry_head *field;
570334e5519SMasami Hiramatsu (Google) struct trace_seq *s = &iter->seq;
571334e5519SMasami Hiramatsu (Google) struct trace_probe *tp;
572334e5519SMasami Hiramatsu (Google)
573334e5519SMasami Hiramatsu (Google) field = (struct fentry_trace_entry_head *)iter->ent;
574334e5519SMasami Hiramatsu (Google) tp = trace_probe_primary_from_call(
575334e5519SMasami Hiramatsu (Google) container_of(event, struct trace_event_call, event));
576334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(!tp))
577334e5519SMasami Hiramatsu (Google) goto out;
578334e5519SMasami Hiramatsu (Google)
579334e5519SMasami Hiramatsu (Google) trace_seq_printf(s, "%s: (", trace_probe_name(tp));
580334e5519SMasami Hiramatsu (Google)
581334e5519SMasami Hiramatsu (Google) if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
582334e5519SMasami Hiramatsu (Google) goto out;
583334e5519SMasami Hiramatsu (Google)
584334e5519SMasami Hiramatsu (Google) trace_seq_putc(s, ')');
585334e5519SMasami Hiramatsu (Google)
586334e5519SMasami Hiramatsu (Google) if (trace_probe_print_args(s, tp->args, tp->nr_args,
587334e5519SMasami Hiramatsu (Google) (u8 *)&field[1], field) < 0)
588334e5519SMasami Hiramatsu (Google) goto out;
589334e5519SMasami Hiramatsu (Google)
590334e5519SMasami Hiramatsu (Google) trace_seq_putc(s, '\n');
591334e5519SMasami Hiramatsu (Google) out:
592334e5519SMasami Hiramatsu (Google) return trace_handle_return(s);
593334e5519SMasami Hiramatsu (Google) }
594334e5519SMasami Hiramatsu (Google)
595334e5519SMasami Hiramatsu (Google) static enum print_line_t
print_fexit_event(struct trace_iterator * iter,int flags,struct trace_event * event)596334e5519SMasami Hiramatsu (Google) print_fexit_event(struct trace_iterator *iter, int flags,
597334e5519SMasami Hiramatsu (Google) struct trace_event *event)
598334e5519SMasami Hiramatsu (Google) {
599334e5519SMasami Hiramatsu (Google) struct fexit_trace_entry_head *field;
600334e5519SMasami Hiramatsu (Google) struct trace_seq *s = &iter->seq;
601334e5519SMasami Hiramatsu (Google) struct trace_probe *tp;
602334e5519SMasami Hiramatsu (Google)
603334e5519SMasami Hiramatsu (Google) field = (struct fexit_trace_entry_head *)iter->ent;
604334e5519SMasami Hiramatsu (Google) tp = trace_probe_primary_from_call(
605334e5519SMasami Hiramatsu (Google) container_of(event, struct trace_event_call, event));
606334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(!tp))
607334e5519SMasami Hiramatsu (Google) goto out;
608334e5519SMasami Hiramatsu (Google)
609334e5519SMasami Hiramatsu (Google) trace_seq_printf(s, "%s: (", trace_probe_name(tp));
610334e5519SMasami Hiramatsu (Google)
611334e5519SMasami Hiramatsu (Google) if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET))
612334e5519SMasami Hiramatsu (Google) goto out;
613334e5519SMasami Hiramatsu (Google)
614334e5519SMasami Hiramatsu (Google) trace_seq_puts(s, " <- ");
615334e5519SMasami Hiramatsu (Google)
616334e5519SMasami Hiramatsu (Google) if (!seq_print_ip_sym(s, field->func, flags & ~TRACE_ITER_SYM_OFFSET))
617334e5519SMasami Hiramatsu (Google) goto out;
618334e5519SMasami Hiramatsu (Google)
619334e5519SMasami Hiramatsu (Google) trace_seq_putc(s, ')');
620334e5519SMasami Hiramatsu (Google)
621334e5519SMasami Hiramatsu (Google) if (trace_probe_print_args(s, tp->args, tp->nr_args,
622334e5519SMasami Hiramatsu (Google) (u8 *)&field[1], field) < 0)
623334e5519SMasami Hiramatsu (Google) goto out;
624334e5519SMasami Hiramatsu (Google)
625334e5519SMasami Hiramatsu (Google) trace_seq_putc(s, '\n');
626334e5519SMasami Hiramatsu (Google)
627334e5519SMasami Hiramatsu (Google) out:
628334e5519SMasami Hiramatsu (Google) return trace_handle_return(s);
629334e5519SMasami Hiramatsu (Google) }
630334e5519SMasami Hiramatsu (Google)
fentry_event_define_fields(struct trace_event_call * event_call)631334e5519SMasami Hiramatsu (Google) static int fentry_event_define_fields(struct trace_event_call *event_call)
632334e5519SMasami Hiramatsu (Google) {
633334e5519SMasami Hiramatsu (Google) int ret;
634334e5519SMasami Hiramatsu (Google) struct fentry_trace_entry_head field;
635334e5519SMasami Hiramatsu (Google) struct trace_probe *tp;
636334e5519SMasami Hiramatsu (Google)
637334e5519SMasami Hiramatsu (Google) tp = trace_probe_primary_from_call(event_call);
638334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(!tp))
639334e5519SMasami Hiramatsu (Google) return -ENOENT;
640334e5519SMasami Hiramatsu (Google)
641334e5519SMasami Hiramatsu (Google) DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
642334e5519SMasami Hiramatsu (Google)
643334e5519SMasami Hiramatsu (Google) return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
644334e5519SMasami Hiramatsu (Google) }
645334e5519SMasami Hiramatsu (Google)
fexit_event_define_fields(struct trace_event_call * event_call)646334e5519SMasami Hiramatsu (Google) static int fexit_event_define_fields(struct trace_event_call *event_call)
647334e5519SMasami Hiramatsu (Google) {
648334e5519SMasami Hiramatsu (Google) int ret;
649334e5519SMasami Hiramatsu (Google) struct fexit_trace_entry_head field;
650334e5519SMasami Hiramatsu (Google) struct trace_probe *tp;
651334e5519SMasami Hiramatsu (Google)
652334e5519SMasami Hiramatsu (Google) tp = trace_probe_primary_from_call(event_call);
653334e5519SMasami Hiramatsu (Google) if (WARN_ON_ONCE(!tp))
654334e5519SMasami Hiramatsu (Google) return -ENOENT;
655334e5519SMasami Hiramatsu (Google)
656334e5519SMasami Hiramatsu (Google) DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0);
657334e5519SMasami Hiramatsu (Google) DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0);
658334e5519SMasami Hiramatsu (Google)
659334e5519SMasami Hiramatsu (Google) return traceprobe_define_arg_fields(event_call, sizeof(field), tp);
660334e5519SMasami Hiramatsu (Google) }
661334e5519SMasami Hiramatsu (Google)
662334e5519SMasami Hiramatsu (Google) static struct trace_event_functions fentry_funcs = {
663334e5519SMasami Hiramatsu (Google) .trace = print_fentry_event
664334e5519SMasami Hiramatsu (Google) };
665334e5519SMasami Hiramatsu (Google)
666334e5519SMasami Hiramatsu (Google) static struct trace_event_functions fexit_funcs = {
667334e5519SMasami Hiramatsu (Google) .trace = print_fexit_event
668334e5519SMasami Hiramatsu (Google) };
669334e5519SMasami Hiramatsu (Google)
670334e5519SMasami Hiramatsu (Google) static struct trace_event_fields fentry_fields_array[] = {
671334e5519SMasami Hiramatsu (Google) { .type = TRACE_FUNCTION_TYPE,
672334e5519SMasami Hiramatsu (Google) .define_fields = fentry_event_define_fields },
673334e5519SMasami Hiramatsu (Google) {}
674334e5519SMasami Hiramatsu (Google) };
675334e5519SMasami Hiramatsu (Google)
676334e5519SMasami Hiramatsu (Google) static struct trace_event_fields fexit_fields_array[] = {
677334e5519SMasami Hiramatsu (Google) { .type = TRACE_FUNCTION_TYPE,
678334e5519SMasami Hiramatsu (Google) .define_fields = fexit_event_define_fields },
679334e5519SMasami Hiramatsu (Google) {}
680334e5519SMasami Hiramatsu (Google) };
681334e5519SMasami Hiramatsu (Google)
682334e5519SMasami Hiramatsu (Google) static int fprobe_register(struct trace_event_call *event,
683334e5519SMasami Hiramatsu (Google) enum trace_reg type, void *data);
684334e5519SMasami Hiramatsu (Google)
init_trace_event_call(struct trace_fprobe * tf)685334e5519SMasami Hiramatsu (Google) static inline void init_trace_event_call(struct trace_fprobe *tf)
686334e5519SMasami Hiramatsu (Google) {
687334e5519SMasami Hiramatsu (Google) struct trace_event_call *call = trace_probe_event_call(&tf->tp);
688334e5519SMasami Hiramatsu (Google)
689334e5519SMasami Hiramatsu (Google) if (trace_fprobe_is_return(tf)) {
690334e5519SMasami Hiramatsu (Google) call->event.funcs = &fexit_funcs;
691334e5519SMasami Hiramatsu (Google) call->class->fields_array = fexit_fields_array;
692334e5519SMasami Hiramatsu (Google) } else {
693334e5519SMasami Hiramatsu (Google) call->event.funcs = &fentry_funcs;
694334e5519SMasami Hiramatsu (Google) call->class->fields_array = fentry_fields_array;
695334e5519SMasami Hiramatsu (Google) }
696334e5519SMasami Hiramatsu (Google)
697334e5519SMasami Hiramatsu (Google) call->flags = TRACE_EVENT_FL_FPROBE;
698334e5519SMasami Hiramatsu (Google) call->class->reg = fprobe_register;
699334e5519SMasami Hiramatsu (Google) }
700334e5519SMasami Hiramatsu (Google)
register_fprobe_event(struct trace_fprobe * tf)701334e5519SMasami Hiramatsu (Google) static int register_fprobe_event(struct trace_fprobe *tf)
702334e5519SMasami Hiramatsu (Google) {
703334e5519SMasami Hiramatsu (Google) init_trace_event_call(tf);
704334e5519SMasami Hiramatsu (Google)
705334e5519SMasami Hiramatsu (Google) return trace_probe_register_event_call(&tf->tp);
706334e5519SMasami Hiramatsu (Google) }
707334e5519SMasami Hiramatsu (Google)
unregister_fprobe_event(struct trace_fprobe * tf)708334e5519SMasami Hiramatsu (Google) static int unregister_fprobe_event(struct trace_fprobe *tf)
709334e5519SMasami Hiramatsu (Google) {
710334e5519SMasami Hiramatsu (Google) return trace_probe_unregister_event_call(&tf->tp);
711334e5519SMasami Hiramatsu (Google) }
712334e5519SMasami Hiramatsu (Google)
__regsiter_tracepoint_fprobe(struct trace_fprobe * tf)71357a7e6deSMasami Hiramatsu (Google) static int __regsiter_tracepoint_fprobe(struct trace_fprobe *tf)
71457a7e6deSMasami Hiramatsu (Google) {
71557a7e6deSMasami Hiramatsu (Google) struct tracepoint *tpoint = tf->tpoint;
71657a7e6deSMasami Hiramatsu (Google) unsigned long ip = (unsigned long)tpoint->probestub;
71757a7e6deSMasami Hiramatsu (Google) int ret;
71857a7e6deSMasami Hiramatsu (Google)
71957a7e6deSMasami Hiramatsu (Google) /*
72057a7e6deSMasami Hiramatsu (Google) * Here, we do 2 steps to enable fprobe on a tracepoint.
72157a7e6deSMasami Hiramatsu (Google) * At first, put __probestub_##TP function on the tracepoint
72257a7e6deSMasami Hiramatsu (Google) * and put a fprobe on the stub function.
72357a7e6deSMasami Hiramatsu (Google) */
72457a7e6deSMasami Hiramatsu (Google) ret = tracepoint_probe_register_prio_may_exist(tpoint,
72557a7e6deSMasami Hiramatsu (Google) tpoint->probestub, NULL, 0);
72657a7e6deSMasami Hiramatsu (Google) if (ret < 0)
72757a7e6deSMasami Hiramatsu (Google) return ret;
72857a7e6deSMasami Hiramatsu (Google) return register_fprobe_ips(&tf->fp, &ip, 1);
72957a7e6deSMasami Hiramatsu (Google) }
73057a7e6deSMasami Hiramatsu (Google)
731334e5519SMasami Hiramatsu (Google) /* Internal register function - just handle fprobe and flags */
__register_trace_fprobe(struct trace_fprobe * tf)732334e5519SMasami Hiramatsu (Google) static int __register_trace_fprobe(struct trace_fprobe *tf)
733334e5519SMasami Hiramatsu (Google) {
734334e5519SMasami Hiramatsu (Google) int i, ret;
735334e5519SMasami Hiramatsu (Google)
736334e5519SMasami Hiramatsu (Google) /* Should we need new LOCKDOWN flag for fprobe? */
737334e5519SMasami Hiramatsu (Google) ret = security_locked_down(LOCKDOWN_KPROBES);
738334e5519SMasami Hiramatsu (Google) if (ret)
739334e5519SMasami Hiramatsu (Google) return ret;
740334e5519SMasami Hiramatsu (Google)
741334e5519SMasami Hiramatsu (Google) if (trace_fprobe_is_registered(tf))
742334e5519SMasami Hiramatsu (Google) return -EINVAL;
743334e5519SMasami Hiramatsu (Google)
744334e5519SMasami Hiramatsu (Google) for (i = 0; i < tf->tp.nr_args; i++) {
745334e5519SMasami Hiramatsu (Google) ret = traceprobe_update_arg(&tf->tp.args[i]);
746334e5519SMasami Hiramatsu (Google) if (ret)
747334e5519SMasami Hiramatsu (Google) return ret;
748334e5519SMasami Hiramatsu (Google) }
749334e5519SMasami Hiramatsu (Google)
750334e5519SMasami Hiramatsu (Google) /* Set/clear disabled flag according to tp->flag */
751334e5519SMasami Hiramatsu (Google) if (trace_probe_is_enabled(&tf->tp))
752334e5519SMasami Hiramatsu (Google) tf->fp.flags &= ~FPROBE_FL_DISABLED;
753334e5519SMasami Hiramatsu (Google) else
754334e5519SMasami Hiramatsu (Google) tf->fp.flags |= FPROBE_FL_DISABLED;
755334e5519SMasami Hiramatsu (Google)
756e2d0d7b2SMasami Hiramatsu (Google) if (trace_fprobe_is_tracepoint(tf)) {
75757a7e6deSMasami Hiramatsu (Google)
75857a7e6deSMasami Hiramatsu (Google) /* This tracepoint is not loaded yet */
75957a7e6deSMasami Hiramatsu (Google) if (tf->tpoint == TRACEPOINT_STUB)
76057a7e6deSMasami Hiramatsu (Google) return 0;
76157a7e6deSMasami Hiramatsu (Google)
76257a7e6deSMasami Hiramatsu (Google) return __regsiter_tracepoint_fprobe(tf);
763e2d0d7b2SMasami Hiramatsu (Google) }
764e2d0d7b2SMasami Hiramatsu (Google)
765334e5519SMasami Hiramatsu (Google) /* TODO: handle filter, nofilter or symbol list */
766334e5519SMasami Hiramatsu (Google) return register_fprobe(&tf->fp, tf->symbol, NULL);
767334e5519SMasami Hiramatsu (Google) }
768334e5519SMasami Hiramatsu (Google)
769334e5519SMasami Hiramatsu (Google) /* Internal unregister function - just handle fprobe and flags */
__unregister_trace_fprobe(struct trace_fprobe * tf)770334e5519SMasami Hiramatsu (Google) static void __unregister_trace_fprobe(struct trace_fprobe *tf)
771334e5519SMasami Hiramatsu (Google) {
772334e5519SMasami Hiramatsu (Google) if (trace_fprobe_is_registered(tf)) {
773334e5519SMasami Hiramatsu (Google) unregister_fprobe(&tf->fp);
774334e5519SMasami Hiramatsu (Google) memset(&tf->fp, 0, sizeof(tf->fp));
775e2d0d7b2SMasami Hiramatsu (Google) if (trace_fprobe_is_tracepoint(tf)) {
776e2d0d7b2SMasami Hiramatsu (Google) tracepoint_probe_unregister(tf->tpoint,
777e2d0d7b2SMasami Hiramatsu (Google) tf->tpoint->probestub, NULL);
778e2d0d7b2SMasami Hiramatsu (Google) tf->tpoint = NULL;
779e2d0d7b2SMasami Hiramatsu (Google) tf->mod = NULL;
780e2d0d7b2SMasami Hiramatsu (Google) }
781334e5519SMasami Hiramatsu (Google) }
782334e5519SMasami Hiramatsu (Google) }
783334e5519SMasami Hiramatsu (Google)
784334e5519SMasami Hiramatsu (Google) /* TODO: make this trace_*probe common function */
785334e5519SMasami Hiramatsu (Google) /* Unregister a trace_probe and probe_event */
unregister_trace_fprobe(struct trace_fprobe * tf)786334e5519SMasami Hiramatsu (Google) static int unregister_trace_fprobe(struct trace_fprobe *tf)
787334e5519SMasami Hiramatsu (Google) {
788334e5519SMasami Hiramatsu (Google) /* If other probes are on the event, just unregister fprobe */
789334e5519SMasami Hiramatsu (Google) if (trace_probe_has_sibling(&tf->tp))
790334e5519SMasami Hiramatsu (Google) goto unreg;
791334e5519SMasami Hiramatsu (Google)
792334e5519SMasami Hiramatsu (Google) /* Enabled event can not be unregistered */
793334e5519SMasami Hiramatsu (Google) if (trace_probe_is_enabled(&tf->tp))
794334e5519SMasami Hiramatsu (Google) return -EBUSY;
795334e5519SMasami Hiramatsu (Google)
796334e5519SMasami Hiramatsu (Google) /* If there's a reference to the dynamic event */
797334e5519SMasami Hiramatsu (Google) if (trace_event_dyn_busy(trace_probe_event_call(&tf->tp)))
798334e5519SMasami Hiramatsu (Google) return -EBUSY;
799334e5519SMasami Hiramatsu (Google)
800334e5519SMasami Hiramatsu (Google) /* Will fail if probe is being used by ftrace or perf */
801334e5519SMasami Hiramatsu (Google) if (unregister_fprobe_event(tf))
802334e5519SMasami Hiramatsu (Google) return -EBUSY;
803334e5519SMasami Hiramatsu (Google)
804334e5519SMasami Hiramatsu (Google) unreg:
805334e5519SMasami Hiramatsu (Google) __unregister_trace_fprobe(tf);
806334e5519SMasami Hiramatsu (Google) dyn_event_remove(&tf->devent);
807334e5519SMasami Hiramatsu (Google) trace_probe_unlink(&tf->tp);
808334e5519SMasami Hiramatsu (Google)
809334e5519SMasami Hiramatsu (Google) return 0;
810334e5519SMasami Hiramatsu (Google) }
811334e5519SMasami Hiramatsu (Google)
trace_fprobe_has_same_fprobe(struct trace_fprobe * orig,struct trace_fprobe * comp)812334e5519SMasami Hiramatsu (Google) static bool trace_fprobe_has_same_fprobe(struct trace_fprobe *orig,
813334e5519SMasami Hiramatsu (Google) struct trace_fprobe *comp)
814334e5519SMasami Hiramatsu (Google) {
815334e5519SMasami Hiramatsu (Google) struct trace_probe_event *tpe = orig->tp.event;
816334e5519SMasami Hiramatsu (Google) int i;
817334e5519SMasami Hiramatsu (Google)
818334e5519SMasami Hiramatsu (Google) list_for_each_entry(orig, &tpe->probes, tp.list) {
819334e5519SMasami Hiramatsu (Google) if (strcmp(trace_fprobe_symbol(orig),
820334e5519SMasami Hiramatsu (Google) trace_fprobe_symbol(comp)))
821334e5519SMasami Hiramatsu (Google) continue;
822334e5519SMasami Hiramatsu (Google)
823334e5519SMasami Hiramatsu (Google) /*
824334e5519SMasami Hiramatsu (Google) * trace_probe_compare_arg_type() ensured that nr_args and
825334e5519SMasami Hiramatsu (Google) * each argument name and type are same. Let's compare comm.
826334e5519SMasami Hiramatsu (Google) */
827334e5519SMasami Hiramatsu (Google) for (i = 0; i < orig->tp.nr_args; i++) {
828334e5519SMasami Hiramatsu (Google) if (strcmp(orig->tp.args[i].comm,
829334e5519SMasami Hiramatsu (Google) comp->tp.args[i].comm))
830334e5519SMasami Hiramatsu (Google) break;
831334e5519SMasami Hiramatsu (Google) }
832334e5519SMasami Hiramatsu (Google)
833334e5519SMasami Hiramatsu (Google) if (i == orig->tp.nr_args)
834334e5519SMasami Hiramatsu (Google) return true;
835334e5519SMasami Hiramatsu (Google) }
836334e5519SMasami Hiramatsu (Google)
837334e5519SMasami Hiramatsu (Google) return false;
838334e5519SMasami Hiramatsu (Google) }
839334e5519SMasami Hiramatsu (Google)
append_trace_fprobe(struct trace_fprobe * tf,struct trace_fprobe * to)840334e5519SMasami Hiramatsu (Google) static int append_trace_fprobe(struct trace_fprobe *tf, struct trace_fprobe *to)
841334e5519SMasami Hiramatsu (Google) {
842334e5519SMasami Hiramatsu (Google) int ret;
843334e5519SMasami Hiramatsu (Google)
844e2d0d7b2SMasami Hiramatsu (Google) if (trace_fprobe_is_return(tf) != trace_fprobe_is_return(to) ||
845e2d0d7b2SMasami Hiramatsu (Google) trace_fprobe_is_tracepoint(tf) != trace_fprobe_is_tracepoint(to)) {
846334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(0);
847334e5519SMasami Hiramatsu (Google) trace_probe_log_err(0, DIFF_PROBE_TYPE);
848334e5519SMasami Hiramatsu (Google) return -EEXIST;
849334e5519SMasami Hiramatsu (Google) }
850334e5519SMasami Hiramatsu (Google) ret = trace_probe_compare_arg_type(&tf->tp, &to->tp);
851334e5519SMasami Hiramatsu (Google) if (ret) {
852334e5519SMasami Hiramatsu (Google) /* Note that argument starts index = 2 */
853334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(ret + 1);
854334e5519SMasami Hiramatsu (Google) trace_probe_log_err(0, DIFF_ARG_TYPE);
855334e5519SMasami Hiramatsu (Google) return -EEXIST;
856334e5519SMasami Hiramatsu (Google) }
857334e5519SMasami Hiramatsu (Google) if (trace_fprobe_has_same_fprobe(to, tf)) {
858334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(0);
859334e5519SMasami Hiramatsu (Google) trace_probe_log_err(0, SAME_PROBE);
860334e5519SMasami Hiramatsu (Google) return -EEXIST;
861334e5519SMasami Hiramatsu (Google) }
862334e5519SMasami Hiramatsu (Google)
863334e5519SMasami Hiramatsu (Google) /* Append to existing event */
864334e5519SMasami Hiramatsu (Google) ret = trace_probe_append(&tf->tp, &to->tp);
865334e5519SMasami Hiramatsu (Google) if (ret)
866334e5519SMasami Hiramatsu (Google) return ret;
867334e5519SMasami Hiramatsu (Google)
868334e5519SMasami Hiramatsu (Google) ret = __register_trace_fprobe(tf);
869334e5519SMasami Hiramatsu (Google) if (ret)
870334e5519SMasami Hiramatsu (Google) trace_probe_unlink(&tf->tp);
871334e5519SMasami Hiramatsu (Google) else
872334e5519SMasami Hiramatsu (Google) dyn_event_add(&tf->devent, trace_probe_event_call(&tf->tp));
873334e5519SMasami Hiramatsu (Google)
874334e5519SMasami Hiramatsu (Google) return ret;
875334e5519SMasami Hiramatsu (Google) }
876334e5519SMasami Hiramatsu (Google)
877334e5519SMasami Hiramatsu (Google) /* Register a trace_probe and probe_event */
register_trace_fprobe(struct trace_fprobe * tf)878334e5519SMasami Hiramatsu (Google) static int register_trace_fprobe(struct trace_fprobe *tf)
879334e5519SMasami Hiramatsu (Google) {
880334e5519SMasami Hiramatsu (Google) struct trace_fprobe *old_tf;
881334e5519SMasami Hiramatsu (Google) int ret;
882334e5519SMasami Hiramatsu (Google)
88382756372SMasami Hiramatsu (Google) guard(mutex)(&event_mutex);
884334e5519SMasami Hiramatsu (Google)
885334e5519SMasami Hiramatsu (Google) old_tf = find_trace_fprobe(trace_probe_name(&tf->tp),
886334e5519SMasami Hiramatsu (Google) trace_probe_group_name(&tf->tp));
88782756372SMasami Hiramatsu (Google) if (old_tf)
88882756372SMasami Hiramatsu (Google) return append_trace_fprobe(tf, old_tf);
889334e5519SMasami Hiramatsu (Google)
890334e5519SMasami Hiramatsu (Google) /* Register new event */
891334e5519SMasami Hiramatsu (Google) ret = register_fprobe_event(tf);
892334e5519SMasami Hiramatsu (Google) if (ret) {
893334e5519SMasami Hiramatsu (Google) if (ret == -EEXIST) {
894334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(0);
895334e5519SMasami Hiramatsu (Google) trace_probe_log_err(0, EVENT_EXIST);
896334e5519SMasami Hiramatsu (Google) } else
897334e5519SMasami Hiramatsu (Google) pr_warn("Failed to register probe event(%d)\n", ret);
89882756372SMasami Hiramatsu (Google) return ret;
899334e5519SMasami Hiramatsu (Google) }
900334e5519SMasami Hiramatsu (Google)
901334e5519SMasami Hiramatsu (Google) /* Register fprobe */
902334e5519SMasami Hiramatsu (Google) ret = __register_trace_fprobe(tf);
903334e5519SMasami Hiramatsu (Google) if (ret < 0)
904334e5519SMasami Hiramatsu (Google) unregister_fprobe_event(tf);
905334e5519SMasami Hiramatsu (Google) else
906334e5519SMasami Hiramatsu (Google) dyn_event_add(&tf->devent, trace_probe_event_call(&tf->tp));
907334e5519SMasami Hiramatsu (Google)
908334e5519SMasami Hiramatsu (Google) return ret;
909334e5519SMasami Hiramatsu (Google) }
910334e5519SMasami Hiramatsu (Google)
911e2d0d7b2SMasami Hiramatsu (Google) struct __find_tracepoint_cb_data {
912e2d0d7b2SMasami Hiramatsu (Google) const char *tp_name;
913e2d0d7b2SMasami Hiramatsu (Google) struct tracepoint *tpoint;
91467e9a9eeSMasami Hiramatsu (Google) struct module *mod;
915e2d0d7b2SMasami Hiramatsu (Google) };
916e2d0d7b2SMasami Hiramatsu (Google)
__find_tracepoint_module_cb(struct tracepoint * tp,struct module * mod,void * priv)91767e9a9eeSMasami Hiramatsu (Google) static void __find_tracepoint_module_cb(struct tracepoint *tp, struct module *mod, void *priv)
91867e9a9eeSMasami Hiramatsu (Google) {
91967e9a9eeSMasami Hiramatsu (Google) struct __find_tracepoint_cb_data *data = priv;
92067e9a9eeSMasami Hiramatsu (Google)
92167e9a9eeSMasami Hiramatsu (Google) if (!data->tpoint && !strcmp(data->tp_name, tp->name)) {
922*dd941507SMasami Hiramatsu (Google) /* If module is not specified, try getting module refcount. */
923*dd941507SMasami Hiramatsu (Google) if (!data->mod && mod) {
924*dd941507SMasami Hiramatsu (Google) /* If failed to get refcount, ignore this tracepoint. */
925*dd941507SMasami Hiramatsu (Google) if (!try_module_get(mod))
926*dd941507SMasami Hiramatsu (Google) return;
927*dd941507SMasami Hiramatsu (Google)
92867e9a9eeSMasami Hiramatsu (Google) data->mod = mod;
92967e9a9eeSMasami Hiramatsu (Google) }
930*dd941507SMasami Hiramatsu (Google) data->tpoint = tp;
931*dd941507SMasami Hiramatsu (Google) }
93257a7e6deSMasami Hiramatsu (Google) }
93367e9a9eeSMasami Hiramatsu (Google)
__find_tracepoint_cb(struct tracepoint * tp,void * priv)934e2d0d7b2SMasami Hiramatsu (Google) static void __find_tracepoint_cb(struct tracepoint *tp, void *priv)
935e2d0d7b2SMasami Hiramatsu (Google) {
936e2d0d7b2SMasami Hiramatsu (Google) struct __find_tracepoint_cb_data *data = priv;
937e2d0d7b2SMasami Hiramatsu (Google)
938e2d0d7b2SMasami Hiramatsu (Google) if (!data->tpoint && !strcmp(data->tp_name, tp->name))
939e2d0d7b2SMasami Hiramatsu (Google) data->tpoint = tp;
940e2d0d7b2SMasami Hiramatsu (Google) }
941e2d0d7b2SMasami Hiramatsu (Google)
942*dd941507SMasami Hiramatsu (Google) /*
943*dd941507SMasami Hiramatsu (Google) * Find a tracepoint from kernel and module. If the tracepoint is on the module,
944*dd941507SMasami Hiramatsu (Google) * the module's refcount is incremented and returned as *@tp_mod. Thus, if it is
945*dd941507SMasami Hiramatsu (Google) * not NULL, caller must call module_put(*tp_mod) after used the tracepoint.
946*dd941507SMasami Hiramatsu (Google) */
find_tracepoint(const char * tp_name,struct module ** tp_mod)94767e9a9eeSMasami Hiramatsu (Google) static struct tracepoint *find_tracepoint(const char *tp_name,
94867e9a9eeSMasami Hiramatsu (Google) struct module **tp_mod)
949e2d0d7b2SMasami Hiramatsu (Google) {
950e2d0d7b2SMasami Hiramatsu (Google) struct __find_tracepoint_cb_data data = {
951e2d0d7b2SMasami Hiramatsu (Google) .tp_name = tp_name,
95267e9a9eeSMasami Hiramatsu (Google) .mod = NULL,
953e2d0d7b2SMasami Hiramatsu (Google) };
954e2d0d7b2SMasami Hiramatsu (Google)
955e2d0d7b2SMasami Hiramatsu (Google) for_each_kernel_tracepoint(__find_tracepoint_cb, &data);
956e2d0d7b2SMasami Hiramatsu (Google)
95767e9a9eeSMasami Hiramatsu (Google) if (!data.tpoint && IS_ENABLED(CONFIG_MODULES)) {
95867e9a9eeSMasami Hiramatsu (Google) for_each_module_tracepoint(__find_tracepoint_module_cb, &data);
95967e9a9eeSMasami Hiramatsu (Google) *tp_mod = data.mod;
96067e9a9eeSMasami Hiramatsu (Google) }
96167e9a9eeSMasami Hiramatsu (Google)
962e2d0d7b2SMasami Hiramatsu (Google) return data.tpoint;
963e2d0d7b2SMasami Hiramatsu (Google) }
964e2d0d7b2SMasami Hiramatsu (Google)
96557a7e6deSMasami Hiramatsu (Google) #ifdef CONFIG_MODULES
reenable_trace_fprobe(struct trace_fprobe * tf)96657a7e6deSMasami Hiramatsu (Google) static void reenable_trace_fprobe(struct trace_fprobe *tf)
96757a7e6deSMasami Hiramatsu (Google) {
96857a7e6deSMasami Hiramatsu (Google) struct trace_probe *tp = &tf->tp;
96957a7e6deSMasami Hiramatsu (Google)
97057a7e6deSMasami Hiramatsu (Google) list_for_each_entry(tf, trace_probe_probe_list(tp), tp.list) {
97157a7e6deSMasami Hiramatsu (Google) __enable_trace_fprobe(tf);
97257a7e6deSMasami Hiramatsu (Google) }
97357a7e6deSMasami Hiramatsu (Google) }
97457a7e6deSMasami Hiramatsu (Google)
975*dd941507SMasami Hiramatsu (Google) /*
976*dd941507SMasami Hiramatsu (Google) * Find a tracepoint from specified module. In this case, this does not get the
977*dd941507SMasami Hiramatsu (Google) * module's refcount. The caller must ensure the module is not freed.
978*dd941507SMasami Hiramatsu (Google) */
find_tracepoint_in_module(struct module * mod,const char * tp_name)97957a7e6deSMasami Hiramatsu (Google) static struct tracepoint *find_tracepoint_in_module(struct module *mod,
98057a7e6deSMasami Hiramatsu (Google) const char *tp_name)
98157a7e6deSMasami Hiramatsu (Google) {
98257a7e6deSMasami Hiramatsu (Google) struct __find_tracepoint_cb_data data = {
98357a7e6deSMasami Hiramatsu (Google) .tp_name = tp_name,
98457a7e6deSMasami Hiramatsu (Google) .mod = mod,
98557a7e6deSMasami Hiramatsu (Google) };
98657a7e6deSMasami Hiramatsu (Google)
98757a7e6deSMasami Hiramatsu (Google) for_each_tracepoint_in_module(mod, __find_tracepoint_module_cb, &data);
98857a7e6deSMasami Hiramatsu (Google) return data.tpoint;
98957a7e6deSMasami Hiramatsu (Google) }
99057a7e6deSMasami Hiramatsu (Google)
__tracepoint_probe_module_cb(struct notifier_block * self,unsigned long val,void * data)99157a7e6deSMasami Hiramatsu (Google) static int __tracepoint_probe_module_cb(struct notifier_block *self,
99257a7e6deSMasami Hiramatsu (Google) unsigned long val, void *data)
99357a7e6deSMasami Hiramatsu (Google) {
99457a7e6deSMasami Hiramatsu (Google) struct tp_module *tp_mod = data;
99557a7e6deSMasami Hiramatsu (Google) struct tracepoint *tpoint;
99657a7e6deSMasami Hiramatsu (Google) struct trace_fprobe *tf;
99757a7e6deSMasami Hiramatsu (Google) struct dyn_event *pos;
99857a7e6deSMasami Hiramatsu (Google)
99957a7e6deSMasami Hiramatsu (Google) if (val != MODULE_STATE_GOING && val != MODULE_STATE_COMING)
100057a7e6deSMasami Hiramatsu (Google) return NOTIFY_DONE;
100157a7e6deSMasami Hiramatsu (Google)
100257a7e6deSMasami Hiramatsu (Google) mutex_lock(&event_mutex);
100357a7e6deSMasami Hiramatsu (Google) for_each_trace_fprobe(tf, pos) {
100457a7e6deSMasami Hiramatsu (Google) if (val == MODULE_STATE_COMING && tf->tpoint == TRACEPOINT_STUB) {
100557a7e6deSMasami Hiramatsu (Google) tpoint = find_tracepoint_in_module(tp_mod->mod, tf->symbol);
100657a7e6deSMasami Hiramatsu (Google) if (tpoint) {
100757a7e6deSMasami Hiramatsu (Google) tf->tpoint = tpoint;
100857a7e6deSMasami Hiramatsu (Google) tf->mod = tp_mod->mod;
100957a7e6deSMasami Hiramatsu (Google) if (!WARN_ON_ONCE(__regsiter_tracepoint_fprobe(tf)) &&
101057a7e6deSMasami Hiramatsu (Google) trace_probe_is_enabled(&tf->tp))
101157a7e6deSMasami Hiramatsu (Google) reenable_trace_fprobe(tf);
101257a7e6deSMasami Hiramatsu (Google) }
101357a7e6deSMasami Hiramatsu (Google) } else if (val == MODULE_STATE_GOING && tp_mod->mod == tf->mod) {
10140a8bb688SMasami Hiramatsu (Google) unregister_fprobe(&tf->fp);
10150a8bb688SMasami Hiramatsu (Google) if (trace_fprobe_is_tracepoint(tf)) {
101657a7e6deSMasami Hiramatsu (Google) tracepoint_probe_unregister(tf->tpoint,
101757a7e6deSMasami Hiramatsu (Google) tf->tpoint->probestub, NULL);
10180a8bb688SMasami Hiramatsu (Google) tf->tpoint = TRACEPOINT_STUB;
101957a7e6deSMasami Hiramatsu (Google) tf->mod = NULL;
102057a7e6deSMasami Hiramatsu (Google) }
102157a7e6deSMasami Hiramatsu (Google) }
10220a8bb688SMasami Hiramatsu (Google) }
102357a7e6deSMasami Hiramatsu (Google) mutex_unlock(&event_mutex);
102457a7e6deSMasami Hiramatsu (Google)
102557a7e6deSMasami Hiramatsu (Google) return NOTIFY_DONE;
102657a7e6deSMasami Hiramatsu (Google) }
102757a7e6deSMasami Hiramatsu (Google)
102857a7e6deSMasami Hiramatsu (Google) static struct notifier_block tracepoint_module_nb = {
102957a7e6deSMasami Hiramatsu (Google) .notifier_call = __tracepoint_probe_module_cb,
103057a7e6deSMasami Hiramatsu (Google) };
103157a7e6deSMasami Hiramatsu (Google) #endif /* CONFIG_MODULES */
103257a7e6deSMasami Hiramatsu (Google)
parse_symbol_and_return(int argc,const char * argv[],char ** symbol,bool * is_return,bool is_tracepoint)103308c9306fSMasami Hiramatsu (Google) static int parse_symbol_and_return(int argc, const char *argv[],
103408c9306fSMasami Hiramatsu (Google) char **symbol, bool *is_return,
103508c9306fSMasami Hiramatsu (Google) bool is_tracepoint)
103608c9306fSMasami Hiramatsu (Google) {
103708c9306fSMasami Hiramatsu (Google) char *tmp = strchr(argv[1], '%');
103808c9306fSMasami Hiramatsu (Google) int i;
103908c9306fSMasami Hiramatsu (Google)
104008c9306fSMasami Hiramatsu (Google) if (tmp) {
104108c9306fSMasami Hiramatsu (Google) int len = tmp - argv[1];
104208c9306fSMasami Hiramatsu (Google)
104308c9306fSMasami Hiramatsu (Google) if (!is_tracepoint && !strcmp(tmp, "%return")) {
104408c9306fSMasami Hiramatsu (Google) *is_return = true;
104508c9306fSMasami Hiramatsu (Google) } else {
104608c9306fSMasami Hiramatsu (Google) trace_probe_log_err(len, BAD_ADDR_SUFFIX);
104708c9306fSMasami Hiramatsu (Google) return -EINVAL;
104808c9306fSMasami Hiramatsu (Google) }
104908c9306fSMasami Hiramatsu (Google) *symbol = kmemdup_nul(argv[1], len, GFP_KERNEL);
105008c9306fSMasami Hiramatsu (Google) } else
105108c9306fSMasami Hiramatsu (Google) *symbol = kstrdup(argv[1], GFP_KERNEL);
105208c9306fSMasami Hiramatsu (Google) if (!*symbol)
105308c9306fSMasami Hiramatsu (Google) return -ENOMEM;
105408c9306fSMasami Hiramatsu (Google)
105508c9306fSMasami Hiramatsu (Google) if (*is_return)
105608c9306fSMasami Hiramatsu (Google) return 0;
105708c9306fSMasami Hiramatsu (Google)
1058d0453655SMasami Hiramatsu (Google) if (is_tracepoint) {
1059d0453655SMasami Hiramatsu (Google) tmp = *symbol;
1060d0453655SMasami Hiramatsu (Google) while (*tmp && (isalnum(*tmp) || *tmp == '_'))
1061d0453655SMasami Hiramatsu (Google) tmp++;
1062d0453655SMasami Hiramatsu (Google) if (*tmp) {
1063d0453655SMasami Hiramatsu (Google) /* find a wrong character. */
1064d0453655SMasami Hiramatsu (Google) trace_probe_log_err(tmp - *symbol, BAD_TP_NAME);
1065d0453655SMasami Hiramatsu (Google) kfree(*symbol);
1066d0453655SMasami Hiramatsu (Google) *symbol = NULL;
1067d0453655SMasami Hiramatsu (Google) return -EINVAL;
1068d0453655SMasami Hiramatsu (Google) }
1069d0453655SMasami Hiramatsu (Google) }
1070d0453655SMasami Hiramatsu (Google)
107108c9306fSMasami Hiramatsu (Google) /* If there is $retval, this should be a return fprobe. */
107208c9306fSMasami Hiramatsu (Google) for (i = 2; i < argc; i++) {
107308c9306fSMasami Hiramatsu (Google) tmp = strstr(argv[i], "$retval");
107408c9306fSMasami Hiramatsu (Google) if (tmp && !isalnum(tmp[7]) && tmp[7] != '_') {
1075ce51e615SMasami Hiramatsu (Google) if (is_tracepoint) {
1076ce51e615SMasami Hiramatsu (Google) trace_probe_log_set_index(i);
1077ce51e615SMasami Hiramatsu (Google) trace_probe_log_err(tmp - argv[i], RETVAL_ON_PROBE);
1078ac965d7dSMasami Hiramatsu (Google) kfree(*symbol);
1079ac965d7dSMasami Hiramatsu (Google) *symbol = NULL;
1080ce51e615SMasami Hiramatsu (Google) return -EINVAL;
1081ce51e615SMasami Hiramatsu (Google) }
108208c9306fSMasami Hiramatsu (Google) *is_return = true;
108308c9306fSMasami Hiramatsu (Google) break;
108408c9306fSMasami Hiramatsu (Google) }
108508c9306fSMasami Hiramatsu (Google) }
108608c9306fSMasami Hiramatsu (Google) return 0;
108708c9306fSMasami Hiramatsu (Google) }
108808c9306fSMasami Hiramatsu (Google)
DEFINE_FREE(module_put,struct module *,if (_T)module_put (_T))108982756372SMasami Hiramatsu (Google) DEFINE_FREE(module_put, struct module *, if (_T) module_put(_T))
109082756372SMasami Hiramatsu (Google)
109182756372SMasami Hiramatsu (Google) static int trace_fprobe_create_internal(int argc, const char *argv[],
109282756372SMasami Hiramatsu (Google) struct traceprobe_parse_context *ctx)
1093334e5519SMasami Hiramatsu (Google) {
1094334e5519SMasami Hiramatsu (Google) /*
1095334e5519SMasami Hiramatsu (Google) * Argument syntax:
1096334e5519SMasami Hiramatsu (Google) * - Add fentry probe:
1097334e5519SMasami Hiramatsu (Google) * f[:[GRP/][EVENT]] [MOD:]KSYM [FETCHARGS]
1098334e5519SMasami Hiramatsu (Google) * - Add fexit probe:
1099334e5519SMasami Hiramatsu (Google) * f[N][:[GRP/][EVENT]] [MOD:]KSYM%return [FETCHARGS]
1100e2d0d7b2SMasami Hiramatsu (Google) * - Add tracepoint probe:
1101e2d0d7b2SMasami Hiramatsu (Google) * t[:[GRP/][EVENT]] TRACEPOINT [FETCHARGS]
1102334e5519SMasami Hiramatsu (Google) *
1103334e5519SMasami Hiramatsu (Google) * Fetch args:
1104334e5519SMasami Hiramatsu (Google) * $retval : fetch return value
1105334e5519SMasami Hiramatsu (Google) * $stack : fetch stack address
1106334e5519SMasami Hiramatsu (Google) * $stackN : fetch Nth entry of stack (N:0-)
1107334e5519SMasami Hiramatsu (Google) * $argN : fetch Nth argument (N:1-)
1108334e5519SMasami Hiramatsu (Google) * $comm : fetch current task comm
1109334e5519SMasami Hiramatsu (Google) * @ADDR : fetch memory at ADDR (ADDR should be in kernel)
1110334e5519SMasami Hiramatsu (Google) * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
1111334e5519SMasami Hiramatsu (Google) * Dereferencing memory fetch:
1112334e5519SMasami Hiramatsu (Google) * +|-offs(ARG) : fetch memory at ARG +|- offs address.
1113334e5519SMasami Hiramatsu (Google) * Alias name of args:
1114334e5519SMasami Hiramatsu (Google) * NAME=FETCHARG : set NAME as alias of FETCHARG.
1115334e5519SMasami Hiramatsu (Google) * Type of args:
1116334e5519SMasami Hiramatsu (Google) * FETCHARG:TYPE : use TYPE instead of unsigned long.
1117334e5519SMasami Hiramatsu (Google) */
111882756372SMasami Hiramatsu (Google) struct trace_fprobe *tf __free(free_trace_fprobe) = NULL;
1119a2224559SMasami Hiramatsu (Google) int i, new_argc = 0, ret = 0;
1120334e5519SMasami Hiramatsu (Google) bool is_return = false;
112182756372SMasami Hiramatsu (Google) char *symbol __free(kfree) = NULL;
1122334e5519SMasami Hiramatsu (Google) const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
112382756372SMasami Hiramatsu (Google) const char **new_argv __free(kfree) = NULL;
1124334e5519SMasami Hiramatsu (Google) char buf[MAX_EVENT_NAME_LEN];
1125334e5519SMasami Hiramatsu (Google) char gbuf[MAX_EVENT_NAME_LEN];
1126b576e097SMasami Hiramatsu (Google) char sbuf[KSYM_NAME_LEN];
112718b1e870SMasami Hiramatsu (Google) char abuf[MAX_BTF_ARGS_LEN];
112882756372SMasami Hiramatsu (Google) char *dbuf __free(kfree) = NULL;
1129e2d0d7b2SMasami Hiramatsu (Google) bool is_tracepoint = false;
113082756372SMasami Hiramatsu (Google) struct module *tp_mod __free(module_put) = NULL;
1131b576e097SMasami Hiramatsu (Google) struct tracepoint *tpoint = NULL;
1132334e5519SMasami Hiramatsu (Google)
1133e2d0d7b2SMasami Hiramatsu (Google) if ((argv[0][0] != 'f' && argv[0][0] != 't') || argc < 2)
1134334e5519SMasami Hiramatsu (Google) return -ECANCELED;
1135334e5519SMasami Hiramatsu (Google)
1136e2d0d7b2SMasami Hiramatsu (Google) if (argv[0][0] == 't') {
1137e2d0d7b2SMasami Hiramatsu (Google) is_tracepoint = true;
1138e2d0d7b2SMasami Hiramatsu (Google) group = TRACEPOINT_EVENT_SYSTEM;
1139e2d0d7b2SMasami Hiramatsu (Google) }
1140e2d0d7b2SMasami Hiramatsu (Google)
1141a2224559SMasami Hiramatsu (Google) if (argv[0][1] != '\0') {
1142a2224559SMasami Hiramatsu (Google) if (argv[0][1] != ':') {
1143a2224559SMasami Hiramatsu (Google) trace_probe_log_set_index(0);
1144334e5519SMasami Hiramatsu (Google) trace_probe_log_err(1, BAD_MAXACT);
114582756372SMasami Hiramatsu (Google) return -EINVAL;
1146334e5519SMasami Hiramatsu (Google) }
1147a2224559SMasami Hiramatsu (Google) event = &argv[0][2];
1148334e5519SMasami Hiramatsu (Google) }
1149334e5519SMasami Hiramatsu (Google)
1150334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(1);
1151334e5519SMasami Hiramatsu (Google)
1152e2d0d7b2SMasami Hiramatsu (Google) /* a symbol(or tracepoint) must be specified */
115308c9306fSMasami Hiramatsu (Google) ret = parse_symbol_and_return(argc, argv, &symbol, &is_return, is_tracepoint);
115408c9306fSMasami Hiramatsu (Google) if (ret < 0)
115582756372SMasami Hiramatsu (Google) return -EINVAL;
115608c9306fSMasami Hiramatsu (Google)
1157334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(0);
1158334e5519SMasami Hiramatsu (Google) if (event) {
1159334e5519SMasami Hiramatsu (Google) ret = traceprobe_parse_event_name(&event, &group, gbuf,
1160334e5519SMasami Hiramatsu (Google) event - argv[0]);
1161334e5519SMasami Hiramatsu (Google) if (ret)
116282756372SMasami Hiramatsu (Google) return -EINVAL;
1163334e5519SMasami Hiramatsu (Google) }
1164334e5519SMasami Hiramatsu (Google)
1165334e5519SMasami Hiramatsu (Google) if (!event) {
1166334e5519SMasami Hiramatsu (Google) /* Make a new event name */
1167e2d0d7b2SMasami Hiramatsu (Google) if (is_tracepoint)
1168b576e097SMasami Hiramatsu (Google) snprintf(buf, MAX_EVENT_NAME_LEN, "%s%s",
1169b576e097SMasami Hiramatsu (Google) isdigit(*symbol) ? "_" : "", symbol);
1170e2d0d7b2SMasami Hiramatsu (Google) else
1171334e5519SMasami Hiramatsu (Google) snprintf(buf, MAX_EVENT_NAME_LEN, "%s__%s", symbol,
1172334e5519SMasami Hiramatsu (Google) is_return ? "exit" : "entry");
1173334e5519SMasami Hiramatsu (Google) sanitize_event_name(buf);
1174334e5519SMasami Hiramatsu (Google) event = buf;
1175334e5519SMasami Hiramatsu (Google) }
1176334e5519SMasami Hiramatsu (Google)
1177b576e097SMasami Hiramatsu (Google) if (is_return)
117882756372SMasami Hiramatsu (Google) ctx->flags |= TPARG_FL_RETURN;
1179b576e097SMasami Hiramatsu (Google) else
118082756372SMasami Hiramatsu (Google) ctx->flags |= TPARG_FL_FENTRY;
1181b576e097SMasami Hiramatsu (Google)
1182b576e097SMasami Hiramatsu (Google) if (is_tracepoint) {
118382756372SMasami Hiramatsu (Google) ctx->flags |= TPARG_FL_TPOINT;
118467e9a9eeSMasami Hiramatsu (Google) tpoint = find_tracepoint(symbol, &tp_mod);
118557a7e6deSMasami Hiramatsu (Google) if (tpoint) {
118682756372SMasami Hiramatsu (Google) ctx->funcname = kallsyms_lookup(
118757a7e6deSMasami Hiramatsu (Google) (unsigned long)tpoint->probestub,
118857a7e6deSMasami Hiramatsu (Google) NULL, NULL, NULL, sbuf);
118957a7e6deSMasami Hiramatsu (Google) } else if (IS_ENABLED(CONFIG_MODULES)) {
119057a7e6deSMasami Hiramatsu (Google) /* This *may* be loaded afterwards */
119157a7e6deSMasami Hiramatsu (Google) tpoint = TRACEPOINT_STUB;
119282756372SMasami Hiramatsu (Google) ctx->funcname = symbol;
119357a7e6deSMasami Hiramatsu (Google) } else {
1194b576e097SMasami Hiramatsu (Google) trace_probe_log_set_index(1);
1195b576e097SMasami Hiramatsu (Google) trace_probe_log_err(0, NO_TRACEPOINT);
119682756372SMasami Hiramatsu (Google) return -EINVAL;
1197b576e097SMasami Hiramatsu (Google) }
1198b576e097SMasami Hiramatsu (Google) } else
119982756372SMasami Hiramatsu (Google) ctx->funcname = symbol;
1200b576e097SMasami Hiramatsu (Google)
120118b1e870SMasami Hiramatsu (Google) argc -= 2; argv += 2;
120218b1e870SMasami Hiramatsu (Google) new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
120382756372SMasami Hiramatsu (Google) abuf, MAX_BTF_ARGS_LEN, ctx);
120482756372SMasami Hiramatsu (Google) if (IS_ERR(new_argv))
120582756372SMasami Hiramatsu (Google) return PTR_ERR(new_argv);
120618b1e870SMasami Hiramatsu (Google) if (new_argv) {
120718b1e870SMasami Hiramatsu (Google) argc = new_argc;
120818b1e870SMasami Hiramatsu (Google) argv = new_argv;
120918b1e870SMasami Hiramatsu (Google) }
121082756372SMasami Hiramatsu (Google) if (argc > MAX_TRACE_ARGS) {
121182756372SMasami Hiramatsu (Google) trace_probe_log_set_index(2);
121218b1e870SMasami Hiramatsu (Google) trace_probe_log_err(0, TOO_MANY_ARGS);
1213d9b15224SYe Bin return -E2BIG;
1214d9b15224SYe Bin }
121582756372SMasami Hiramatsu (Google)
1216d9b15224SYe Bin ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
1217334e5519SMasami Hiramatsu (Google) if (ret)
121867e9a9eeSMasami Hiramatsu (Google) return ret;
1219a2224559SMasami Hiramatsu (Google)
1220334e5519SMasami Hiramatsu (Google) /* setup a probe */
1221334e5519SMasami Hiramatsu (Google) tf = alloc_trace_fprobe(group, event, symbol, tpoint, tp_mod,
1222334e5519SMasami Hiramatsu (Google) argc, is_return);
1223334e5519SMasami Hiramatsu (Google) if (IS_ERR(tf)) {
122482756372SMasami Hiramatsu (Google) ret = PTR_ERR(tf);
1225334e5519SMasami Hiramatsu (Google) /* This must return -ENOMEM, else there is a bug */
1226e2d0d7b2SMasami Hiramatsu (Google) WARN_ON_ONCE(ret != -ENOMEM);
1227334e5519SMasami Hiramatsu (Google) return ret;
122873f35080SMikel Rychliski }
1229334e5519SMasami Hiramatsu (Google)
123082756372SMasami Hiramatsu (Google) /* parse arguments */
123182756372SMasami Hiramatsu (Google) for (i = 0; i < argc; i++) {
1232334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(i + 2);
123382756372SMasami Hiramatsu (Google) ctx->offset = 0;
1234334e5519SMasami Hiramatsu (Google) ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], ctx);
1235334e5519SMasami Hiramatsu (Google) if (ret)
123625f00e40SMasami Hiramatsu (Google) return ret; /* This can be -ENOMEM */
123725f00e40SMasami Hiramatsu (Google) }
123825f00e40SMasami Hiramatsu (Google)
1239db5e2286SMasami Hiramatsu (Google) if (is_return && tf->tp.entry_arg) {
1240db5e2286SMasami Hiramatsu (Google) tf->fp.entry_handler = trace_fprobe_entry_handler;
1241db5e2286SMasami Hiramatsu (Google) tf->fp.entry_data_size = traceprobe_get_entry_data_size(&tf->tp);
1242db5e2286SMasami Hiramatsu (Google) if (ALIGN(tf->fp.entry_data_size, sizeof(long)) > MAX_FPROBE_DATA_SIZE) {
1243db5e2286SMasami Hiramatsu (Google) trace_probe_log_set_index(2);
124425f00e40SMasami Hiramatsu (Google) trace_probe_log_err(0, TOO_MANY_EARGS);
124525f00e40SMasami Hiramatsu (Google) return -E2BIG;
1246334e5519SMasami Hiramatsu (Google) }
1247334e5519SMasami Hiramatsu (Google) }
1248334e5519SMasami Hiramatsu (Google)
124982756372SMasami Hiramatsu (Google) ret = traceprobe_set_print_fmt(&tf->tp,
1250334e5519SMasami Hiramatsu (Google) is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL);
1251334e5519SMasami Hiramatsu (Google) if (ret < 0)
1252334e5519SMasami Hiramatsu (Google) return ret;
1253334e5519SMasami Hiramatsu (Google)
1254334e5519SMasami Hiramatsu (Google) ret = register_trace_fprobe(tf);
1255334e5519SMasami Hiramatsu (Google) if (ret) {
1256334e5519SMasami Hiramatsu (Google) trace_probe_log_set_index(1);
1257334e5519SMasami Hiramatsu (Google) if (ret == -EILSEQ)
1258334e5519SMasami Hiramatsu (Google) trace_probe_log_err(0, BAD_INSN_BNDRY);
1259334e5519SMasami Hiramatsu (Google) else if (ret == -ENOENT)
126082756372SMasami Hiramatsu (Google) trace_probe_log_err(0, BAD_PROBE_ADDR);
1261334e5519SMasami Hiramatsu (Google) else if (ret != -ENOMEM && ret != -EEXIST)
1262334e5519SMasami Hiramatsu (Google) trace_probe_log_err(0, FAIL_REG_PROBE);
126382756372SMasami Hiramatsu (Google) return -EINVAL;
126482756372SMasami Hiramatsu (Google) }
126582756372SMasami Hiramatsu (Google)
126682756372SMasami Hiramatsu (Google) /* 'tf' is successfully registered. To avoid freeing, assign NULL. */
126782756372SMasami Hiramatsu (Google) tf = NULL;
126882756372SMasami Hiramatsu (Google)
126982756372SMasami Hiramatsu (Google) return 0;
127082756372SMasami Hiramatsu (Google) }
127182756372SMasami Hiramatsu (Google)
trace_fprobe_create_cb(int argc,const char * argv[])127282756372SMasami Hiramatsu (Google) static int trace_fprobe_create_cb(int argc, const char *argv[])
127382756372SMasami Hiramatsu (Google) {
127482756372SMasami Hiramatsu (Google) struct traceprobe_parse_context ctx = {
127582756372SMasami Hiramatsu (Google) .flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE,
127682756372SMasami Hiramatsu (Google) };
127782756372SMasami Hiramatsu (Google) int ret;
1278b1d1e904SMasami Hiramatsu (Google)
1279334e5519SMasami Hiramatsu (Google) trace_probe_log_init("trace_fprobe", argc, argv);
1280334e5519SMasami Hiramatsu (Google) ret = trace_fprobe_create_internal(argc, argv, &ctx);
1281334e5519SMasami Hiramatsu (Google) traceprobe_finish_parse(&ctx);
1282334e5519SMasami Hiramatsu (Google) trace_probe_log_clear();
1283334e5519SMasami Hiramatsu (Google) return ret;
1284334e5519SMasami Hiramatsu (Google) }
128582756372SMasami Hiramatsu (Google)
trace_fprobe_create(const char * raw_command)1286334e5519SMasami Hiramatsu (Google) static int trace_fprobe_create(const char *raw_command)
1287334e5519SMasami Hiramatsu (Google) {
1288334e5519SMasami Hiramatsu (Google) return trace_probe_create(raw_command, trace_fprobe_create_cb);
1289334e5519SMasami Hiramatsu (Google) }
1290334e5519SMasami Hiramatsu (Google)
trace_fprobe_release(struct dyn_event * ev)1291334e5519SMasami Hiramatsu (Google) static int trace_fprobe_release(struct dyn_event *ev)
1292334e5519SMasami Hiramatsu (Google) {
1293334e5519SMasami Hiramatsu (Google) struct trace_fprobe *tf = to_trace_fprobe(ev);
1294334e5519SMasami Hiramatsu (Google) int ret = unregister_trace_fprobe(tf);
1295334e5519SMasami Hiramatsu (Google)
1296334e5519SMasami Hiramatsu (Google) if (!ret)
1297334e5519SMasami Hiramatsu (Google) free_trace_fprobe(tf);
1298334e5519SMasami Hiramatsu (Google) return ret;
1299334e5519SMasami Hiramatsu (Google) }
1300334e5519SMasami Hiramatsu (Google)
trace_fprobe_show(struct seq_file * m,struct dyn_event * ev)1301334e5519SMasami Hiramatsu (Google) static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev)
1302334e5519SMasami Hiramatsu (Google) {
1303e2d0d7b2SMasami Hiramatsu (Google) struct trace_fprobe *tf = to_trace_fprobe(ev);
1304e2d0d7b2SMasami Hiramatsu (Google) int i;
1305e2d0d7b2SMasami Hiramatsu (Google)
1306334e5519SMasami Hiramatsu (Google) if (trace_fprobe_is_tracepoint(tf))
1307334e5519SMasami Hiramatsu (Google) seq_putc(m, 't');
1308334e5519SMasami Hiramatsu (Google) else
1309334e5519SMasami Hiramatsu (Google) seq_putc(m, 'f');
1310334e5519SMasami Hiramatsu (Google) seq_printf(m, ":%s/%s", trace_probe_group_name(&tf->tp),
1311334e5519SMasami Hiramatsu (Google) trace_probe_name(&tf->tp));
1312334e5519SMasami Hiramatsu (Google)
1313334e5519SMasami Hiramatsu (Google) seq_printf(m, " %s%s", trace_fprobe_symbol(tf),
1314334e5519SMasami Hiramatsu (Google) trace_fprobe_is_return(tf) ? "%return" : "");
1315334e5519SMasami Hiramatsu (Google)
1316334e5519SMasami Hiramatsu (Google) for (i = 0; i < tf->tp.nr_args; i++)
1317334e5519SMasami Hiramatsu (Google) seq_printf(m, " %s=%s", tf->tp.args[i].name, tf->tp.args[i].comm);
1318334e5519SMasami Hiramatsu (Google) seq_putc(m, '\n');
1319334e5519SMasami Hiramatsu (Google)
1320334e5519SMasami Hiramatsu (Google) return 0;
1321334e5519SMasami Hiramatsu (Google) }
1322334e5519SMasami Hiramatsu (Google)
1323334e5519SMasami Hiramatsu (Google) /*
1324334e5519SMasami Hiramatsu (Google) * called by perf_trace_init() or __ftrace_set_clr_event() under event_mutex.
1325334e5519SMasami Hiramatsu (Google) */
fprobe_register(struct trace_event_call * event,enum trace_reg type,void * data)1326334e5519SMasami Hiramatsu (Google) static int fprobe_register(struct trace_event_call *event,
1327334e5519SMasami Hiramatsu (Google) enum trace_reg type, void *data)
1328334e5519SMasami Hiramatsu (Google) {
1329334e5519SMasami Hiramatsu (Google) struct trace_event_file *file = data;
1330334e5519SMasami Hiramatsu (Google)
1331334e5519SMasami Hiramatsu (Google) switch (type) {
1332334e5519SMasami Hiramatsu (Google) case TRACE_REG_REGISTER:
1333334e5519SMasami Hiramatsu (Google) return enable_trace_fprobe(event, file);
1334334e5519SMasami Hiramatsu (Google) case TRACE_REG_UNREGISTER:
1335334e5519SMasami Hiramatsu (Google) return disable_trace_fprobe(event, file);
1336334e5519SMasami Hiramatsu (Google)
1337334e5519SMasami Hiramatsu (Google) #ifdef CONFIG_PERF_EVENTS
1338334e5519SMasami Hiramatsu (Google) case TRACE_REG_PERF_REGISTER:
1339334e5519SMasami Hiramatsu (Google) return enable_trace_fprobe(event, NULL);
1340334e5519SMasami Hiramatsu (Google) case TRACE_REG_PERF_UNREGISTER:
1341334e5519SMasami Hiramatsu (Google) return disable_trace_fprobe(event, NULL);
1342334e5519SMasami Hiramatsu (Google) case TRACE_REG_PERF_OPEN:
1343334e5519SMasami Hiramatsu (Google) case TRACE_REG_PERF_CLOSE:
1344334e5519SMasami Hiramatsu (Google) case TRACE_REG_PERF_ADD:
1345334e5519SMasami Hiramatsu (Google) case TRACE_REG_PERF_DEL:
1346334e5519SMasami Hiramatsu (Google) return 0;
1347334e5519SMasami Hiramatsu (Google) #endif
1348334e5519SMasami Hiramatsu (Google) }
1349334e5519SMasami Hiramatsu (Google) return 0;
1350334e5519SMasami Hiramatsu (Google) }
1351334e5519SMasami Hiramatsu (Google)
1352334e5519SMasami Hiramatsu (Google) /*
1353334e5519SMasami Hiramatsu (Google) * Register dynevent at core_initcall. This allows kernel to setup fprobe
1354334e5519SMasami Hiramatsu (Google) * events in postcore_initcall without tracefs.
1355334e5519SMasami Hiramatsu (Google) */
init_fprobe_trace_early(void)1356334e5519SMasami Hiramatsu (Google) static __init int init_fprobe_trace_early(void)
1357334e5519SMasami Hiramatsu (Google) {
1358334e5519SMasami Hiramatsu (Google) int ret;
1359334e5519SMasami Hiramatsu (Google)
1360334e5519SMasami Hiramatsu (Google) ret = dyn_event_register(&trace_fprobe_ops);
1361e2d0d7b2SMasami Hiramatsu (Google) if (ret)
1362e2d0d7b2SMasami Hiramatsu (Google) return ret;
1363e2d0d7b2SMasami Hiramatsu (Google)
1364e2d0d7b2SMasami Hiramatsu (Google) #ifdef CONFIG_MODULES
1365e2d0d7b2SMasami Hiramatsu (Google) ret = register_tracepoint_module_notifier(&tracepoint_module_nb);
1366e2d0d7b2SMasami Hiramatsu (Google) if (ret)
1367334e5519SMasami Hiramatsu (Google) return ret;
1368334e5519SMasami Hiramatsu (Google) #endif
1369334e5519SMasami Hiramatsu (Google)
1370 return 0;
1371 }
1372 core_initcall(init_fprobe_trace_early);
1373