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; 20*76d0de57SMasami Hiramatsu (Google) char data[]; 215b0ab789SMasami Hiramatsu }; 225b0ab789SMasami Hiramatsu 23cad9931fSMasami Hiramatsu static void fprobe_handler(unsigned long ip, unsigned long parent_ip, 24cad9931fSMasami Hiramatsu struct ftrace_ops *ops, struct ftrace_regs *fregs) 25cad9931fSMasami Hiramatsu { 265b0ab789SMasami Hiramatsu struct fprobe_rethook_node *fpr; 27*76d0de57SMasami Hiramatsu (Google) struct rethook_node *rh = NULL; 28cad9931fSMasami Hiramatsu struct fprobe *fp; 29*76d0de57SMasami Hiramatsu (Google) void *entry_data = NULL; 30cad9931fSMasami Hiramatsu int bit; 31cad9931fSMasami Hiramatsu 32cad9931fSMasami Hiramatsu fp = container_of(ops, struct fprobe, ops); 33cad9931fSMasami Hiramatsu if (fprobe_disabled(fp)) 34cad9931fSMasami Hiramatsu return; 35cad9931fSMasami Hiramatsu 36cad9931fSMasami Hiramatsu bit = ftrace_test_recursion_trylock(ip, parent_ip); 37cad9931fSMasami Hiramatsu if (bit < 0) { 38cad9931fSMasami Hiramatsu fp->nmissed++; 39cad9931fSMasami Hiramatsu return; 40cad9931fSMasami Hiramatsu } 41cad9931fSMasami Hiramatsu 425b0ab789SMasami Hiramatsu if (fp->exit_handler) { 435b0ab789SMasami Hiramatsu rh = rethook_try_get(fp->rethook); 445b0ab789SMasami Hiramatsu if (!rh) { 455b0ab789SMasami Hiramatsu fp->nmissed++; 465b0ab789SMasami Hiramatsu goto out; 475b0ab789SMasami Hiramatsu } 485b0ab789SMasami Hiramatsu fpr = container_of(rh, struct fprobe_rethook_node, node); 495b0ab789SMasami Hiramatsu fpr->entry_ip = ip; 50*76d0de57SMasami Hiramatsu (Google) if (fp->entry_data_size) 51*76d0de57SMasami Hiramatsu (Google) entry_data = fpr->data; 525b0ab789SMasami Hiramatsu } 535b0ab789SMasami Hiramatsu 54*76d0de57SMasami Hiramatsu (Google) if (fp->entry_handler) 55*76d0de57SMasami Hiramatsu (Google) fp->entry_handler(fp, ip, ftrace_get_regs(fregs), entry_data); 56*76d0de57SMasami Hiramatsu (Google) 57*76d0de57SMasami Hiramatsu (Google) if (rh) 58*76d0de57SMasami Hiramatsu (Google) rethook_hook(rh, ftrace_get_regs(fregs), true); 59*76d0de57SMasami Hiramatsu (Google) 605b0ab789SMasami Hiramatsu out: 61cad9931fSMasami Hiramatsu ftrace_test_recursion_unlock(bit); 62cad9931fSMasami Hiramatsu } 63cad9931fSMasami Hiramatsu NOKPROBE_SYMBOL(fprobe_handler); 64cad9931fSMasami Hiramatsu 65ab51e15dSMasami Hiramatsu static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip, 66ab51e15dSMasami Hiramatsu struct ftrace_ops *ops, struct ftrace_regs *fregs) 67ab51e15dSMasami Hiramatsu { 68ab51e15dSMasami Hiramatsu struct fprobe *fp = container_of(ops, struct fprobe, ops); 69ab51e15dSMasami Hiramatsu 70ab51e15dSMasami Hiramatsu if (unlikely(kprobe_running())) { 71ab51e15dSMasami Hiramatsu fp->nmissed++; 72ab51e15dSMasami Hiramatsu return; 73ab51e15dSMasami Hiramatsu } 74ab51e15dSMasami Hiramatsu kprobe_busy_begin(); 75ab51e15dSMasami Hiramatsu fprobe_handler(ip, parent_ip, ops, fregs); 76ab51e15dSMasami Hiramatsu kprobe_busy_end(); 77ab51e15dSMasami Hiramatsu } 78ab51e15dSMasami Hiramatsu 795b0ab789SMasami Hiramatsu static void fprobe_exit_handler(struct rethook_node *rh, void *data, 805b0ab789SMasami Hiramatsu struct pt_regs *regs) 815b0ab789SMasami Hiramatsu { 825b0ab789SMasami Hiramatsu struct fprobe *fp = (struct fprobe *)data; 835b0ab789SMasami Hiramatsu struct fprobe_rethook_node *fpr; 845b0ab789SMasami Hiramatsu 855b0ab789SMasami Hiramatsu if (!fp || fprobe_disabled(fp)) 865b0ab789SMasami Hiramatsu return; 875b0ab789SMasami Hiramatsu 885b0ab789SMasami Hiramatsu fpr = container_of(rh, struct fprobe_rethook_node, node); 895b0ab789SMasami Hiramatsu 90*76d0de57SMasami Hiramatsu (Google) fp->exit_handler(fp, fpr->entry_ip, regs, 91*76d0de57SMasami Hiramatsu (Google) fp->entry_data_size ? (void *)fpr->data : NULL); 925b0ab789SMasami Hiramatsu } 935b0ab789SMasami Hiramatsu NOKPROBE_SYMBOL(fprobe_exit_handler); 945b0ab789SMasami Hiramatsu 958be92533SJiri Olsa static int symbols_cmp(const void *a, const void *b) 968be92533SJiri Olsa { 978be92533SJiri Olsa const char **str_a = (const char **) a; 988be92533SJiri Olsa const char **str_b = (const char **) b; 998be92533SJiri Olsa 1008be92533SJiri Olsa return strcmp(*str_a, *str_b); 1018be92533SJiri Olsa } 1028be92533SJiri Olsa 103cad9931fSMasami Hiramatsu /* Convert ftrace location address from symbols */ 104cad9931fSMasami Hiramatsu static unsigned long *get_ftrace_locations(const char **syms, int num) 105cad9931fSMasami Hiramatsu { 106cad9931fSMasami Hiramatsu unsigned long *addrs; 107cad9931fSMasami Hiramatsu 108cad9931fSMasami Hiramatsu /* Convert symbols to symbol address */ 109cad9931fSMasami Hiramatsu addrs = kcalloc(num, sizeof(*addrs), GFP_KERNEL); 110cad9931fSMasami Hiramatsu if (!addrs) 111cad9931fSMasami Hiramatsu return ERR_PTR(-ENOMEM); 112cad9931fSMasami Hiramatsu 1138be92533SJiri Olsa /* ftrace_lookup_symbols expects sorted symbols */ 1148be92533SJiri Olsa sort(syms, num, sizeof(*syms), symbols_cmp, NULL); 115cad9931fSMasami Hiramatsu 1168be92533SJiri Olsa if (!ftrace_lookup_symbols(syms, num, addrs)) 117cad9931fSMasami Hiramatsu return addrs; 118cad9931fSMasami Hiramatsu 119cad9931fSMasami Hiramatsu kfree(addrs); 120cad9931fSMasami Hiramatsu return ERR_PTR(-ENOENT); 121cad9931fSMasami Hiramatsu } 122cad9931fSMasami Hiramatsu 123cad9931fSMasami Hiramatsu static void fprobe_init(struct fprobe *fp) 124cad9931fSMasami Hiramatsu { 125cad9931fSMasami Hiramatsu fp->nmissed = 0; 126ab51e15dSMasami Hiramatsu if (fprobe_shared_with_kprobes(fp)) 127ab51e15dSMasami Hiramatsu fp->ops.func = fprobe_kprobe_handler; 128ab51e15dSMasami Hiramatsu else 129cad9931fSMasami Hiramatsu fp->ops.func = fprobe_handler; 130cad9931fSMasami Hiramatsu fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS; 131cad9931fSMasami Hiramatsu } 132cad9931fSMasami Hiramatsu 1335b0ab789SMasami Hiramatsu static int fprobe_init_rethook(struct fprobe *fp, int num) 1345b0ab789SMasami Hiramatsu { 1355b0ab789SMasami Hiramatsu int i, size; 1365b0ab789SMasami Hiramatsu 1375b0ab789SMasami Hiramatsu if (num < 0) 1385b0ab789SMasami Hiramatsu return -EINVAL; 1395b0ab789SMasami Hiramatsu 1405b0ab789SMasami Hiramatsu if (!fp->exit_handler) { 1415b0ab789SMasami Hiramatsu fp->rethook = NULL; 1425b0ab789SMasami Hiramatsu return 0; 1435b0ab789SMasami Hiramatsu } 1445b0ab789SMasami Hiramatsu 1455b0ab789SMasami Hiramatsu /* Initialize rethook if needed */ 1465b0ab789SMasami Hiramatsu size = num * num_possible_cpus() * 2; 1475b0ab789SMasami Hiramatsu if (size < 0) 1485b0ab789SMasami Hiramatsu return -E2BIG; 1495b0ab789SMasami Hiramatsu 1505b0ab789SMasami Hiramatsu fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler); 151d05ea35eSRafael Mendonca if (!fp->rethook) 152d05ea35eSRafael Mendonca return -ENOMEM; 1535b0ab789SMasami Hiramatsu for (i = 0; i < size; i++) { 1549052e4e8SMasami Hiramatsu struct fprobe_rethook_node *node; 1555b0ab789SMasami Hiramatsu 156*76d0de57SMasami Hiramatsu (Google) node = kzalloc(sizeof(*node) + fp->entry_data_size, GFP_KERNEL); 1575b0ab789SMasami Hiramatsu if (!node) { 1585b0ab789SMasami Hiramatsu rethook_free(fp->rethook); 1595b0ab789SMasami Hiramatsu fp->rethook = NULL; 1605b0ab789SMasami Hiramatsu return -ENOMEM; 1615b0ab789SMasami Hiramatsu } 1629052e4e8SMasami Hiramatsu rethook_add_node(fp->rethook, &node->node); 1635b0ab789SMasami Hiramatsu } 1645b0ab789SMasami Hiramatsu return 0; 1655b0ab789SMasami Hiramatsu } 1665b0ab789SMasami Hiramatsu 1675b0ab789SMasami Hiramatsu static void fprobe_fail_cleanup(struct fprobe *fp) 1685b0ab789SMasami Hiramatsu { 1695b0ab789SMasami Hiramatsu if (fp->rethook) { 1705b0ab789SMasami Hiramatsu /* Don't need to cleanup rethook->handler because this is not used. */ 1715b0ab789SMasami Hiramatsu rethook_free(fp->rethook); 1725b0ab789SMasami Hiramatsu fp->rethook = NULL; 1735b0ab789SMasami Hiramatsu } 1745b0ab789SMasami Hiramatsu ftrace_free_filter(&fp->ops); 1755b0ab789SMasami Hiramatsu } 1765b0ab789SMasami Hiramatsu 177cad9931fSMasami Hiramatsu /** 178cad9931fSMasami Hiramatsu * register_fprobe() - Register fprobe to ftrace by pattern. 179cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be registered. 180cad9931fSMasami Hiramatsu * @filter: A wildcard pattern of probed symbols. 181cad9931fSMasami Hiramatsu * @notfilter: A wildcard pattern of NOT probed symbols. 182cad9931fSMasami Hiramatsu * 183cad9931fSMasami Hiramatsu * Register @fp to ftrace for enabling the probe on the symbols matched to @filter. 184cad9931fSMasami Hiramatsu * If @notfilter is not NULL, the symbols matched the @notfilter are not probed. 185cad9931fSMasami Hiramatsu * 186cad9931fSMasami Hiramatsu * Return 0 if @fp is registered successfully, -errno if not. 187cad9931fSMasami Hiramatsu */ 188cad9931fSMasami Hiramatsu int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter) 189cad9931fSMasami Hiramatsu { 1905b0ab789SMasami Hiramatsu struct ftrace_hash *hash; 191cad9931fSMasami Hiramatsu unsigned char *str; 192cad9931fSMasami Hiramatsu int ret, len; 193cad9931fSMasami Hiramatsu 194cad9931fSMasami Hiramatsu if (!fp || !filter) 195cad9931fSMasami Hiramatsu return -EINVAL; 196cad9931fSMasami Hiramatsu 197cad9931fSMasami Hiramatsu fprobe_init(fp); 198cad9931fSMasami Hiramatsu 199cad9931fSMasami Hiramatsu len = strlen(filter); 200cad9931fSMasami Hiramatsu str = kstrdup(filter, GFP_KERNEL); 201cad9931fSMasami Hiramatsu ret = ftrace_set_filter(&fp->ops, str, len, 0); 202cad9931fSMasami Hiramatsu kfree(str); 203cad9931fSMasami Hiramatsu if (ret) 204cad9931fSMasami Hiramatsu return ret; 205cad9931fSMasami Hiramatsu 206cad9931fSMasami Hiramatsu if (notfilter) { 207cad9931fSMasami Hiramatsu len = strlen(notfilter); 208cad9931fSMasami Hiramatsu str = kstrdup(notfilter, GFP_KERNEL); 209cad9931fSMasami Hiramatsu ret = ftrace_set_notrace(&fp->ops, str, len, 0); 210cad9931fSMasami Hiramatsu kfree(str); 211cad9931fSMasami Hiramatsu if (ret) 212cad9931fSMasami Hiramatsu goto out; 213cad9931fSMasami Hiramatsu } 214cad9931fSMasami Hiramatsu 2155b0ab789SMasami Hiramatsu /* TODO: 2165b0ab789SMasami Hiramatsu * correctly calculate the total number of filtered symbols 2175b0ab789SMasami Hiramatsu * from both filter and notfilter. 2185b0ab789SMasami Hiramatsu */ 219261608f3SMasami Hiramatsu hash = rcu_access_pointer(fp->ops.local_hash.filter_hash); 2205b0ab789SMasami Hiramatsu if (WARN_ON_ONCE(!hash)) 2215b0ab789SMasami Hiramatsu goto out; 2225b0ab789SMasami Hiramatsu 2235b0ab789SMasami Hiramatsu ret = fprobe_init_rethook(fp, (int)hash->count); 2245b0ab789SMasami Hiramatsu if (!ret) 225cad9931fSMasami Hiramatsu ret = register_ftrace_function(&fp->ops); 2265b0ab789SMasami Hiramatsu 227cad9931fSMasami Hiramatsu out: 228cad9931fSMasami Hiramatsu if (ret) 2295b0ab789SMasami Hiramatsu fprobe_fail_cleanup(fp); 230cad9931fSMasami Hiramatsu return ret; 231cad9931fSMasami Hiramatsu } 232cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(register_fprobe); 233cad9931fSMasami Hiramatsu 234cad9931fSMasami Hiramatsu /** 235cad9931fSMasami Hiramatsu * register_fprobe_ips() - Register fprobe to ftrace by address. 236cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be registered. 237cad9931fSMasami Hiramatsu * @addrs: An array of target ftrace location addresses. 238cad9931fSMasami Hiramatsu * @num: The number of entries of @addrs. 239cad9931fSMasami Hiramatsu * 240cad9931fSMasami Hiramatsu * Register @fp to ftrace for enabling the probe on the address given by @addrs. 241cad9931fSMasami Hiramatsu * The @addrs must be the addresses of ftrace location address, which may be 242cad9931fSMasami Hiramatsu * the symbol address + arch-dependent offset. 243cad9931fSMasami Hiramatsu * If you unsure what this mean, please use other registration functions. 244cad9931fSMasami Hiramatsu * 245cad9931fSMasami Hiramatsu * Return 0 if @fp is registered successfully, -errno if not. 246cad9931fSMasami Hiramatsu */ 247cad9931fSMasami Hiramatsu int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num) 248cad9931fSMasami Hiramatsu { 249cad9931fSMasami Hiramatsu int ret; 250cad9931fSMasami Hiramatsu 251cad9931fSMasami Hiramatsu if (!fp || !addrs || num <= 0) 252cad9931fSMasami Hiramatsu return -EINVAL; 253cad9931fSMasami Hiramatsu 254cad9931fSMasami Hiramatsu fprobe_init(fp); 255cad9931fSMasami Hiramatsu 256cad9931fSMasami Hiramatsu ret = ftrace_set_filter_ips(&fp->ops, addrs, num, 0, 0); 2575b0ab789SMasami Hiramatsu if (ret) 2585b0ab789SMasami Hiramatsu return ret; 2595b0ab789SMasami Hiramatsu 2605b0ab789SMasami Hiramatsu ret = fprobe_init_rethook(fp, num); 261cad9931fSMasami Hiramatsu if (!ret) 262cad9931fSMasami Hiramatsu ret = register_ftrace_function(&fp->ops); 263cad9931fSMasami Hiramatsu 264cad9931fSMasami Hiramatsu if (ret) 2655b0ab789SMasami Hiramatsu fprobe_fail_cleanup(fp); 266cad9931fSMasami Hiramatsu return ret; 267cad9931fSMasami Hiramatsu } 268cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(register_fprobe_ips); 269cad9931fSMasami Hiramatsu 270cad9931fSMasami Hiramatsu /** 271cad9931fSMasami Hiramatsu * register_fprobe_syms() - Register fprobe to ftrace by symbols. 272cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be registered. 273cad9931fSMasami Hiramatsu * @syms: An array of target symbols. 274cad9931fSMasami Hiramatsu * @num: The number of entries of @syms. 275cad9931fSMasami Hiramatsu * 276cad9931fSMasami Hiramatsu * Register @fp to the symbols given by @syms array. This will be useful if 277cad9931fSMasami Hiramatsu * you are sure the symbols exist in the kernel. 278cad9931fSMasami Hiramatsu * 279cad9931fSMasami Hiramatsu * Return 0 if @fp is registered successfully, -errno if not. 280cad9931fSMasami Hiramatsu */ 281cad9931fSMasami Hiramatsu int register_fprobe_syms(struct fprobe *fp, const char **syms, int num) 282cad9931fSMasami Hiramatsu { 283cad9931fSMasami Hiramatsu unsigned long *addrs; 284cad9931fSMasami Hiramatsu int ret; 285cad9931fSMasami Hiramatsu 286cad9931fSMasami Hiramatsu if (!fp || !syms || num <= 0) 287cad9931fSMasami Hiramatsu return -EINVAL; 288cad9931fSMasami Hiramatsu 289cad9931fSMasami Hiramatsu addrs = get_ftrace_locations(syms, num); 290cad9931fSMasami Hiramatsu if (IS_ERR(addrs)) 291cad9931fSMasami Hiramatsu return PTR_ERR(addrs); 292cad9931fSMasami Hiramatsu 293cad9931fSMasami Hiramatsu ret = register_fprobe_ips(fp, addrs, num); 294cad9931fSMasami Hiramatsu 295cad9931fSMasami Hiramatsu kfree(addrs); 296cad9931fSMasami Hiramatsu 297cad9931fSMasami Hiramatsu return ret; 298cad9931fSMasami Hiramatsu } 299cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(register_fprobe_syms); 300cad9931fSMasami Hiramatsu 301cad9931fSMasami Hiramatsu /** 302cad9931fSMasami Hiramatsu * unregister_fprobe() - Unregister fprobe from ftrace 303cad9931fSMasami Hiramatsu * @fp: A fprobe data structure to be unregistered. 304cad9931fSMasami Hiramatsu * 305cad9931fSMasami Hiramatsu * Unregister fprobe (and remove ftrace hooks from the function entries). 306cad9931fSMasami Hiramatsu * 307cad9931fSMasami Hiramatsu * Return 0 if @fp is unregistered successfully, -errno if not. 308cad9931fSMasami Hiramatsu */ 309cad9931fSMasami Hiramatsu int unregister_fprobe(struct fprobe *fp) 310cad9931fSMasami Hiramatsu { 311cad9931fSMasami Hiramatsu int ret; 312cad9931fSMasami Hiramatsu 31361b304b7SMasami Hiramatsu (Google) if (!fp || (fp->ops.saved_func != fprobe_handler && 31461b304b7SMasami Hiramatsu (Google) fp->ops.saved_func != fprobe_kprobe_handler)) 315cad9931fSMasami Hiramatsu return -EINVAL; 316cad9931fSMasami Hiramatsu 3175b0ab789SMasami Hiramatsu /* 3185b0ab789SMasami Hiramatsu * rethook_free() starts disabling the rethook, but the rethook handlers 3195b0ab789SMasami Hiramatsu * may be running on other processors at this point. To make sure that all 3205b0ab789SMasami Hiramatsu * current running handlers are finished, call unregister_ftrace_function() 3215b0ab789SMasami Hiramatsu * after this. 3225b0ab789SMasami Hiramatsu */ 3235b0ab789SMasami Hiramatsu if (fp->rethook) 3245b0ab789SMasami Hiramatsu rethook_free(fp->rethook); 325cad9931fSMasami Hiramatsu 3265b0ab789SMasami Hiramatsu ret = unregister_ftrace_function(&fp->ops); 3275b0ab789SMasami Hiramatsu if (ret < 0) 3285b0ab789SMasami Hiramatsu return ret; 3295b0ab789SMasami Hiramatsu 330cad9931fSMasami Hiramatsu ftrace_free_filter(&fp->ops); 331cad9931fSMasami Hiramatsu 332cad9931fSMasami Hiramatsu return ret; 333cad9931fSMasami Hiramatsu } 334cad9931fSMasami Hiramatsu EXPORT_SYMBOL_GPL(unregister_fprobe); 335