1cad9931fSMasami Hiramatsu // SPDX-License-Identifier: GPL-2.0
2cad9931fSMasami Hiramatsu /*
3cad9931fSMasami Hiramatsu * fprobe - Simple ftrace probe wrapper for function entry.
4cad9931fSMasami Hiramatsu */
5cad9931fSMasami Hiramatsu #define pr_fmt(fmt) "fprobe: " fmt
6cad9931fSMasami Hiramatsu
7cad9931fSMasami Hiramatsu #include <linux/err.h>
8cad9931fSMasami Hiramatsu #include <linux/fprobe.h>
9cad9931fSMasami Hiramatsu #include <linux/kallsyms.h>
10cad9931fSMasami Hiramatsu #include <linux/kprobes.h>
115b0ab789SMasami Hiramatsu #include <linux/rethook.h>
12cad9931fSMasami Hiramatsu #include <linux/slab.h>
13cad9931fSMasami Hiramatsu #include <linux/sort.h>
14cad9931fSMasami Hiramatsu
155b0ab789SMasami Hiramatsu #include "trace.h"
165b0ab789SMasami Hiramatsu
175b0ab789SMasami Hiramatsu struct fprobe_rethook_node {
185b0ab789SMasami Hiramatsu struct rethook_node node;
195b0ab789SMasami Hiramatsu unsigned long entry_ip;
2027527410SZe Gao unsigned long entry_parent_ip;
2176d0de57SMasami Hiramatsu (Google) char data[];
225b0ab789SMasami Hiramatsu };
235b0ab789SMasami Hiramatsu
__fprobe_handler(unsigned long ip,unsigned long parent_ip,struct ftrace_ops * ops,struct ftrace_regs * fregs)243cc4e2c5SZe Gao static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip,
25cad9931fSMasami Hiramatsu struct ftrace_ops *ops, struct ftrace_regs *fregs)
26cad9931fSMasami Hiramatsu {
275b0ab789SMasami Hiramatsu struct fprobe_rethook_node *fpr;
2876d0de57SMasami Hiramatsu (Google) struct rethook_node *rh = NULL;
29cad9931fSMasami Hiramatsu struct fprobe *fp;
3076d0de57SMasami Hiramatsu (Google) void *entry_data = NULL;
313cc4e2c5SZe Gao int ret = 0;
32cad9931fSMasami Hiramatsu
33cad9931fSMasami Hiramatsu fp = container_of(ops, struct fprobe, ops);
34cad9931fSMasami Hiramatsu
355b0ab789SMasami Hiramatsu if (fp->exit_handler) {
365b0ab789SMasami Hiramatsu rh = rethook_try_get(fp->rethook);
375b0ab789SMasami Hiramatsu if (!rh) {
385b0ab789SMasami Hiramatsu fp->nmissed++;
393cc4e2c5SZe Gao return;
405b0ab789SMasami Hiramatsu }
415b0ab789SMasami Hiramatsu fpr = container_of(rh, struct fprobe_rethook_node, node);
425b0ab789SMasami Hiramatsu fpr->entry_ip = ip;
4327527410SZe Gao fpr->entry_parent_ip = parent_ip;
4476d0de57SMasami Hiramatsu (Google) if (fp->entry_data_size)
4576d0de57SMasami Hiramatsu (Google) entry_data = fpr->data;
465b0ab789SMasami Hiramatsu }
475b0ab789SMasami Hiramatsu
4876d0de57SMasami Hiramatsu (Google) if (fp->entry_handler)
49cb16330dSMasami Hiramatsu (Google) ret = fp->entry_handler(fp, ip, parent_ip, ftrace_get_regs(fregs), entry_data);
5076d0de57SMasami Hiramatsu (Google)
5139d95420SMasami Hiramatsu (Google) /* If entry_handler returns !0, nmissed is not counted. */
5239d95420SMasami Hiramatsu (Google) if (rh) {
5339d95420SMasami Hiramatsu (Google) if (ret)
5439d95420SMasami Hiramatsu (Google) rethook_recycle(rh);
5539d95420SMasami Hiramatsu (Google) else
5676d0de57SMasami Hiramatsu (Google) rethook_hook(rh, ftrace_get_regs(fregs), true);
5739d95420SMasami Hiramatsu (Google) }
583cc4e2c5SZe Gao }
593cc4e2c5SZe Gao
fprobe_handler(unsigned long ip,unsigned long parent_ip,struct ftrace_ops * ops,struct ftrace_regs * fregs)603cc4e2c5SZe Gao static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
613cc4e2c5SZe Gao struct ftrace_ops *ops, struct ftrace_regs *fregs)
623cc4e2c5SZe Gao {
633cc4e2c5SZe Gao struct fprobe *fp;
643cc4e2c5SZe Gao int bit;
653cc4e2c5SZe Gao
663cc4e2c5SZe Gao fp = container_of(ops, struct fprobe, ops);
673cc4e2c5SZe Gao if (fprobe_disabled(fp))
683cc4e2c5SZe Gao return;
693cc4e2c5SZe Gao
703cc4e2c5SZe Gao /* recursion detection has to go before any traceable function and
713cc4e2c5SZe Gao * all functions before this point should be marked as notrace
723cc4e2c5SZe Gao */
733cc4e2c5SZe Gao bit = ftrace_test_recursion_trylock(ip, parent_ip);
743cc4e2c5SZe Gao if (bit < 0) {
753cc4e2c5SZe Gao fp->nmissed++;
763cc4e2c5SZe Gao return;
773cc4e2c5SZe Gao }
783cc4e2c5SZe Gao __fprobe_handler(ip, parent_ip, ops, fregs);
79cad9931fSMasami Hiramatsu ftrace_test_recursion_unlock(bit);
803cc4e2c5SZe Gao
81cad9931fSMasami Hiramatsu }
82cad9931fSMasami Hiramatsu NOKPROBE_SYMBOL(fprobe_handler);
83cad9931fSMasami Hiramatsu
fprobe_kprobe_handler(unsigned long ip,unsigned long parent_ip,struct ftrace_ops * ops,struct ftrace_regs * fregs)84ab51e15dSMasami Hiramatsu static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
85ab51e15dSMasami Hiramatsu struct ftrace_ops *ops, struct ftrace_regs *fregs)
86ab51e15dSMasami Hiramatsu {
873cc4e2c5SZe Gao struct fprobe *fp;
883cc4e2c5SZe Gao int bit;
893cc4e2c5SZe Gao
903cc4e2c5SZe Gao fp = container_of(ops, struct fprobe, ops);
913cc4e2c5SZe Gao if (fprobe_disabled(fp))
923cc4e2c5SZe Gao return;
933cc4e2c5SZe Gao
943cc4e2c5SZe Gao /* recursion detection has to go before any traceable function and
953cc4e2c5SZe Gao * all functions called before this point should be marked as notrace
963cc4e2c5SZe Gao */
973cc4e2c5SZe Gao bit = ftrace_test_recursion_trylock(ip, parent_ip);
983cc4e2c5SZe Gao if (bit < 0) {
993cc4e2c5SZe Gao fp->nmissed++;
1003cc4e2c5SZe Gao return;
1013cc4e2c5SZe Gao }
102ab51e15dSMasami Hiramatsu
103d5f28bb1SMasami Hiramatsu (Google) /*
104d5f28bb1SMasami Hiramatsu (Google) * This user handler is shared with other kprobes and is not expected to be
105d5f28bb1SMasami Hiramatsu (Google) * called recursively. So if any other kprobe handler is running, this will
106d5f28bb1SMasami Hiramatsu (Google) * exit as kprobe does. See the section 'Share the callbacks with kprobes'
107d5f28bb1SMasami Hiramatsu (Google) * in Documentation/trace/fprobe.rst for more information.
108d5f28bb1SMasami Hiramatsu (Google) */
109ab51e15dSMasami Hiramatsu if (unlikely(kprobe_running())) {
110ab51e15dSMasami Hiramatsu fp->nmissed++;
1115f0c584dSZe Gao goto recursion_unlock;
112ab51e15dSMasami Hiramatsu }
1133cc4e2c5SZe Gao
114ab51e15dSMasami Hiramatsu kprobe_busy_begin();
1153cc4e2c5SZe Gao __fprobe_handler(ip, parent_ip, ops, fregs);
116ab51e15dSMasami Hiramatsu kprobe_busy_end();
1175f0c584dSZe Gao
1185f0c584dSZe Gao recursion_unlock:
1193cc4e2c5SZe Gao ftrace_test_recursion_unlock(bit);
120ab51e15dSMasami Hiramatsu }
121ab51e15dSMasami Hiramatsu
fprobe_exit_handler(struct rethook_node * rh,void * data,unsigned long ret_ip,struct pt_regs * regs)1225b0ab789SMasami Hiramatsu static void fprobe_exit_handler(struct rethook_node *rh, void *data,
123cb16330dSMasami Hiramatsu (Google) unsigned long ret_ip, struct pt_regs *regs)
1245b0ab789SMasami Hiramatsu {
1255b0ab789SMasami Hiramatsu struct fprobe *fp = (struct fprobe *)data;
1265b0ab789SMasami Hiramatsu struct fprobe_rethook_node *fpr;
12727527410SZe Gao int bit;
1285b0ab789SMasami Hiramatsu
1295b0ab789SMasami Hiramatsu if (!fp || fprobe_disabled(fp))
1305b0ab789SMasami Hiramatsu return;
1315b0ab789SMasami Hiramatsu
1325b0ab789SMasami Hiramatsu fpr = container_of(rh, struct fprobe_rethook_node, node);
1335b0ab789SMasami Hiramatsu
13427527410SZe Gao /*
13527527410SZe Gao * we need to assure no calls to traceable functions in-between the
13627527410SZe Gao * end of fprobe_handler and the beginning of fprobe_exit_handler.
13727527410SZe Gao */
13827527410SZe Gao bit = ftrace_test_recursion_trylock(fpr->entry_ip, fpr->entry_parent_ip);
13927527410SZe Gao if (bit < 0) {
14027527410SZe Gao fp->nmissed++;
14127527410SZe Gao return;
14227527410SZe Gao }
14327527410SZe Gao
144cb16330dSMasami Hiramatsu (Google) fp->exit_handler(fp, fpr->entry_ip, ret_ip, regs,
14576d0de57SMasami Hiramatsu (Google) fp->entry_data_size ? (void *)fpr->data : NULL);
14627527410SZe Gao ftrace_test_recursion_unlock(bit);
1475b0ab789SMasami Hiramatsu }
1485b0ab789SMasami Hiramatsu NOKPROBE_SYMBOL(fprobe_exit_handler);
1495b0ab789SMasami Hiramatsu
symbols_cmp(const void * a,const void * b)1508be92533SJiri Olsa static int symbols_cmp(const void *a, const void *b)
1518be92533SJiri Olsa {
1528be92533SJiri Olsa const char **str_a = (const char **) a;
1538be92533SJiri Olsa const char **str_b = (const char **) b;
1548be92533SJiri Olsa
1558be92533SJiri Olsa return strcmp(*str_a, *str_b);
1568be92533SJiri Olsa }
1578be92533SJiri Olsa
158cad9931fSMasami Hiramatsu /* Convert ftrace location address from symbols */
get_ftrace_locations(const char ** syms,int num)159cad9931fSMasami Hiramatsu static unsigned long *get_ftrace_locations(const char **syms, int num)
160cad9931fSMasami Hiramatsu {
161cad9931fSMasami Hiramatsu unsigned long *addrs;
162cad9931fSMasami Hiramatsu
163cad9931fSMasami Hiramatsu /* Convert symbols to symbol address */
164cad9931fSMasami Hiramatsu addrs = kcalloc(num, sizeof(*addrs), GFP_KERNEL);
165cad9931fSMasami Hiramatsu if (!addrs)
166cad9931fSMasami Hiramatsu return ERR_PTR(-ENOMEM);
167cad9931fSMasami Hiramatsu
1688be92533SJiri Olsa /* ftrace_lookup_symbols expects sorted symbols */
1698be92533SJiri Olsa sort(syms, num, sizeof(*syms), symbols_cmp, NULL);
170cad9931fSMasami Hiramatsu
1718be92533SJiri Olsa if (!ftrace_lookup_symbols(syms, num, addrs))
172cad9931fSMasami Hiramatsu return addrs;
173cad9931fSMasami Hiramatsu
174cad9931fSMasami Hiramatsu kfree(addrs);
175cad9931fSMasami Hiramatsu return ERR_PTR(-ENOENT);
176cad9931fSMasami Hiramatsu }
177cad9931fSMasami Hiramatsu
fprobe_init(struct fprobe * fp)178cad9931fSMasami Hiramatsu static void fprobe_init(struct fprobe *fp)
179cad9931fSMasami Hiramatsu {
180cad9931fSMasami Hiramatsu fp->nmissed = 0;
181ab51e15dSMasami Hiramatsu if (fprobe_shared_with_kprobes(fp))
182ab51e15dSMasami Hiramatsu fp->ops.func = fprobe_kprobe_handler;
183ab51e15dSMasami Hiramatsu else
184cad9931fSMasami Hiramatsu fp->ops.func = fprobe_handler;
185cad9931fSMasami Hiramatsu fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS;
186cad9931fSMasami Hiramatsu }
187cad9931fSMasami Hiramatsu
fprobe_init_rethook(struct fprobe * fp,int num)1885b0ab789SMasami Hiramatsu static int fprobe_init_rethook(struct fprobe *fp, int num)
1895b0ab789SMasami Hiramatsu {
1905b0ab789SMasami Hiramatsu int i, size;
1915b0ab789SMasami Hiramatsu
192*700b2b43SMasami Hiramatsu (Google) if (num <= 0)
1935b0ab789SMasami Hiramatsu return -EINVAL;
1945b0ab789SMasami Hiramatsu
1955b0ab789SMasami Hiramatsu if (!fp->exit_handler) {
1965b0ab789SMasami Hiramatsu fp->rethook = NULL;
1975b0ab789SMasami Hiramatsu return 0;
1985b0ab789SMasami Hiramatsu }
1995b0ab789SMasami Hiramatsu
2005b0ab789SMasami Hiramatsu /* Initialize rethook if needed */
20159a7a298SMasami Hiramatsu (Google) if (fp->nr_maxactive)
20259a7a298SMasami Hiramatsu (Google) size = fp->nr_maxactive;
20359a7a298SMasami Hiramatsu (Google) else
2045b0ab789SMasami Hiramatsu size = num * num_possible_cpus() * 2;
205*700b2b43SMasami Hiramatsu (Google) if (size <= 0)
206*700b2b43SMasami Hiramatsu (Google) return -EINVAL;
2075b0ab789SMasami Hiramatsu
2085b0ab789SMasami Hiramatsu fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler);
209d05ea35eSRafael Mendonca if (!fp->rethook)
210d05ea35eSRafael Mendonca return -ENOMEM;
2115b0ab789SMasami Hiramatsu for (i = 0; i < size; i++) {
2129052e4e8SMasami Hiramatsu struct fprobe_rethook_node *node;
2135b0ab789SMasami Hiramatsu
21476d0de57SMasami Hiramatsu (Google) node = kzalloc(sizeof(*node) + fp->entry_data_size, GFP_KERNEL);
2155b0ab789SMasami Hiramatsu if (!node) {
2165b0ab789SMasami Hiramatsu rethook_free(fp->rethook);
2175b0ab789SMasami Hiramatsu fp->rethook = NULL;
2185b0ab789SMasami Hiramatsu return -ENOMEM;
2195b0ab789SMasami Hiramatsu }
2209052e4e8SMasami Hiramatsu rethook_add_node(fp->rethook, &node->node);
2215b0ab789SMasami Hiramatsu }
2225b0ab789SMasami Hiramatsu return 0;
2235b0ab789SMasami Hiramatsu }
2245b0ab789SMasami Hiramatsu
fprobe_fail_cleanup(struct fprobe * fp)2255b0ab789SMasami Hiramatsu static void fprobe_fail_cleanup(struct fprobe *fp)
2265b0ab789SMasami Hiramatsu {
2275b0ab789SMasami Hiramatsu if (fp->rethook) {
2285b0ab789SMasami Hiramatsu /* Don't need to cleanup rethook->handler because this is not used. */
2295b0ab789SMasami Hiramatsu rethook_free(fp->rethook);
2305b0ab789SMasami Hiramatsu fp->rethook = NULL;
2315b0ab789SMasami Hiramatsu }
2325b0ab789SMasami Hiramatsu ftrace_free_filter(&fp->ops);
2335b0ab789SMasami Hiramatsu }
2345b0ab789SMasami Hiramatsu
235cad9931fSMasami Hiramatsu /**
236cad9931fSMasami Hiramatsu * register_fprobe() - Register fprobe to ftrace by pattern.
237cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be registered.
238cad9931fSMasami Hiramatsu * @filter: A wildcard pattern of probed symbols.
239cad9931fSMasami Hiramatsu * @notfilter: A wildcard pattern of NOT probed symbols.
240cad9931fSMasami Hiramatsu *
241cad9931fSMasami Hiramatsu * Register @fp to ftrace for enabling the probe on the symbols matched to @filter.
242cad9931fSMasami Hiramatsu * If @notfilter is not NULL, the symbols matched the @notfilter are not probed.
243cad9931fSMasami Hiramatsu *
244cad9931fSMasami Hiramatsu * Return 0 if @fp is registered successfully, -errno if not.
245cad9931fSMasami Hiramatsu */
register_fprobe(struct fprobe * fp,const char * filter,const char * notfilter)246cad9931fSMasami Hiramatsu int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter)
247cad9931fSMasami Hiramatsu {
2485b0ab789SMasami Hiramatsu struct ftrace_hash *hash;
249cad9931fSMasami Hiramatsu unsigned char *str;
250cad9931fSMasami Hiramatsu int ret, len;
251cad9931fSMasami Hiramatsu
252cad9931fSMasami Hiramatsu if (!fp || !filter)
253cad9931fSMasami Hiramatsu return -EINVAL;
254cad9931fSMasami Hiramatsu
255cad9931fSMasami Hiramatsu fprobe_init(fp);
256cad9931fSMasami Hiramatsu
257cad9931fSMasami Hiramatsu len = strlen(filter);
258cad9931fSMasami Hiramatsu str = kstrdup(filter, GFP_KERNEL);
259cad9931fSMasami Hiramatsu ret = ftrace_set_filter(&fp->ops, str, len, 0);
260cad9931fSMasami Hiramatsu kfree(str);
261cad9931fSMasami Hiramatsu if (ret)
262cad9931fSMasami Hiramatsu return ret;
263cad9931fSMasami Hiramatsu
264cad9931fSMasami Hiramatsu if (notfilter) {
265cad9931fSMasami Hiramatsu len = strlen(notfilter);
266cad9931fSMasami Hiramatsu str = kstrdup(notfilter, GFP_KERNEL);
267cad9931fSMasami Hiramatsu ret = ftrace_set_notrace(&fp->ops, str, len, 0);
268cad9931fSMasami Hiramatsu kfree(str);
269cad9931fSMasami Hiramatsu if (ret)
270cad9931fSMasami Hiramatsu goto out;
271cad9931fSMasami Hiramatsu }
272cad9931fSMasami Hiramatsu
2735b0ab789SMasami Hiramatsu /* TODO:
2745b0ab789SMasami Hiramatsu * correctly calculate the total number of filtered symbols
2755b0ab789SMasami Hiramatsu * from both filter and notfilter.
2765b0ab789SMasami Hiramatsu */
277261608f3SMasami Hiramatsu hash = rcu_access_pointer(fp->ops.local_hash.filter_hash);
2785b0ab789SMasami Hiramatsu if (WARN_ON_ONCE(!hash))
2795b0ab789SMasami Hiramatsu goto out;
2805b0ab789SMasami Hiramatsu
2815b0ab789SMasami Hiramatsu ret = fprobe_init_rethook(fp, (int)hash->count);
2825b0ab789SMasami Hiramatsu if (!ret)
283cad9931fSMasami Hiramatsu ret = register_ftrace_function(&fp->ops);
2845b0ab789SMasami Hiramatsu
285cad9931fSMasami Hiramatsu out:
286cad9931fSMasami Hiramatsu if (ret)
2875b0ab789SMasami Hiramatsu fprobe_fail_cleanup(fp);
288cad9931fSMasami Hiramatsu return ret;
289cad9931fSMasami Hiramatsu }
290cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(register_fprobe);
291cad9931fSMasami Hiramatsu
292cad9931fSMasami Hiramatsu /**
293cad9931fSMasami Hiramatsu * register_fprobe_ips() - Register fprobe to ftrace by address.
294cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be registered.
295cad9931fSMasami Hiramatsu * @addrs: An array of target ftrace location addresses.
296cad9931fSMasami Hiramatsu * @num: The number of entries of @addrs.
297cad9931fSMasami Hiramatsu *
298cad9931fSMasami Hiramatsu * Register @fp to ftrace for enabling the probe on the address given by @addrs.
299cad9931fSMasami Hiramatsu * The @addrs must be the addresses of ftrace location address, which may be
300cad9931fSMasami Hiramatsu * the symbol address + arch-dependent offset.
301cad9931fSMasami Hiramatsu * If you unsure what this mean, please use other registration functions.
302cad9931fSMasami Hiramatsu *
303cad9931fSMasami Hiramatsu * Return 0 if @fp is registered successfully, -errno if not.
304cad9931fSMasami Hiramatsu */
register_fprobe_ips(struct fprobe * fp,unsigned long * addrs,int num)305cad9931fSMasami Hiramatsu int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num)
306cad9931fSMasami Hiramatsu {
307cad9931fSMasami Hiramatsu int ret;
308cad9931fSMasami Hiramatsu
309cad9931fSMasami Hiramatsu if (!fp || !addrs || num <= 0)
310cad9931fSMasami Hiramatsu return -EINVAL;
311cad9931fSMasami Hiramatsu
312cad9931fSMasami Hiramatsu fprobe_init(fp);
313cad9931fSMasami Hiramatsu
314cad9931fSMasami Hiramatsu ret = ftrace_set_filter_ips(&fp->ops, addrs, num, 0, 0);
3155b0ab789SMasami Hiramatsu if (ret)
3165b0ab789SMasami Hiramatsu return ret;
3175b0ab789SMasami Hiramatsu
3185b0ab789SMasami Hiramatsu ret = fprobe_init_rethook(fp, num);
319cad9931fSMasami Hiramatsu if (!ret)
320cad9931fSMasami Hiramatsu ret = register_ftrace_function(&fp->ops);
321cad9931fSMasami Hiramatsu
322cad9931fSMasami Hiramatsu if (ret)
3235b0ab789SMasami Hiramatsu fprobe_fail_cleanup(fp);
324cad9931fSMasami Hiramatsu return ret;
325cad9931fSMasami Hiramatsu }
326cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(register_fprobe_ips);
327cad9931fSMasami Hiramatsu
328cad9931fSMasami Hiramatsu /**
329cad9931fSMasami Hiramatsu * register_fprobe_syms() - Register fprobe to ftrace by symbols.
330cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be registered.
331cad9931fSMasami Hiramatsu * @syms: An array of target symbols.
332cad9931fSMasami Hiramatsu * @num: The number of entries of @syms.
333cad9931fSMasami Hiramatsu *
334cad9931fSMasami Hiramatsu * Register @fp to the symbols given by @syms array. This will be useful if
335cad9931fSMasami Hiramatsu * you are sure the symbols exist in the kernel.
336cad9931fSMasami Hiramatsu *
337cad9931fSMasami Hiramatsu * Return 0 if @fp is registered successfully, -errno if not.
338cad9931fSMasami Hiramatsu */
register_fprobe_syms(struct fprobe * fp,const char ** syms,int num)339cad9931fSMasami Hiramatsu int register_fprobe_syms(struct fprobe *fp, const char **syms, int num)
340cad9931fSMasami Hiramatsu {
341cad9931fSMasami Hiramatsu unsigned long *addrs;
342cad9931fSMasami Hiramatsu int ret;
343cad9931fSMasami Hiramatsu
344cad9931fSMasami Hiramatsu if (!fp || !syms || num <= 0)
345cad9931fSMasami Hiramatsu return -EINVAL;
346cad9931fSMasami Hiramatsu
347cad9931fSMasami Hiramatsu addrs = get_ftrace_locations(syms, num);
348cad9931fSMasami Hiramatsu if (IS_ERR(addrs))
349cad9931fSMasami Hiramatsu return PTR_ERR(addrs);
350cad9931fSMasami Hiramatsu
351cad9931fSMasami Hiramatsu ret = register_fprobe_ips(fp, addrs, num);
352cad9931fSMasami Hiramatsu
353cad9931fSMasami Hiramatsu kfree(addrs);
354cad9931fSMasami Hiramatsu
355cad9931fSMasami Hiramatsu return ret;
356cad9931fSMasami Hiramatsu }
357cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(register_fprobe_syms);
358cad9931fSMasami Hiramatsu
fprobe_is_registered(struct fprobe * fp)359334e5519SMasami Hiramatsu (Google) bool fprobe_is_registered(struct fprobe *fp)
360334e5519SMasami Hiramatsu (Google) {
361334e5519SMasami Hiramatsu (Google) if (!fp || (fp->ops.saved_func != fprobe_handler &&
362334e5519SMasami Hiramatsu (Google) fp->ops.saved_func != fprobe_kprobe_handler))
363334e5519SMasami Hiramatsu (Google) return false;
364334e5519SMasami Hiramatsu (Google) return true;
365334e5519SMasami Hiramatsu (Google) }
366334e5519SMasami Hiramatsu (Google)
367cad9931fSMasami Hiramatsu /**
368cad9931fSMasami Hiramatsu * unregister_fprobe() - Unregister fprobe from ftrace
369cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be unregistered.
370cad9931fSMasami Hiramatsu *
371cad9931fSMasami Hiramatsu * Unregister fprobe (and remove ftrace hooks from the function entries).
372cad9931fSMasami Hiramatsu *
373cad9931fSMasami Hiramatsu * Return 0 if @fp is unregistered successfully, -errno if not.
374cad9931fSMasami Hiramatsu */
unregister_fprobe(struct fprobe * fp)375cad9931fSMasami Hiramatsu int unregister_fprobe(struct fprobe *fp)
376cad9931fSMasami Hiramatsu {
377cad9931fSMasami Hiramatsu int ret;
378cad9931fSMasami Hiramatsu
379334e5519SMasami Hiramatsu (Google) if (!fprobe_is_registered(fp))
380cad9931fSMasami Hiramatsu return -EINVAL;
381cad9931fSMasami Hiramatsu
3825b0ab789SMasami Hiramatsu if (fp->rethook)
383195b9cb5SMasami Hiramatsu (Google) rethook_stop(fp->rethook);
384cad9931fSMasami Hiramatsu
3855b0ab789SMasami Hiramatsu ret = unregister_ftrace_function(&fp->ops);
3865b0ab789SMasami Hiramatsu if (ret < 0)
3875b0ab789SMasami Hiramatsu return ret;
3885b0ab789SMasami Hiramatsu
3895f810187SJiri Olsa if (fp->rethook)
3905f810187SJiri Olsa rethook_free(fp->rethook);
3915f810187SJiri Olsa
392cad9931fSMasami Hiramatsu ftrace_free_filter(&fp->ops);
393cad9931fSMasami Hiramatsu
394cad9931fSMasami Hiramatsu return ret;
395cad9931fSMasami Hiramatsu }
396cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(unregister_fprobe);
397