Steven Rostedt (VMware) | bcea3f9 | 2018-08-16 11:23:53 -0400 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 2 | /* |
Masami Hiramatsu | 77b44d1 | 2009-11-03 19:12:47 -0500 | [diff] [blame] | 3 | * Kprobes-based tracing events |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 4 | * |
| 5 | * Created by Masami Hiramatsu <mhiramat@redhat.com> |
| 6 | * |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 7 | */ |
Masami Hiramatsu | 7257634 | 2017-02-07 20:21:28 +0900 | [diff] [blame] | 8 | #define pr_fmt(fmt) "trace_kprobe: " fmt |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 9 | |
| 10 | #include <linux/module.h> |
| 11 | #include <linux/uaccess.h> |
Ingo Molnar | b2d0910 | 2017-02-04 01:27:20 +0100 | [diff] [blame] | 12 | #include <linux/rculist.h> |
Masami Hiramatsu | 540adea | 2018-01-13 02:55:03 +0900 | [diff] [blame] | 13 | #include <linux/error-injection.h> |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 14 | |
Francis Deslauriers | d899926 | 2018-07-30 19:20:42 +0900 | [diff] [blame] | 15 | #include "trace_kprobe_selftest.h" |
Srikar Dronamraju | 8ab83f5 | 2012-04-09 14:41:44 +0530 | [diff] [blame] | 16 | #include "trace_probe.h" |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 17 | #include "trace_probe_tmpl.h" |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 18 | |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 19 | #define KPROBE_EVENT_SYSTEM "kprobes" |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 20 | #define KRETPROBE_MAXACTIVE_MAX 4096 |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 21 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 22 | /** |
Masami Hiramatsu | 77b44d1 | 2009-11-03 19:12:47 -0500 | [diff] [blame] | 23 | * Kprobe event core functions |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 24 | */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 25 | struct trace_kprobe { |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 26 | struct list_head list; |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 27 | struct kretprobe rp; /* Use rp.kp for kprobe use */ |
Martin KaFai Lau | a7636d9 | 2016-02-03 12:28:28 -0800 | [diff] [blame] | 28 | unsigned long __percpu *nhit; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 29 | const char *symbol; /* symbol name */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 30 | struct trace_probe tp; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 31 | }; |
| 32 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 33 | #define SIZEOF_TRACE_KPROBE(n) \ |
| 34 | (offsetof(struct trace_kprobe, tp.args) + \ |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 35 | (sizeof(struct probe_arg) * (n))) |
Masami Hiramatsu | a82378d | 2009-08-13 16:35:18 -0400 | [diff] [blame] | 36 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 37 | static nokprobe_inline bool trace_kprobe_is_return(struct trace_kprobe *tk) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 38 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 39 | return tk->rp.handler != NULL; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 40 | } |
| 41 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 42 | static nokprobe_inline const char *trace_kprobe_symbol(struct trace_kprobe *tk) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 43 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 44 | return tk->symbol ? tk->symbol : "unknown"; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 45 | } |
| 46 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 47 | static nokprobe_inline unsigned long trace_kprobe_offset(struct trace_kprobe *tk) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 48 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 49 | return tk->rp.kp.offset; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 50 | } |
| 51 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 52 | static nokprobe_inline bool trace_kprobe_has_gone(struct trace_kprobe *tk) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 53 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 54 | return !!(kprobe_gone(&tk->rp.kp)); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 55 | } |
| 56 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 57 | static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk, |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 58 | struct module *mod) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 59 | { |
| 60 | int len = strlen(mod->name); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 61 | const char *name = trace_kprobe_symbol(tk); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 62 | return strncmp(mod->name, name, len) == 0 && name[len] == ':'; |
| 63 | } |
| 64 | |
Masami Hiramatsu | 59158ec | 2018-08-29 01:18:15 +0900 | [diff] [blame] | 65 | static nokprobe_inline bool trace_kprobe_module_exist(struct trace_kprobe *tk) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 66 | { |
Masami Hiramatsu | 59158ec | 2018-08-29 01:18:15 +0900 | [diff] [blame] | 67 | char *p; |
| 68 | bool ret; |
| 69 | |
| 70 | if (!tk->symbol) |
| 71 | return false; |
| 72 | p = strchr(tk->symbol, ':'); |
| 73 | if (!p) |
| 74 | return true; |
| 75 | *p = '\0'; |
| 76 | mutex_lock(&module_mutex); |
| 77 | ret = !!find_module(tk->symbol); |
| 78 | mutex_unlock(&module_mutex); |
| 79 | *p = ':'; |
| 80 | |
| 81 | return ret; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 82 | } |
| 83 | |
Marcin Nowakowski | f18f97a | 2016-12-09 15:19:37 +0100 | [diff] [blame] | 84 | static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk) |
| 85 | { |
| 86 | unsigned long nhit = 0; |
| 87 | int cpu; |
| 88 | |
| 89 | for_each_possible_cpu(cpu) |
| 90 | nhit += *per_cpu_ptr(tk->nhit, cpu); |
| 91 | |
| 92 | return nhit; |
| 93 | } |
| 94 | |
Masami Hiramatsu | 6bc6c77 | 2018-08-02 16:50:48 +0900 | [diff] [blame] | 95 | /* Return 0 if it fails to find the symbol address */ |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 96 | static nokprobe_inline |
| 97 | unsigned long trace_kprobe_address(struct trace_kprobe *tk) |
| 98 | { |
| 99 | unsigned long addr; |
| 100 | |
| 101 | if (tk->symbol) { |
| 102 | addr = (unsigned long) |
| 103 | kallsyms_lookup_name(trace_kprobe_symbol(tk)); |
Masami Hiramatsu | 6bc6c77 | 2018-08-02 16:50:48 +0900 | [diff] [blame] | 104 | if (addr) |
| 105 | addr += tk->rp.kp.offset; |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 106 | } else { |
| 107 | addr = (unsigned long)tk->rp.kp.addr; |
| 108 | } |
| 109 | return addr; |
| 110 | } |
| 111 | |
Masami Hiramatsu | b4da334 | 2018-01-13 02:54:04 +0900 | [diff] [blame] | 112 | bool trace_kprobe_on_func_entry(struct trace_event_call *call) |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 113 | { |
| 114 | struct trace_kprobe *tk = (struct trace_kprobe *)call->data; |
Masami Hiramatsu | b4da334 | 2018-01-13 02:54:04 +0900 | [diff] [blame] | 115 | |
| 116 | return kprobe_on_func_entry(tk->rp.kp.addr, |
| 117 | tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name, |
| 118 | tk->rp.kp.addr ? 0 : tk->rp.kp.offset); |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 119 | } |
| 120 | |
Masami Hiramatsu | b4da334 | 2018-01-13 02:54:04 +0900 | [diff] [blame] | 121 | bool trace_kprobe_error_injectable(struct trace_event_call *call) |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 122 | { |
| 123 | struct trace_kprobe *tk = (struct trace_kprobe *)call->data; |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 124 | |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 125 | return within_error_injection_list(trace_kprobe_address(tk)); |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 126 | } |
| 127 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 128 | static int register_kprobe_event(struct trace_kprobe *tk); |
| 129 | static int unregister_kprobe_event(struct trace_kprobe *tk); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 130 | |
| 131 | static DEFINE_MUTEX(probe_lock); |
| 132 | static LIST_HEAD(probe_list); |
| 133 | |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 134 | static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); |
| 135 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, |
| 136 | struct pt_regs *regs); |
| 137 | |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 138 | /* |
| 139 | * Allocate new trace_probe and initialize it (including kprobes). |
| 140 | */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 141 | static struct trace_kprobe *alloc_trace_kprobe(const char *group, |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 142 | const char *event, |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 143 | void *addr, |
| 144 | const char *symbol, |
| 145 | unsigned long offs, |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 146 | int maxactive, |
Srikar Dronamraju | 3a6b766 | 2012-04-09 14:41:33 +0530 | [diff] [blame] | 147 | int nargs, bool is_return) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 148 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 149 | struct trace_kprobe *tk; |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 150 | int ret = -ENOMEM; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 151 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 152 | tk = kzalloc(SIZEOF_TRACE_KPROBE(nargs), GFP_KERNEL); |
| 153 | if (!tk) |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 154 | return ERR_PTR(ret); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 155 | |
Martin KaFai Lau | a7636d9 | 2016-02-03 12:28:28 -0800 | [diff] [blame] | 156 | tk->nhit = alloc_percpu(unsigned long); |
| 157 | if (!tk->nhit) |
| 158 | goto error; |
| 159 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 160 | if (symbol) { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 161 | tk->symbol = kstrdup(symbol, GFP_KERNEL); |
| 162 | if (!tk->symbol) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 163 | goto error; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 164 | tk->rp.kp.symbol_name = tk->symbol; |
| 165 | tk->rp.kp.offset = offs; |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 166 | } else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 167 | tk->rp.kp.addr = addr; |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 168 | |
| 169 | if (is_return) |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 170 | tk->rp.handler = kretprobe_dispatcher; |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 171 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 172 | tk->rp.kp.pre_handler = kprobe_dispatcher; |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 173 | |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 174 | tk->rp.maxactive = maxactive; |
| 175 | |
Masami Hiramatsu | da34634f | 2010-08-27 20:39:12 +0900 | [diff] [blame] | 176 | if (!event || !is_good_name(event)) { |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 177 | ret = -EINVAL; |
Masami Hiramatsu | 4263565 | 2009-08-13 16:35:26 -0400 | [diff] [blame] | 178 | goto error; |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 179 | } |
| 180 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 181 | tk->tp.call.class = &tk->tp.class; |
| 182 | tk->tp.call.name = kstrdup(event, GFP_KERNEL); |
| 183 | if (!tk->tp.call.name) |
Masami Hiramatsu | 4263565 | 2009-08-13 16:35:26 -0400 | [diff] [blame] | 184 | goto error; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 185 | |
Masami Hiramatsu | da34634f | 2010-08-27 20:39:12 +0900 | [diff] [blame] | 186 | if (!group || !is_good_name(group)) { |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 187 | ret = -EINVAL; |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 188 | goto error; |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 189 | } |
| 190 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 191 | tk->tp.class.system = kstrdup(group, GFP_KERNEL); |
| 192 | if (!tk->tp.class.system) |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 193 | goto error; |
| 194 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 195 | INIT_LIST_HEAD(&tk->list); |
| 196 | INIT_LIST_HEAD(&tk->tp.files); |
| 197 | return tk; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 198 | error: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 199 | kfree(tk->tp.call.name); |
| 200 | kfree(tk->symbol); |
Martin KaFai Lau | a7636d9 | 2016-02-03 12:28:28 -0800 | [diff] [blame] | 201 | free_percpu(tk->nhit); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 202 | kfree(tk); |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 203 | return ERR_PTR(ret); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 204 | } |
| 205 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 206 | static void free_trace_kprobe(struct trace_kprobe *tk) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 207 | { |
| 208 | int i; |
| 209 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 210 | for (i = 0; i < tk->tp.nr_args; i++) |
| 211 | traceprobe_free_probe_arg(&tk->tp.args[i]); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 212 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 213 | kfree(tk->tp.call.class->system); |
| 214 | kfree(tk->tp.call.name); |
| 215 | kfree(tk->symbol); |
Martin KaFai Lau | a7636d9 | 2016-02-03 12:28:28 -0800 | [diff] [blame] | 216 | free_percpu(tk->nhit); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 217 | kfree(tk); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 218 | } |
| 219 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 220 | static struct trace_kprobe *find_trace_kprobe(const char *event, |
| 221 | const char *group) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 222 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 223 | struct trace_kprobe *tk; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 224 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 225 | list_for_each_entry(tk, &probe_list, list) |
Steven Rostedt (Red Hat) | 687fcc4 | 2015-05-13 14:20:14 -0400 | [diff] [blame] | 226 | if (strcmp(trace_event_name(&tk->tp.call), event) == 0 && |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 227 | strcmp(tk->tp.call.class->system, group) == 0) |
| 228 | return tk; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 229 | return NULL; |
| 230 | } |
| 231 | |
Steven Rostedt (VMware) | 87107a2 | 2018-07-26 12:07:32 -0400 | [diff] [blame] | 232 | static inline int __enable_trace_kprobe(struct trace_kprobe *tk) |
| 233 | { |
| 234 | int ret = 0; |
| 235 | |
| 236 | if (trace_probe_is_registered(&tk->tp) && !trace_kprobe_has_gone(tk)) { |
| 237 | if (trace_kprobe_is_return(tk)) |
| 238 | ret = enable_kretprobe(&tk->rp); |
| 239 | else |
| 240 | ret = enable_kprobe(&tk->rp.kp); |
| 241 | } |
| 242 | |
| 243 | return ret; |
| 244 | } |
| 245 | |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 246 | /* |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 247 | * Enable trace_probe |
| 248 | * if the file is NULL, enable "perf" handler, or enable "trace" handler. |
| 249 | */ |
| 250 | static int |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 251 | enable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 252 | { |
Steven Rostedt (VMware) | 87107a2 | 2018-07-26 12:07:32 -0400 | [diff] [blame] | 253 | struct event_file_link *link; |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 254 | int ret = 0; |
| 255 | |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 256 | if (file) { |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 257 | link = kmalloc(sizeof(*link), GFP_KERNEL); |
| 258 | if (!link) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 259 | ret = -ENOMEM; |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 260 | goto out; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 261 | } |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 262 | |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 263 | link->file = file; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 264 | list_add_tail_rcu(&link->list, &tk->tp.files); |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 265 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 266 | tk->tp.flags |= TP_FLAG_TRACE; |
Steven Rostedt (VMware) | 87107a2 | 2018-07-26 12:07:32 -0400 | [diff] [blame] | 267 | ret = __enable_trace_kprobe(tk); |
| 268 | if (ret) { |
| 269 | list_del_rcu(&link->list); |
Artem Savkov | 57ea2a3 | 2018-07-25 16:20:38 +0200 | [diff] [blame] | 270 | kfree(link); |
| 271 | tk->tp.flags &= ~TP_FLAG_TRACE; |
Artem Savkov | 57ea2a3 | 2018-07-25 16:20:38 +0200 | [diff] [blame] | 272 | } |
Steven Rostedt (VMware) | 87107a2 | 2018-07-26 12:07:32 -0400 | [diff] [blame] | 273 | |
| 274 | } else { |
| 275 | tk->tp.flags |= TP_FLAG_PROFILE; |
| 276 | ret = __enable_trace_kprobe(tk); |
| 277 | if (ret) |
| 278 | tk->tp.flags &= ~TP_FLAG_PROFILE; |
Artem Savkov | 57ea2a3 | 2018-07-25 16:20:38 +0200 | [diff] [blame] | 279 | } |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 280 | out: |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 281 | return ret; |
| 282 | } |
| 283 | |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 284 | /* |
| 285 | * Disable trace_probe |
| 286 | * if the file is NULL, disable "perf" handler, or disable "trace" handler. |
| 287 | */ |
| 288 | static int |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 289 | disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 290 | { |
Masami Hiramatsu | a232e27 | 2013-07-09 18:35:26 +0900 | [diff] [blame] | 291 | struct event_file_link *link = NULL; |
| 292 | int wait = 0; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 293 | int ret = 0; |
| 294 | |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 295 | if (file) { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 296 | link = find_event_file_link(&tk->tp, file); |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 297 | if (!link) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 298 | ret = -EINVAL; |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 299 | goto out; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 300 | } |
| 301 | |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 302 | list_del_rcu(&link->list); |
Masami Hiramatsu | a232e27 | 2013-07-09 18:35:26 +0900 | [diff] [blame] | 303 | wait = 1; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 304 | if (!list_empty(&tk->tp.files)) |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 305 | goto out; |
| 306 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 307 | tk->tp.flags &= ~TP_FLAG_TRACE; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 308 | } else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 309 | tk->tp.flags &= ~TP_FLAG_PROFILE; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 310 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 311 | if (!trace_probe_is_enabled(&tk->tp) && trace_probe_is_registered(&tk->tp)) { |
| 312 | if (trace_kprobe_is_return(tk)) |
| 313 | disable_kretprobe(&tk->rp); |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 314 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 315 | disable_kprobe(&tk->rp.kp); |
Masami Hiramatsu | a232e27 | 2013-07-09 18:35:26 +0900 | [diff] [blame] | 316 | wait = 1; |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 317 | } |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 318 | |
| 319 | /* |
| 320 | * if tk is not added to any list, it must be a local trace_kprobe |
| 321 | * created with perf_event_open. We don't need to wait for these |
| 322 | * trace_kprobes |
| 323 | */ |
| 324 | if (list_empty(&tk->list)) |
| 325 | wait = 0; |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 326 | out: |
Masami Hiramatsu | a232e27 | 2013-07-09 18:35:26 +0900 | [diff] [blame] | 327 | if (wait) { |
| 328 | /* |
| 329 | * Synchronize with kprobe_trace_func/kretprobe_trace_func |
| 330 | * to ensure disabled (all running handlers are finished). |
| 331 | * This is not only for kfree(), but also the caller, |
| 332 | * trace_remove_event_call() supposes it for releasing |
| 333 | * event_call related objects, which will be accessed in |
| 334 | * the kprobe_trace_func/kretprobe_trace_func. |
| 335 | */ |
| 336 | synchronize_sched(); |
| 337 | kfree(link); /* Ignored if link == NULL */ |
| 338 | } |
| 339 | |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 340 | return ret; |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 341 | } |
| 342 | |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 343 | #if defined(CONFIG_KPROBES_ON_FTRACE) && \ |
| 344 | !defined(CONFIG_KPROBE_EVENTS_ON_NOTRACE) |
| 345 | static bool within_notrace_func(struct trace_kprobe *tk) |
| 346 | { |
| 347 | unsigned long offset, size, addr; |
| 348 | |
| 349 | addr = trace_kprobe_address(tk); |
Masami Hiramatsu | 6bc6c77 | 2018-08-02 16:50:48 +0900 | [diff] [blame] | 350 | if (!addr || !kallsyms_lookup_size_offset(addr, &size, &offset)) |
| 351 | return false; |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 352 | |
Masami Hiramatsu | 9161a86 | 2018-08-21 22:04:57 +0900 | [diff] [blame] | 353 | /* Get the entry address of the target function */ |
| 354 | addr -= offset; |
| 355 | |
| 356 | /* |
| 357 | * Since ftrace_location_range() does inclusive range check, we need |
| 358 | * to subtract 1 byte from the end address. |
| 359 | */ |
| 360 | return !ftrace_location_range(addr, addr + size - 1); |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 361 | } |
| 362 | #else |
| 363 | #define within_notrace_func(tk) (false) |
| 364 | #endif |
| 365 | |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 366 | /* Internal register function - just handle k*probes and flags */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 367 | static int __register_trace_kprobe(struct trace_kprobe *tk) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 368 | { |
Masami Hiramatsu | a668281 | 2018-08-29 01:18:43 +0900 | [diff] [blame] | 369 | int i, ret; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 370 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 371 | if (trace_probe_is_registered(&tk->tp)) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 372 | return -EINVAL; |
| 373 | |
Masami Hiramatsu | 45408c4 | 2018-07-30 19:20:14 +0900 | [diff] [blame] | 374 | if (within_notrace_func(tk)) { |
| 375 | pr_warn("Could not probe notrace function %s\n", |
| 376 | trace_kprobe_symbol(tk)); |
| 377 | return -EINVAL; |
| 378 | } |
| 379 | |
Masami Hiramatsu | a668281 | 2018-08-29 01:18:43 +0900 | [diff] [blame] | 380 | for (i = 0; i < tk->tp.nr_args; i++) { |
| 381 | ret = traceprobe_update_arg(&tk->tp.args[i]); |
| 382 | if (ret) |
| 383 | return ret; |
| 384 | } |
| 385 | |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 386 | /* Set/clear disabled flag according to tp->flag */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 387 | if (trace_probe_is_enabled(&tk->tp)) |
| 388 | tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 389 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 390 | tk->rp.kp.flags |= KPROBE_FLAG_DISABLED; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 391 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 392 | if (trace_kprobe_is_return(tk)) |
| 393 | ret = register_kretprobe(&tk->rp); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 394 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 395 | ret = register_kprobe(&tk->rp.kp); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 396 | |
Masami Hiramatsu | 59158ec | 2018-08-29 01:18:15 +0900 | [diff] [blame] | 397 | if (ret == 0) { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 398 | tk->tp.flags |= TP_FLAG_REGISTERED; |
Masami Hiramatsu | 59158ec | 2018-08-29 01:18:15 +0900 | [diff] [blame] | 399 | } else if (ret == -EILSEQ) { |
| 400 | pr_warn("Probing address(0x%p) is not an instruction boundary.\n", |
| 401 | tk->rp.kp.addr); |
| 402 | ret = -EINVAL; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 403 | } |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 404 | return ret; |
| 405 | } |
| 406 | |
| 407 | /* Internal unregister function - just handle k*probes and flags */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 408 | static void __unregister_trace_kprobe(struct trace_kprobe *tk) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 409 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 410 | if (trace_probe_is_registered(&tk->tp)) { |
| 411 | if (trace_kprobe_is_return(tk)) |
| 412 | unregister_kretprobe(&tk->rp); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 413 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 414 | unregister_kprobe(&tk->rp.kp); |
| 415 | tk->tp.flags &= ~TP_FLAG_REGISTERED; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 416 | /* Cleanup kprobe for reuse */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 417 | if (tk->rp.kp.symbol_name) |
| 418 | tk->rp.kp.addr = NULL; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 419 | } |
| 420 | } |
| 421 | |
Masami Hiramatsu | 2d5e067 | 2009-09-14 16:48:56 -0400 | [diff] [blame] | 422 | /* Unregister a trace_probe and probe_event: call with locking probe_lock */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 423 | static int unregister_trace_kprobe(struct trace_kprobe *tk) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 424 | { |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 425 | /* Enabled event can not be unregistered */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 426 | if (trace_probe_is_enabled(&tk->tp)) |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 427 | return -EBUSY; |
| 428 | |
Steven Rostedt (Red Hat) | 40c3259 | 2013-07-03 23:33:50 -0400 | [diff] [blame] | 429 | /* Will fail if probe is being used by ftrace or perf */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 430 | if (unregister_kprobe_event(tk)) |
Steven Rostedt (Red Hat) | 40c3259 | 2013-07-03 23:33:50 -0400 | [diff] [blame] | 431 | return -EBUSY; |
| 432 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 433 | __unregister_trace_kprobe(tk); |
| 434 | list_del(&tk->list); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 435 | |
| 436 | return 0; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | /* Register a trace_probe and probe_event */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 440 | static int register_trace_kprobe(struct trace_kprobe *tk) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 441 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 442 | struct trace_kprobe *old_tk; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 443 | int ret; |
| 444 | |
| 445 | mutex_lock(&probe_lock); |
| 446 | |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 447 | /* Delete old (same name) event if exist */ |
Steven Rostedt (Red Hat) | 687fcc4 | 2015-05-13 14:20:14 -0400 | [diff] [blame] | 448 | old_tk = find_trace_kprobe(trace_event_name(&tk->tp.call), |
Mathieu Desnoyers | de7b297 | 2014-04-08 17:26:21 -0400 | [diff] [blame] | 449 | tk->tp.call.class->system); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 450 | if (old_tk) { |
| 451 | ret = unregister_trace_kprobe(old_tk); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 452 | if (ret < 0) |
| 453 | goto end; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 454 | free_trace_kprobe(old_tk); |
Masami Hiramatsu | 2d5e067 | 2009-09-14 16:48:56 -0400 | [diff] [blame] | 455 | } |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 456 | |
| 457 | /* Register new event */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 458 | ret = register_kprobe_event(tk); |
Masami Hiramatsu | 2d5e067 | 2009-09-14 16:48:56 -0400 | [diff] [blame] | 459 | if (ret) { |
Joe Perches | a395d6a | 2016-03-22 14:28:09 -0700 | [diff] [blame] | 460 | pr_warn("Failed to register probe event(%d)\n", ret); |
Masami Hiramatsu | 2d5e067 | 2009-09-14 16:48:56 -0400 | [diff] [blame] | 461 | goto end; |
| 462 | } |
| 463 | |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 464 | /* Register k*probe */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 465 | ret = __register_trace_kprobe(tk); |
Masami Hiramatsu | 59158ec | 2018-08-29 01:18:15 +0900 | [diff] [blame] | 466 | if (ret == -ENOENT && !trace_kprobe_module_exist(tk)) { |
| 467 | pr_warn("This probe might be able to register after target module is loaded. Continue.\n"); |
| 468 | ret = 0; |
| 469 | } |
| 470 | |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 471 | if (ret < 0) |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 472 | unregister_kprobe_event(tk); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 473 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 474 | list_add_tail(&tk->list, &probe_list); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 475 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 476 | end: |
| 477 | mutex_unlock(&probe_lock); |
| 478 | return ret; |
| 479 | } |
| 480 | |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 481 | /* Module notifier call back, checking event on the module */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 482 | static int trace_kprobe_module_callback(struct notifier_block *nb, |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 483 | unsigned long val, void *data) |
| 484 | { |
| 485 | struct module *mod = data; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 486 | struct trace_kprobe *tk; |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 487 | int ret; |
| 488 | |
| 489 | if (val != MODULE_STATE_COMING) |
| 490 | return NOTIFY_DONE; |
| 491 | |
| 492 | /* Update probes on coming module */ |
| 493 | mutex_lock(&probe_lock); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 494 | list_for_each_entry(tk, &probe_list, list) { |
| 495 | if (trace_kprobe_within_module(tk, mod)) { |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 496 | /* Don't need to check busy - this should have gone. */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 497 | __unregister_trace_kprobe(tk); |
| 498 | ret = __register_trace_kprobe(tk); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 499 | if (ret) |
Joe Perches | a395d6a | 2016-03-22 14:28:09 -0700 | [diff] [blame] | 500 | pr_warn("Failed to re-register probe %s on %s: %d\n", |
| 501 | trace_event_name(&tk->tp.call), |
| 502 | mod->name, ret); |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 503 | } |
| 504 | } |
| 505 | mutex_unlock(&probe_lock); |
| 506 | |
| 507 | return NOTIFY_DONE; |
| 508 | } |
| 509 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 510 | static struct notifier_block trace_kprobe_module_nb = { |
| 511 | .notifier_call = trace_kprobe_module_callback, |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 512 | .priority = 1 /* Invoked after kprobe module callback */ |
| 513 | }; |
| 514 | |
Naveen N. Rao | fca18a4 | 2017-07-08 00:27:30 +0530 | [diff] [blame] | 515 | /* Convert certain expected symbols into '_' when generating event names */ |
| 516 | static inline void sanitize_event_name(char *name) |
| 517 | { |
| 518 | while (*name++ != '\0') |
| 519 | if (*name == ':' || *name == '.') |
| 520 | *name = '_'; |
| 521 | } |
| 522 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 523 | static int create_trace_kprobe(int argc, char **argv) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 524 | { |
| 525 | /* |
| 526 | * Argument syntax: |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 527 | * - Add kprobe: |
| 528 | * p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS] |
| 529 | * - Add kretprobe: |
| 530 | * r[MAXACTIVE][:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS] |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 531 | * Fetch args: |
Masami Hiramatsu | 2e06ff6 | 2009-10-07 18:27:59 -0400 | [diff] [blame] | 532 | * $retval : fetch return value |
| 533 | * $stack : fetch stack address |
| 534 | * $stackN : fetch Nth of stack (N:0-) |
Omar Sandoval | 35abb67 | 2016-06-08 18:38:02 -0700 | [diff] [blame] | 535 | * $comm : fetch current task comm |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 536 | * @ADDR : fetch memory at ADDR (ADDR should be in kernel) |
| 537 | * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol) |
| 538 | * %REG : fetch register REG |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 539 | * Dereferencing memory fetch: |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 540 | * +|-offs(ARG) : fetch memory at ARG +|- offs address. |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 541 | * Alias name of args: |
| 542 | * NAME=FETCHARG : set NAME as alias of FETCHARG. |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 543 | * Type of args: |
| 544 | * FETCHARG:TYPE : use TYPE instead of unsigned long. |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 545 | */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 546 | struct trace_kprobe *tk; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 547 | int i, ret = 0; |
Srikar Dronamraju | 3a6b766 | 2012-04-09 14:41:33 +0530 | [diff] [blame] | 548 | bool is_return = false, is_delete = false; |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 549 | char *symbol = NULL, *event = NULL, *group = NULL; |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 550 | int maxactive = 0; |
Masami Hiramatsu | da34634f | 2010-08-27 20:39:12 +0900 | [diff] [blame] | 551 | char *arg; |
Masami Hiramatsu | c5d343b | 2018-03-17 21:38:10 +0900 | [diff] [blame] | 552 | long offset = 0; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 553 | void *addr = NULL; |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 554 | char buf[MAX_EVENT_NAME_LEN]; |
Masami Hiramatsu | a1303af | 2018-04-25 21:21:26 +0900 | [diff] [blame] | 555 | unsigned int flags = TPARG_FL_KERNEL; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 556 | |
Masami Hiramatsu | a7c312b | 2009-12-08 17:03:16 -0500 | [diff] [blame] | 557 | /* argc must be >= 1 */ |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 558 | if (argv[0][0] == 'p') |
Srikar Dronamraju | 3a6b766 | 2012-04-09 14:41:33 +0530 | [diff] [blame] | 559 | is_return = false; |
Masami Hiramatsu | a1303af | 2018-04-25 21:21:26 +0900 | [diff] [blame] | 560 | else if (argv[0][0] == 'r') { |
Srikar Dronamraju | 3a6b766 | 2012-04-09 14:41:33 +0530 | [diff] [blame] | 561 | is_return = true; |
Masami Hiramatsu | a1303af | 2018-04-25 21:21:26 +0900 | [diff] [blame] | 562 | flags |= TPARG_FL_RETURN; |
| 563 | } else if (argv[0][0] == '-') |
Srikar Dronamraju | 3a6b766 | 2012-04-09 14:41:33 +0530 | [diff] [blame] | 564 | is_delete = true; |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 565 | else { |
Masami Hiramatsu | a7c312b | 2009-12-08 17:03:16 -0500 | [diff] [blame] | 566 | pr_info("Probe definition must be started with 'p', 'r' or" |
| 567 | " '-'.\n"); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 568 | return -EINVAL; |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 569 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 570 | |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 571 | event = strchr(&argv[0][1], ':'); |
| 572 | if (event) { |
| 573 | event[0] = '\0'; |
| 574 | event++; |
| 575 | } |
| 576 | if (is_return && isdigit(argv[0][1])) { |
| 577 | ret = kstrtouint(&argv[0][1], 0, &maxactive); |
| 578 | if (ret) { |
| 579 | pr_info("Failed to parse maxactive.\n"); |
| 580 | return ret; |
| 581 | } |
| 582 | /* kretprobes instances are iterated over via a list. The |
| 583 | * maximum should stay reasonable. |
| 584 | */ |
| 585 | if (maxactive > KRETPROBE_MAXACTIVE_MAX) { |
| 586 | pr_info("Maxactive is too big (%d > %d).\n", |
| 587 | maxactive, KRETPROBE_MAXACTIVE_MAX); |
| 588 | return -E2BIG; |
| 589 | } |
| 590 | } |
| 591 | |
| 592 | if (event) { |
Steven Rostedt (VMware) | d6b183e | 2018-08-24 16:20:28 -0400 | [diff] [blame] | 593 | char *slash; |
| 594 | |
| 595 | slash = strchr(event, '/'); |
| 596 | if (slash) { |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 597 | group = event; |
Steven Rostedt (VMware) | d6b183e | 2018-08-24 16:20:28 -0400 | [diff] [blame] | 598 | event = slash + 1; |
| 599 | slash[0] = '\0'; |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 600 | if (strlen(group) == 0) { |
Wenji Huang | a5efd92 | 2010-02-24 15:40:23 +0800 | [diff] [blame] | 601 | pr_info("Group name is not specified\n"); |
Masami Hiramatsu | f52487e | 2009-09-10 19:53:53 -0400 | [diff] [blame] | 602 | return -EINVAL; |
| 603 | } |
| 604 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 605 | if (strlen(event) == 0) { |
Wenji Huang | a5efd92 | 2010-02-24 15:40:23 +0800 | [diff] [blame] | 606 | pr_info("Event name is not specified\n"); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 607 | return -EINVAL; |
| 608 | } |
| 609 | } |
Masami Hiramatsu | a7c312b | 2009-12-08 17:03:16 -0500 | [diff] [blame] | 610 | if (!group) |
| 611 | group = KPROBE_EVENT_SYSTEM; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 612 | |
Masami Hiramatsu | a7c312b | 2009-12-08 17:03:16 -0500 | [diff] [blame] | 613 | if (is_delete) { |
| 614 | if (!event) { |
| 615 | pr_info("Delete command needs an event name.\n"); |
| 616 | return -EINVAL; |
| 617 | } |
Srikar Dronamraju | 9da79ab | 2010-06-30 14:15:48 +0530 | [diff] [blame] | 618 | mutex_lock(&probe_lock); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 619 | tk = find_trace_kprobe(event, group); |
| 620 | if (!tk) { |
Srikar Dronamraju | 9da79ab | 2010-06-30 14:15:48 +0530 | [diff] [blame] | 621 | mutex_unlock(&probe_lock); |
Masami Hiramatsu | a7c312b | 2009-12-08 17:03:16 -0500 | [diff] [blame] | 622 | pr_info("Event %s/%s doesn't exist.\n", group, event); |
| 623 | return -ENOENT; |
| 624 | } |
| 625 | /* delete an event */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 626 | ret = unregister_trace_kprobe(tk); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 627 | if (ret == 0) |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 628 | free_trace_kprobe(tk); |
Srikar Dronamraju | 9da79ab | 2010-06-30 14:15:48 +0530 | [diff] [blame] | 629 | mutex_unlock(&probe_lock); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 630 | return ret; |
Masami Hiramatsu | a7c312b | 2009-12-08 17:03:16 -0500 | [diff] [blame] | 631 | } |
| 632 | |
| 633 | if (argc < 2) { |
| 634 | pr_info("Probe point is not specified.\n"); |
| 635 | return -EINVAL; |
| 636 | } |
Sabrina Dubroca | 9e52b32 | 2017-06-22 11:24:42 +0200 | [diff] [blame] | 637 | |
| 638 | /* try to parse an address. if that fails, try to read the |
| 639 | * input as a symbol. */ |
| 640 | if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) { |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 641 | /* a symbol specified */ |
| 642 | symbol = argv[1]; |
| 643 | /* TODO: support .init module functions */ |
Srikar Dronamraju | 8ab83f5 | 2012-04-09 14:41:44 +0530 | [diff] [blame] | 644 | ret = traceprobe_split_symbol_offset(symbol, &offset); |
Masami Hiramatsu | c5d343b | 2018-03-17 21:38:10 +0900 | [diff] [blame] | 645 | if (ret || offset < 0 || offset > UINT_MAX) { |
Sabrina Dubroca | 9e52b32 | 2017-06-22 11:24:42 +0200 | [diff] [blame] | 646 | pr_info("Failed to parse either an address or a symbol.\n"); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 647 | return ret; |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 648 | } |
Masami Hiramatsu | a1303af | 2018-04-25 21:21:26 +0900 | [diff] [blame] | 649 | if (kprobe_on_func_entry(NULL, symbol, offset)) |
| 650 | flags |= TPARG_FL_FENTRY; |
| 651 | if (offset && is_return && !(flags & TPARG_FL_FENTRY)) { |
Steven Rostedt (VMware) | d0e0257 | 2017-02-27 11:52:04 -0500 | [diff] [blame] | 652 | pr_info("Given offset is not valid for return probe.\n"); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 653 | return -EINVAL; |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 654 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 655 | } |
Masami Hiramatsu | a82378d | 2009-08-13 16:35:18 -0400 | [diff] [blame] | 656 | argc -= 2; argv += 2; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 657 | |
| 658 | /* setup a probe */ |
Masami Hiramatsu | 4263565 | 2009-08-13 16:35:26 -0400 | [diff] [blame] | 659 | if (!event) { |
| 660 | /* Make a new event name */ |
Masami Hiramatsu | 4263565 | 2009-08-13 16:35:26 -0400 | [diff] [blame] | 661 | if (symbol) |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 662 | snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_%ld", |
Masami Hiramatsu | 4263565 | 2009-08-13 16:35:26 -0400 | [diff] [blame] | 663 | is_return ? 'r' : 'p', symbol, offset); |
| 664 | else |
Masami Hiramatsu | 6f3cf44 | 2009-12-16 17:24:08 -0500 | [diff] [blame] | 665 | snprintf(buf, MAX_EVENT_NAME_LEN, "%c_0x%p", |
Masami Hiramatsu | 4263565 | 2009-08-13 16:35:26 -0400 | [diff] [blame] | 666 | is_return ? 'r' : 'p', addr); |
Naveen N. Rao | fca18a4 | 2017-07-08 00:27:30 +0530 | [diff] [blame] | 667 | sanitize_event_name(buf); |
Masami Hiramatsu | 4a846b4 | 2009-09-11 05:31:21 +0200 | [diff] [blame] | 668 | event = buf; |
| 669 | } |
Alban Crequy | 696ced4 | 2017-04-03 12:36:22 +0200 | [diff] [blame] | 670 | tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive, |
| 671 | argc, is_return); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 672 | if (IS_ERR(tk)) { |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 673 | pr_info("Failed to allocate trace_probe.(%d)\n", |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 674 | (int)PTR_ERR(tk)); |
| 675 | return PTR_ERR(tk); |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 676 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 677 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 678 | /* parse arguments */ |
Masami Hiramatsu | a82378d | 2009-08-13 16:35:18 -0400 | [diff] [blame] | 679 | ret = 0; |
| 680 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 681 | struct probe_arg *parg = &tk->tp.args[i]; |
| 682 | |
Masami Hiramatsu | 61a5273 | 2010-08-27 20:38:46 +0900 | [diff] [blame] | 683 | /* Increment count for freeing args in error case */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 684 | tk->tp.nr_args++; |
Masami Hiramatsu | 61a5273 | 2010-08-27 20:38:46 +0900 | [diff] [blame] | 685 | |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 686 | /* Parse argument name */ |
| 687 | arg = strchr(argv[i], '='); |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 688 | if (arg) { |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 689 | *arg++ = '\0'; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 690 | parg->name = kstrdup(argv[i], GFP_KERNEL); |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 691 | } else { |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 692 | arg = argv[i]; |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 693 | /* If argument name is omitted, set "argN" */ |
| 694 | snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 695 | parg->name = kstrdup(buf, GFP_KERNEL); |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 696 | } |
Masami Hiramatsu | a703d94 | 2009-10-07 18:28:07 -0400 | [diff] [blame] | 697 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 698 | if (!parg->name) { |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 699 | pr_info("Failed to allocate argument[%d] name.\n", i); |
Masami Hiramatsu | ba8665d | 2009-11-30 19:19:20 -0500 | [diff] [blame] | 700 | ret = -ENOMEM; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 701 | goto error; |
| 702 | } |
Masami Hiramatsu | da34634f | 2010-08-27 20:39:12 +0900 | [diff] [blame] | 703 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 704 | if (!is_good_name(parg->name)) { |
Masami Hiramatsu | da34634f | 2010-08-27 20:39:12 +0900 | [diff] [blame] | 705 | pr_info("Invalid argument[%d] name: %s\n", |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 706 | i, parg->name); |
Masami Hiramatsu | da34634f | 2010-08-27 20:39:12 +0900 | [diff] [blame] | 707 | ret = -EINVAL; |
| 708 | goto error; |
| 709 | } |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 710 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 711 | if (traceprobe_conflict_field_name(parg->name, |
| 712 | tk->tp.args, i)) { |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 713 | pr_info("Argument[%d] name '%s' conflicts with " |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 714 | "another field.\n", i, argv[i]); |
| 715 | ret = -EINVAL; |
| 716 | goto error; |
| 717 | } |
Masami Hiramatsu | ba8665d | 2009-11-30 19:19:20 -0500 | [diff] [blame] | 718 | |
| 719 | /* Parse fetch argument */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 720 | ret = traceprobe_parse_probe_arg(arg, &tk->tp.size, parg, |
Masami Hiramatsu | a1303af | 2018-04-25 21:21:26 +0900 | [diff] [blame] | 721 | flags); |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 722 | if (ret) { |
Masami Hiramatsu | aba9159 | 2010-08-27 20:39:06 +0900 | [diff] [blame] | 723 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 724 | goto error; |
Masami Hiramatsu | e63cc23 | 2009-10-16 20:07:28 -0400 | [diff] [blame] | 725 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 726 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 727 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 728 | ret = register_trace_kprobe(tk); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 729 | if (ret) |
| 730 | goto error; |
| 731 | return 0; |
| 732 | |
| 733 | error: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 734 | free_trace_kprobe(tk); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 735 | return ret; |
| 736 | } |
| 737 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 738 | static int release_all_trace_kprobes(void) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 739 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 740 | struct trace_kprobe *tk; |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 741 | int ret = 0; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 742 | |
| 743 | mutex_lock(&probe_lock); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 744 | /* Ensure no probe is in use. */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 745 | list_for_each_entry(tk, &probe_list, list) |
| 746 | if (trace_probe_is_enabled(&tk->tp)) { |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 747 | ret = -EBUSY; |
| 748 | goto end; |
| 749 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 750 | /* TODO: Use batch unregistration */ |
| 751 | while (!list_empty(&probe_list)) { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 752 | tk = list_entry(probe_list.next, struct trace_kprobe, list); |
| 753 | ret = unregister_trace_kprobe(tk); |
Steven Rostedt (Red Hat) | 40c3259 | 2013-07-03 23:33:50 -0400 | [diff] [blame] | 754 | if (ret) |
| 755 | goto end; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 756 | free_trace_kprobe(tk); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 757 | } |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 758 | |
| 759 | end: |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 760 | mutex_unlock(&probe_lock); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 761 | |
| 762 | return ret; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 763 | } |
| 764 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 765 | /* Probes listing interfaces */ |
| 766 | static void *probes_seq_start(struct seq_file *m, loff_t *pos) |
| 767 | { |
| 768 | mutex_lock(&probe_lock); |
| 769 | return seq_list_start(&probe_list, *pos); |
| 770 | } |
| 771 | |
| 772 | static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos) |
| 773 | { |
| 774 | return seq_list_next(v, &probe_list, pos); |
| 775 | } |
| 776 | |
| 777 | static void probes_seq_stop(struct seq_file *m, void *v) |
| 778 | { |
| 779 | mutex_unlock(&probe_lock); |
| 780 | } |
| 781 | |
| 782 | static int probes_seq_show(struct seq_file *m, void *v) |
| 783 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 784 | struct trace_kprobe *tk = v; |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 785 | int i; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 786 | |
Rasmus Villemoes | fa6f0cc | 2014-11-08 21:42:10 +0100 | [diff] [blame] | 787 | seq_putc(m, trace_kprobe_is_return(tk) ? 'r' : 'p'); |
Mathieu Desnoyers | de7b297 | 2014-04-08 17:26:21 -0400 | [diff] [blame] | 788 | seq_printf(m, ":%s/%s", tk->tp.call.class->system, |
Steven Rostedt (Red Hat) | 687fcc4 | 2015-05-13 14:20:14 -0400 | [diff] [blame] | 789 | trace_event_name(&tk->tp.call)); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 790 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 791 | if (!tk->symbol) |
| 792 | seq_printf(m, " 0x%p", tk->rp.kp.addr); |
| 793 | else if (tk->rp.kp.offset) |
| 794 | seq_printf(m, " %s+%u", trace_kprobe_symbol(tk), |
| 795 | tk->rp.kp.offset); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 796 | else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 797 | seq_printf(m, " %s", trace_kprobe_symbol(tk)); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 798 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 799 | for (i = 0; i < tk->tp.nr_args; i++) |
| 800 | seq_printf(m, " %s=%s", tk->tp.args[i].name, tk->tp.args[i].comm); |
Rasmus Villemoes | fa6f0cc | 2014-11-08 21:42:10 +0100 | [diff] [blame] | 801 | seq_putc(m, '\n'); |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 802 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 803 | return 0; |
| 804 | } |
| 805 | |
| 806 | static const struct seq_operations probes_seq_op = { |
| 807 | .start = probes_seq_start, |
| 808 | .next = probes_seq_next, |
| 809 | .stop = probes_seq_stop, |
| 810 | .show = probes_seq_show |
| 811 | }; |
| 812 | |
| 813 | static int probes_open(struct inode *inode, struct file *file) |
| 814 | { |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 815 | int ret; |
| 816 | |
| 817 | if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 818 | ret = release_all_trace_kprobes(); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 819 | if (ret < 0) |
| 820 | return ret; |
| 821 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 822 | |
| 823 | return seq_open(file, &probes_seq_op); |
| 824 | } |
| 825 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 826 | static ssize_t probes_write(struct file *file, const char __user *buffer, |
| 827 | size_t count, loff_t *ppos) |
| 828 | { |
Tom Zanussi | 7e465ba | 2017-09-22 14:58:20 -0500 | [diff] [blame] | 829 | return trace_parse_run_command(file, buffer, count, ppos, |
| 830 | create_trace_kprobe); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 831 | } |
| 832 | |
| 833 | static const struct file_operations kprobe_events_ops = { |
| 834 | .owner = THIS_MODULE, |
| 835 | .open = probes_open, |
| 836 | .read = seq_read, |
| 837 | .llseek = seq_lseek, |
| 838 | .release = seq_release, |
| 839 | .write = probes_write, |
| 840 | }; |
| 841 | |
Masami Hiramatsu | cd7e7bd | 2009-08-13 16:35:42 -0400 | [diff] [blame] | 842 | /* Probes profiling interfaces */ |
| 843 | static int probes_profile_seq_show(struct seq_file *m, void *v) |
| 844 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 845 | struct trace_kprobe *tk = v; |
Masami Hiramatsu | cd7e7bd | 2009-08-13 16:35:42 -0400 | [diff] [blame] | 846 | |
Mathieu Desnoyers | de7b297 | 2014-04-08 17:26:21 -0400 | [diff] [blame] | 847 | seq_printf(m, " %-44s %15lu %15lu\n", |
Marcin Nowakowski | f18f97a | 2016-12-09 15:19:37 +0100 | [diff] [blame] | 848 | trace_event_name(&tk->tp.call), |
| 849 | trace_kprobe_nhit(tk), |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 850 | tk->rp.kp.nmissed); |
Masami Hiramatsu | cd7e7bd | 2009-08-13 16:35:42 -0400 | [diff] [blame] | 851 | |
| 852 | return 0; |
| 853 | } |
| 854 | |
| 855 | static const struct seq_operations profile_seq_op = { |
| 856 | .start = probes_seq_start, |
| 857 | .next = probes_seq_next, |
| 858 | .stop = probes_seq_stop, |
| 859 | .show = probes_profile_seq_show |
| 860 | }; |
| 861 | |
| 862 | static int profile_open(struct inode *inode, struct file *file) |
| 863 | { |
| 864 | return seq_open(file, &profile_seq_op); |
| 865 | } |
| 866 | |
| 867 | static const struct file_operations kprobe_profile_ops = { |
| 868 | .owner = THIS_MODULE, |
| 869 | .open = profile_open, |
| 870 | .read = seq_read, |
| 871 | .llseek = seq_lseek, |
| 872 | .release = seq_release, |
| 873 | }; |
| 874 | |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 875 | /* Kprobe specific fetch functions */ |
| 876 | |
| 877 | /* Return the length of string -- including null terminal byte */ |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 878 | static nokprobe_inline int |
| 879 | fetch_store_strlen(unsigned long addr) |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 880 | { |
| 881 | mm_segment_t old_fs; |
| 882 | int ret, len = 0; |
| 883 | u8 c; |
| 884 | |
| 885 | old_fs = get_fs(); |
| 886 | set_fs(KERNEL_DS); |
| 887 | pagefault_disable(); |
| 888 | |
| 889 | do { |
| 890 | ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); |
| 891 | len++; |
| 892 | } while (c && ret == 0 && len < MAX_STRING_SIZE); |
| 893 | |
| 894 | pagefault_enable(); |
| 895 | set_fs(old_fs); |
| 896 | |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 897 | return (ret < 0) ? ret : len; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 898 | } |
| 899 | |
| 900 | /* |
| 901 | * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max |
| 902 | * length and relative data location. |
| 903 | */ |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 904 | static nokprobe_inline int |
| 905 | fetch_store_string(unsigned long addr, void *dest, void *base) |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 906 | { |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 907 | int maxlen = get_loc_len(*(u32 *)dest); |
| 908 | u8 *dst = get_loc_data(dest, base); |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 909 | long ret; |
| 910 | |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 911 | if (unlikely(!maxlen)) |
| 912 | return -ENOMEM; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 913 | /* |
| 914 | * Try to get string again, since the string can be changed while |
| 915 | * probing. |
| 916 | */ |
| 917 | ret = strncpy_from_unsafe(dst, (void *)addr, maxlen); |
| 918 | |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 919 | if (ret >= 0) |
| 920 | *(u32 *)dest = make_data_loc(ret, (void *)dst - base); |
| 921 | return ret; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 922 | } |
| 923 | |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 924 | static nokprobe_inline int |
| 925 | probe_mem_read(void *dest, void *src, size_t size) |
| 926 | { |
| 927 | return probe_kernel_read(dest, src, size); |
| 928 | } |
| 929 | |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 930 | /* Note that we don't verify it, since the code does not come from user space */ |
| 931 | static int |
| 932 | process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 933 | void *base) |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 934 | { |
| 935 | unsigned long val; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 936 | |
Masami Hiramatsu | a668281 | 2018-08-29 01:18:43 +0900 | [diff] [blame] | 937 | retry: |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 938 | /* 1st stage: get value from context */ |
| 939 | switch (code->op) { |
| 940 | case FETCH_OP_REG: |
| 941 | val = regs_get_register(regs, code->param); |
| 942 | break; |
| 943 | case FETCH_OP_STACK: |
| 944 | val = regs_get_kernel_stack_nth(regs, code->param); |
| 945 | break; |
| 946 | case FETCH_OP_STACKP: |
| 947 | val = kernel_stack_pointer(regs); |
| 948 | break; |
| 949 | case FETCH_OP_RETVAL: |
| 950 | val = regs_return_value(regs); |
| 951 | break; |
| 952 | case FETCH_OP_IMM: |
| 953 | val = code->immediate; |
| 954 | break; |
| 955 | case FETCH_OP_COMM: |
| 956 | val = (unsigned long)current->comm; |
| 957 | break; |
Masami Hiramatsu | a1303af | 2018-04-25 21:21:26 +0900 | [diff] [blame] | 958 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 959 | case FETCH_OP_ARG: |
| 960 | val = regs_get_kernel_argument(regs, code->param); |
| 961 | break; |
| 962 | #endif |
Masami Hiramatsu | a668281 | 2018-08-29 01:18:43 +0900 | [diff] [blame] | 963 | case FETCH_NOP_SYMBOL: /* Ignore a place holder */ |
| 964 | code++; |
| 965 | goto retry; |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 966 | default: |
| 967 | return -EILSEQ; |
| 968 | } |
| 969 | code++; |
| 970 | |
Masami Hiramatsu | 9b960a3 | 2018-04-25 21:19:59 +0900 | [diff] [blame] | 971 | return process_fetch_insn_bottom(code, val, dest, base); |
Masami Hiramatsu | 5330592 | 2018-04-25 21:18:03 +0900 | [diff] [blame] | 972 | } |
| 973 | NOKPROBE_SYMBOL(process_fetch_insn) |
| 974 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 975 | /* Kprobe handler */ |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 976 | static nokprobe_inline void |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 977 | __kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 978 | struct trace_event_file *trace_file) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 979 | { |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 980 | struct kprobe_trace_entry_head *entry; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 981 | struct ring_buffer_event *event; |
Frederic Weisbecker | 8f8ffe2 | 2009-09-11 01:09:23 +0200 | [diff] [blame] | 982 | struct ring_buffer *buffer; |
Masami Hiramatsu | e09c861 | 2010-07-05 15:54:45 -0300 | [diff] [blame] | 983 | int size, dsize, pc; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 984 | unsigned long irq_flags; |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 985 | struct trace_event_call *call = &tk->tp.call; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 986 | |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 987 | WARN_ON(call != trace_file->event_call); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 988 | |
Steven Rostedt (Red Hat) | 09a5059 | 2015-05-13 15:21:25 -0400 | [diff] [blame] | 989 | if (trace_trigger_soft_disabled(trace_file)) |
Steven Rostedt (Red Hat) | 13a1e4a | 2014-01-06 21:32:10 -0500 | [diff] [blame] | 990 | return; |
Masami Hiramatsu | b882008 | 2013-05-09 14:44:54 +0900 | [diff] [blame] | 991 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 992 | local_save_flags(irq_flags); |
| 993 | pc = preempt_count(); |
| 994 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 995 | dsize = __get_data_size(&tk->tp, regs); |
| 996 | size = sizeof(*entry) + tk->tp.size + dsize; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 997 | |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 998 | event = trace_event_buffer_lock_reserve(&buffer, trace_file, |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 999 | call->event.type, |
| 1000 | size, irq_flags, pc); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1001 | if (!event) |
Xiao Guangrong | 1e12a4a | 2010-01-28 09:34:27 +0800 | [diff] [blame] | 1002 | return; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1003 | |
| 1004 | entry = ring_buffer_event_data(event); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1005 | entry->ip = (unsigned long)tk->rp.kp.addr; |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 1006 | store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1007 | |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1008 | event_trigger_unlock_commit_regs(trace_file, buffer, event, |
Steven Rostedt (Red Hat) | 13a1e4a | 2014-01-06 21:32:10 -0500 | [diff] [blame] | 1009 | entry, irq_flags, pc, regs); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1010 | } |
| 1011 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1012 | static void |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1013 | kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1014 | { |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 1015 | struct event_file_link *link; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1016 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1017 | list_for_each_entry_rcu(link, &tk->tp.files, list) |
| 1018 | __kprobe_trace_func(tk, regs, link->file); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1019 | } |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1020 | NOKPROBE_SYMBOL(kprobe_trace_func); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1021 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1022 | /* Kretprobe handler */ |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1023 | static nokprobe_inline void |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1024 | __kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1025 | struct pt_regs *regs, |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1026 | struct trace_event_file *trace_file) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1027 | { |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1028 | struct kretprobe_trace_entry_head *entry; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1029 | struct ring_buffer_event *event; |
Frederic Weisbecker | 8f8ffe2 | 2009-09-11 01:09:23 +0200 | [diff] [blame] | 1030 | struct ring_buffer *buffer; |
Masami Hiramatsu | e09c861 | 2010-07-05 15:54:45 -0300 | [diff] [blame] | 1031 | int size, pc, dsize; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1032 | unsigned long irq_flags; |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 1033 | struct trace_event_call *call = &tk->tp.call; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1034 | |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1035 | WARN_ON(call != trace_file->event_call); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1036 | |
Steven Rostedt (Red Hat) | 09a5059 | 2015-05-13 15:21:25 -0400 | [diff] [blame] | 1037 | if (trace_trigger_soft_disabled(trace_file)) |
Steven Rostedt (Red Hat) | 13a1e4a | 2014-01-06 21:32:10 -0500 | [diff] [blame] | 1038 | return; |
Masami Hiramatsu | b882008 | 2013-05-09 14:44:54 +0900 | [diff] [blame] | 1039 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1040 | local_save_flags(irq_flags); |
| 1041 | pc = preempt_count(); |
| 1042 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1043 | dsize = __get_data_size(&tk->tp, regs); |
| 1044 | size = sizeof(*entry) + tk->tp.size + dsize; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1045 | |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1046 | event = trace_event_buffer_lock_reserve(&buffer, trace_file, |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1047 | call->event.type, |
| 1048 | size, irq_flags, pc); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1049 | if (!event) |
Xiao Guangrong | 1e12a4a | 2010-01-28 09:34:27 +0800 | [diff] [blame] | 1050 | return; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1051 | |
| 1052 | entry = ring_buffer_event_data(event); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1053 | entry->func = (unsigned long)tk->rp.kp.addr; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1054 | entry->ret_ip = (unsigned long)ri->ret_addr; |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 1055 | store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1056 | |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1057 | event_trigger_unlock_commit_regs(trace_file, buffer, event, |
Steven Rostedt (Red Hat) | 13a1e4a | 2014-01-06 21:32:10 -0500 | [diff] [blame] | 1058 | entry, irq_flags, pc, regs); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1059 | } |
| 1060 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1061 | static void |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1062 | kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1063 | struct pt_regs *regs) |
| 1064 | { |
Oleg Nesterov | b04d52e | 2013-06-20 19:38:14 +0200 | [diff] [blame] | 1065 | struct event_file_link *link; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1066 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1067 | list_for_each_entry_rcu(link, &tk->tp.files, list) |
| 1068 | __kretprobe_trace_func(tk, ri, regs, link->file); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1069 | } |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1070 | NOKPROBE_SYMBOL(kretprobe_trace_func); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1071 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1072 | /* Event entry printers */ |
Masami Hiramatsu | b62fdd9 | 2013-05-13 20:58:39 +0900 | [diff] [blame] | 1073 | static enum print_line_t |
Steven Rostedt | a9a5776 | 2010-04-22 18:46:14 -0400 | [diff] [blame] | 1074 | print_kprobe_event(struct trace_iterator *iter, int flags, |
| 1075 | struct trace_event *event) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1076 | { |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1077 | struct kprobe_trace_entry_head *field; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1078 | struct trace_seq *s = &iter->seq; |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 1079 | struct trace_probe *tp; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1080 | |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1081 | field = (struct kprobe_trace_entry_head *)iter->ent; |
Steven Rostedt | 80decc7 | 2010-04-23 10:00:22 -0400 | [diff] [blame] | 1082 | tp = container_of(event, struct trace_probe, call.event); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1083 | |
Steven Rostedt (Red Hat) | 687fcc4 | 2015-05-13 14:20:14 -0400 | [diff] [blame] | 1084 | trace_seq_printf(s, "%s: (", trace_event_name(&tp->call)); |
Masami Hiramatsu | 6e9f23d | 2009-09-10 19:53:45 -0400 | [diff] [blame] | 1085 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1086 | if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET)) |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1087 | goto out; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1088 | |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1089 | trace_seq_putc(s, ')'); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1090 | |
Masami Hiramatsu | 56de763 | 2018-04-25 21:16:36 +0900 | [diff] [blame] | 1091 | if (print_probe_args(s, tp->args, tp->nr_args, |
| 1092 | (u8 *)&field[1], field) < 0) |
| 1093 | goto out; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1094 | |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1095 | trace_seq_putc(s, '\n'); |
| 1096 | out: |
| 1097 | return trace_handle_return(s); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1098 | } |
| 1099 | |
Masami Hiramatsu | b62fdd9 | 2013-05-13 20:58:39 +0900 | [diff] [blame] | 1100 | static enum print_line_t |
Steven Rostedt | a9a5776 | 2010-04-22 18:46:14 -0400 | [diff] [blame] | 1101 | print_kretprobe_event(struct trace_iterator *iter, int flags, |
| 1102 | struct trace_event *event) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1103 | { |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1104 | struct kretprobe_trace_entry_head *field; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1105 | struct trace_seq *s = &iter->seq; |
Masami Hiramatsu | eca0d91 | 2009-09-10 19:53:38 -0400 | [diff] [blame] | 1106 | struct trace_probe *tp; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1107 | |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1108 | field = (struct kretprobe_trace_entry_head *)iter->ent; |
Steven Rostedt | 80decc7 | 2010-04-23 10:00:22 -0400 | [diff] [blame] | 1109 | tp = container_of(event, struct trace_probe, call.event); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1110 | |
Steven Rostedt (Red Hat) | 687fcc4 | 2015-05-13 14:20:14 -0400 | [diff] [blame] | 1111 | trace_seq_printf(s, "%s: (", trace_event_name(&tp->call)); |
Masami Hiramatsu | 6e9f23d | 2009-09-10 19:53:45 -0400 | [diff] [blame] | 1112 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1113 | if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET)) |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1114 | goto out; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1115 | |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1116 | trace_seq_puts(s, " <- "); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1117 | |
| 1118 | if (!seq_print_ip_sym(s, field->func, flags & ~TRACE_ITER_SYM_OFFSET)) |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1119 | goto out; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1120 | |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1121 | trace_seq_putc(s, ')'); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1122 | |
Masami Hiramatsu | 56de763 | 2018-04-25 21:16:36 +0900 | [diff] [blame] | 1123 | if (print_probe_args(s, tp->args, tp->nr_args, |
| 1124 | (u8 *)&field[1], field) < 0) |
| 1125 | goto out; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1126 | |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1127 | trace_seq_putc(s, '\n'); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1128 | |
Steven Rostedt (Red Hat) | 85224da | 2014-11-12 15:18:16 -0500 | [diff] [blame] | 1129 | out: |
| 1130 | return trace_handle_return(s); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1131 | } |
| 1132 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1133 | |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 1134 | static int kprobe_event_define_fields(struct trace_event_call *event_call) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1135 | { |
Masami Hiramatsu | eeb07b0 | 2018-04-25 21:17:05 +0900 | [diff] [blame] | 1136 | int ret; |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1137 | struct kprobe_trace_entry_head field; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1138 | struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1139 | |
Masami Hiramatsu | a703d94 | 2009-10-07 18:28:07 -0400 | [diff] [blame] | 1140 | DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1141 | |
Masami Hiramatsu | eeb07b0 | 2018-04-25 21:17:05 +0900 | [diff] [blame] | 1142 | return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1143 | } |
| 1144 | |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 1145 | static int kretprobe_event_define_fields(struct trace_event_call *event_call) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1146 | { |
Masami Hiramatsu | eeb07b0 | 2018-04-25 21:17:05 +0900 | [diff] [blame] | 1147 | int ret; |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1148 | struct kretprobe_trace_entry_head field; |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1149 | struct trace_kprobe *tk = (struct trace_kprobe *)event_call->data; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1150 | |
Masami Hiramatsu | a703d94 | 2009-10-07 18:28:07 -0400 | [diff] [blame] | 1151 | DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); |
| 1152 | DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1153 | |
Masami Hiramatsu | eeb07b0 | 2018-04-25 21:17:05 +0900 | [diff] [blame] | 1154 | return traceprobe_define_arg_fields(event_call, sizeof(field), &tk->tp); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1155 | } |
| 1156 | |
Li Zefan | 07b139c | 2009-12-21 14:27:35 +0800 | [diff] [blame] | 1157 | #ifdef CONFIG_PERF_EVENTS |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1158 | |
| 1159 | /* Kprobe profile handler */ |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1160 | static int |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1161 | kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1162 | { |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 1163 | struct trace_event_call *call = &tk->tp.call; |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1164 | struct kprobe_trace_entry_head *entry; |
Peter Zijlstra | 1c024eca | 2010-05-19 14:02:22 +0200 | [diff] [blame] | 1165 | struct hlist_head *head; |
Masami Hiramatsu | e09c861 | 2010-07-05 15:54:45 -0300 | [diff] [blame] | 1166 | int size, __size, dsize; |
Peter Zijlstra | 4ed7c92 | 2009-11-23 11:37:29 +0100 | [diff] [blame] | 1167 | int rctx; |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1168 | |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1169 | if (bpf_prog_array_valid(call)) { |
Masami Hiramatsu | 66665ad | 2018-01-13 02:54:33 +0900 | [diff] [blame] | 1170 | unsigned long orig_ip = instruction_pointer(regs); |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1171 | int ret; |
| 1172 | |
| 1173 | ret = trace_call_bpf(call, regs); |
| 1174 | |
| 1175 | /* |
| 1176 | * We need to check and see if we modified the pc of the |
Masami Hiramatsu | cce188b | 2018-06-20 01:15:45 +0900 | [diff] [blame] | 1177 | * pt_regs, and if so return 1 so that we don't do the |
| 1178 | * single stepping. |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1179 | */ |
Masami Hiramatsu | cce188b | 2018-06-20 01:15:45 +0900 | [diff] [blame] | 1180 | if (orig_ip != instruction_pointer(regs)) |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1181 | return 1; |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1182 | if (!ret) |
| 1183 | return 0; |
| 1184 | } |
Alexei Starovoitov | 2541517 | 2015-03-25 12:49:20 -0700 | [diff] [blame] | 1185 | |
Oleg Nesterov | 288e984 | 2013-06-20 19:38:06 +0200 | [diff] [blame] | 1186 | head = this_cpu_ptr(call->perf_events); |
| 1187 | if (hlist_empty(head)) |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1188 | return 0; |
Oleg Nesterov | 288e984 | 2013-06-20 19:38:06 +0200 | [diff] [blame] | 1189 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1190 | dsize = __get_data_size(&tk->tp, regs); |
| 1191 | __size = sizeof(*entry) + tk->tp.size + dsize; |
Masami Hiramatsu | 74ebb63 | 2009-09-14 16:49:28 -0400 | [diff] [blame] | 1192 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
| 1193 | size -= sizeof(u32); |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1194 | |
Alexei Starovoitov | 1e1dcd9 | 2016-04-06 18:43:24 -0700 | [diff] [blame] | 1195 | entry = perf_trace_buf_alloc(size, NULL, &rctx); |
Xiao Guangrong | 430ad5a | 2010-01-28 09:32:29 +0800 | [diff] [blame] | 1196 | if (!entry) |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1197 | return 0; |
Frederic Weisbecker | ce71b9d | 2009-11-22 05:26:55 +0100 | [diff] [blame] | 1198 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1199 | entry->ip = (unsigned long)tk->rp.kp.addr; |
Masami Hiramatsu | e09c861 | 2010-07-05 15:54:45 -0300 | [diff] [blame] | 1200 | memset(&entry[1], 0, dsize); |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 1201 | store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
Alexei Starovoitov | 1e1dcd9 | 2016-04-06 18:43:24 -0700 | [diff] [blame] | 1202 | perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, |
Peter Zijlstra | 8fd0fbb | 2017-10-11 09:45:29 +0200 | [diff] [blame] | 1203 | head, NULL); |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1204 | return 0; |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1205 | } |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1206 | NOKPROBE_SYMBOL(kprobe_perf_func); |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1207 | |
| 1208 | /* Kretprobe profile handler */ |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1209 | static void |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1210 | kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
Masami Hiramatsu | 2b106aa | 2013-05-09 14:44:41 +0900 | [diff] [blame] | 1211 | struct pt_regs *regs) |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1212 | { |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 1213 | struct trace_event_call *call = &tk->tp.call; |
Masami Hiramatsu | 93ccae7 | 2010-04-12 13:17:08 -0400 | [diff] [blame] | 1214 | struct kretprobe_trace_entry_head *entry; |
Peter Zijlstra | 1c024eca | 2010-05-19 14:02:22 +0200 | [diff] [blame] | 1215 | struct hlist_head *head; |
Masami Hiramatsu | e09c861 | 2010-07-05 15:54:45 -0300 | [diff] [blame] | 1216 | int size, __size, dsize; |
Peter Zijlstra | 4ed7c92 | 2009-11-23 11:37:29 +0100 | [diff] [blame] | 1217 | int rctx; |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1218 | |
Yonghong Song | e87c6bc38 | 2017-10-23 23:53:08 -0700 | [diff] [blame] | 1219 | if (bpf_prog_array_valid(call) && !trace_call_bpf(call, regs)) |
Alexei Starovoitov | 2541517 | 2015-03-25 12:49:20 -0700 | [diff] [blame] | 1220 | return; |
| 1221 | |
Oleg Nesterov | 288e984 | 2013-06-20 19:38:06 +0200 | [diff] [blame] | 1222 | head = this_cpu_ptr(call->perf_events); |
| 1223 | if (hlist_empty(head)) |
| 1224 | return; |
| 1225 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1226 | dsize = __get_data_size(&tk->tp, regs); |
| 1227 | __size = sizeof(*entry) + tk->tp.size + dsize; |
Masami Hiramatsu | 74ebb63 | 2009-09-14 16:49:28 -0400 | [diff] [blame] | 1228 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
| 1229 | size -= sizeof(u32); |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1230 | |
Alexei Starovoitov | 1e1dcd9 | 2016-04-06 18:43:24 -0700 | [diff] [blame] | 1231 | entry = perf_trace_buf_alloc(size, NULL, &rctx); |
Xiao Guangrong | 430ad5a | 2010-01-28 09:32:29 +0800 | [diff] [blame] | 1232 | if (!entry) |
Xiao Guangrong | 1e12a4a | 2010-01-28 09:34:27 +0800 | [diff] [blame] | 1233 | return; |
Frederic Weisbecker | ce71b9d | 2009-11-22 05:26:55 +0100 | [diff] [blame] | 1234 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1235 | entry->func = (unsigned long)tk->rp.kp.addr; |
Masami Hiramatsu | a1a138d | 2009-09-25 11:20:12 -0700 | [diff] [blame] | 1236 | entry->ret_ip = (unsigned long)ri->ret_addr; |
Masami Hiramatsu | 9178412 | 2018-04-25 21:19:01 +0900 | [diff] [blame] | 1237 | store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
Alexei Starovoitov | 1e1dcd9 | 2016-04-06 18:43:24 -0700 | [diff] [blame] | 1238 | perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, |
Peter Zijlstra | 8fd0fbb | 2017-10-11 09:45:29 +0200 | [diff] [blame] | 1239 | head, NULL); |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1240 | } |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1241 | NOKPROBE_SYMBOL(kretprobe_perf_func); |
Yonghong Song | 41bdc4b | 2018-05-24 11:21:09 -0700 | [diff] [blame] | 1242 | |
| 1243 | int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type, |
| 1244 | const char **symbol, u64 *probe_offset, |
| 1245 | u64 *probe_addr, bool perf_type_tracepoint) |
| 1246 | { |
| 1247 | const char *pevent = trace_event_name(event->tp_event); |
| 1248 | const char *group = event->tp_event->class->system; |
| 1249 | struct trace_kprobe *tk; |
| 1250 | |
| 1251 | if (perf_type_tracepoint) |
| 1252 | tk = find_trace_kprobe(pevent, group); |
| 1253 | else |
| 1254 | tk = event->tp_event->data; |
| 1255 | if (!tk) |
| 1256 | return -EINVAL; |
| 1257 | |
| 1258 | *fd_type = trace_kprobe_is_return(tk) ? BPF_FD_TYPE_KRETPROBE |
| 1259 | : BPF_FD_TYPE_KPROBE; |
| 1260 | if (tk->symbol) { |
| 1261 | *symbol = tk->symbol; |
| 1262 | *probe_offset = tk->rp.kp.offset; |
| 1263 | *probe_addr = 0; |
| 1264 | } else { |
| 1265 | *symbol = NULL; |
| 1266 | *probe_offset = 0; |
| 1267 | *probe_addr = (unsigned long)tk->rp.kp.addr; |
| 1268 | } |
| 1269 | return 0; |
| 1270 | } |
Li Zefan | 07b139c | 2009-12-21 14:27:35 +0800 | [diff] [blame] | 1271 | #endif /* CONFIG_PERF_EVENTS */ |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1272 | |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 1273 | /* |
| 1274 | * called by perf_trace_init() or __ftrace_set_clr_event() under event_mutex. |
| 1275 | * |
| 1276 | * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe |
| 1277 | * lockless, but we can't race with this __init function. |
| 1278 | */ |
Steven Rostedt (Red Hat) | 2425bcb | 2015-05-05 11:45:27 -0400 | [diff] [blame] | 1279 | static int kprobe_register(struct trace_event_call *event, |
Masami Hiramatsu | fbc1963 | 2014-04-17 17:18:00 +0900 | [diff] [blame] | 1280 | enum trace_reg type, void *data) |
Steven Rostedt | 2239291 | 2010-04-21 12:27:06 -0400 | [diff] [blame] | 1281 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1282 | struct trace_kprobe *tk = (struct trace_kprobe *)event->data; |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1283 | struct trace_event_file *file = data; |
Masami Hiramatsu | 1538f88 | 2011-06-27 16:26:44 +0900 | [diff] [blame] | 1284 | |
Steven Rostedt | 2239291 | 2010-04-21 12:27:06 -0400 | [diff] [blame] | 1285 | switch (type) { |
| 1286 | case TRACE_REG_REGISTER: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1287 | return enable_trace_kprobe(tk, file); |
Steven Rostedt | 2239291 | 2010-04-21 12:27:06 -0400 | [diff] [blame] | 1288 | case TRACE_REG_UNREGISTER: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1289 | return disable_trace_kprobe(tk, file); |
Steven Rostedt | 2239291 | 2010-04-21 12:27:06 -0400 | [diff] [blame] | 1290 | |
| 1291 | #ifdef CONFIG_PERF_EVENTS |
| 1292 | case TRACE_REG_PERF_REGISTER: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1293 | return enable_trace_kprobe(tk, NULL); |
Steven Rostedt | 2239291 | 2010-04-21 12:27:06 -0400 | [diff] [blame] | 1294 | case TRACE_REG_PERF_UNREGISTER: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1295 | return disable_trace_kprobe(tk, NULL); |
Jiri Olsa | ceec0b6 | 2012-02-15 15:51:49 +0100 | [diff] [blame] | 1296 | case TRACE_REG_PERF_OPEN: |
| 1297 | case TRACE_REG_PERF_CLOSE: |
Jiri Olsa | 489c75c | 2012-02-15 15:51:50 +0100 | [diff] [blame] | 1298 | case TRACE_REG_PERF_ADD: |
| 1299 | case TRACE_REG_PERF_DEL: |
Jiri Olsa | ceec0b6 | 2012-02-15 15:51:49 +0100 | [diff] [blame] | 1300 | return 0; |
Steven Rostedt | 2239291 | 2010-04-21 12:27:06 -0400 | [diff] [blame] | 1301 | #endif |
| 1302 | } |
| 1303 | return 0; |
| 1304 | } |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1305 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1306 | static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1307 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1308 | struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1309 | int ret = 0; |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1310 | |
Martin KaFai Lau | a7636d9 | 2016-02-03 12:28:28 -0800 | [diff] [blame] | 1311 | raw_cpu_inc(*tk->nhit); |
Masami Hiramatsu | 48182bd | 2013-05-09 14:44:36 +0900 | [diff] [blame] | 1312 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1313 | if (tk->tp.flags & TP_FLAG_TRACE) |
| 1314 | kprobe_trace_func(tk, regs); |
Li Zefan | 07b139c | 2009-12-21 14:27:35 +0800 | [diff] [blame] | 1315 | #ifdef CONFIG_PERF_EVENTS |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1316 | if (tk->tp.flags & TP_FLAG_PROFILE) |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1317 | ret = kprobe_perf_func(tk, regs); |
Li Zefan | 07b139c | 2009-12-21 14:27:35 +0800 | [diff] [blame] | 1318 | #endif |
Josef Bacik | 9802d86 | 2017-12-11 11:36:48 -0500 | [diff] [blame] | 1319 | return ret; |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1320 | } |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1321 | NOKPROBE_SYMBOL(kprobe_dispatcher); |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1322 | |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1323 | static int |
| 1324 | kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1325 | { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1326 | struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp); |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1327 | |
Martin KaFai Lau | a7636d9 | 2016-02-03 12:28:28 -0800 | [diff] [blame] | 1328 | raw_cpu_inc(*tk->nhit); |
Masami Hiramatsu | 48182bd | 2013-05-09 14:44:36 +0900 | [diff] [blame] | 1329 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1330 | if (tk->tp.flags & TP_FLAG_TRACE) |
| 1331 | kretprobe_trace_func(tk, ri, regs); |
Li Zefan | 07b139c | 2009-12-21 14:27:35 +0800 | [diff] [blame] | 1332 | #ifdef CONFIG_PERF_EVENTS |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1333 | if (tk->tp.flags & TP_FLAG_PROFILE) |
| 1334 | kretprobe_perf_func(tk, ri, regs); |
Li Zefan | 07b139c | 2009-12-21 14:27:35 +0800 | [diff] [blame] | 1335 | #endif |
Masami Hiramatsu | 50d7805 | 2009-09-14 16:49:20 -0400 | [diff] [blame] | 1336 | return 0; /* We don't tweek kernel, so just return 0 */ |
| 1337 | } |
Masami Hiramatsu | 3da0f18 | 2014-04-17 17:18:28 +0900 | [diff] [blame] | 1338 | NOKPROBE_SYMBOL(kretprobe_dispatcher); |
Masami Hiramatsu | e08d1c6 | 2009-09-10 19:53:30 -0400 | [diff] [blame] | 1339 | |
Steven Rostedt | a9a5776 | 2010-04-22 18:46:14 -0400 | [diff] [blame] | 1340 | static struct trace_event_functions kretprobe_funcs = { |
| 1341 | .trace = print_kretprobe_event |
| 1342 | }; |
| 1343 | |
| 1344 | static struct trace_event_functions kprobe_funcs = { |
| 1345 | .trace = print_kprobe_event |
| 1346 | }; |
| 1347 | |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1348 | static inline void init_trace_event_call(struct trace_kprobe *tk, |
| 1349 | struct trace_event_call *call) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1350 | { |
Li Zefan | ffb9f99 | 2010-05-24 16:24:52 +0800 | [diff] [blame] | 1351 | INIT_LIST_HEAD(&call->class->fields); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1352 | if (trace_kprobe_is_return(tk)) { |
Steven Rostedt | 80decc7 | 2010-04-23 10:00:22 -0400 | [diff] [blame] | 1353 | call->event.funcs = &kretprobe_funcs; |
Steven Rostedt | 2e33af0 | 2010-04-22 10:35:55 -0400 | [diff] [blame] | 1354 | call->class->define_fields = kretprobe_event_define_fields; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1355 | } else { |
Steven Rostedt | 80decc7 | 2010-04-23 10:00:22 -0400 | [diff] [blame] | 1356 | call->event.funcs = &kprobe_funcs; |
Steven Rostedt | 2e33af0 | 2010-04-22 10:35:55 -0400 | [diff] [blame] | 1357 | call->class->define_fields = kprobe_event_define_fields; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1358 | } |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1359 | |
| 1360 | call->flags = TRACE_EVENT_FL_KPROBE; |
| 1361 | call->class->reg = kprobe_register; |
| 1362 | call->data = tk; |
| 1363 | } |
| 1364 | |
| 1365 | static int register_kprobe_event(struct trace_kprobe *tk) |
| 1366 | { |
| 1367 | struct trace_event_call *call = &tk->tp.call; |
| 1368 | int ret = 0; |
| 1369 | |
| 1370 | init_trace_event_call(tk, call); |
| 1371 | |
Masami Hiramatsu | 0a46c85 | 2018-04-25 21:19:30 +0900 | [diff] [blame] | 1372 | if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) |
Lai Jiangshan | a342a028 | 2009-12-15 15:39:49 +0800 | [diff] [blame] | 1373 | return -ENOMEM; |
Steven Rostedt (Red Hat) | 9023c93 | 2015-05-05 09:39:12 -0400 | [diff] [blame] | 1374 | ret = register_trace_event(&call->event); |
Steven Rostedt | 32c0eda | 2010-04-23 10:38:03 -0400 | [diff] [blame] | 1375 | if (!ret) { |
Lai Jiangshan | a342a028 | 2009-12-15 15:39:49 +0800 | [diff] [blame] | 1376 | kfree(call->print_fmt); |
Masami Hiramatsu | ff50d99 | 2009-08-13 16:35:34 -0400 | [diff] [blame] | 1377 | return -ENODEV; |
Lai Jiangshan | a342a028 | 2009-12-15 15:39:49 +0800 | [diff] [blame] | 1378 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1379 | ret = trace_add_event_call(call); |
Masami Hiramatsu | ff50d99 | 2009-08-13 16:35:34 -0400 | [diff] [blame] | 1380 | if (ret) { |
Mathieu Desnoyers | de7b297 | 2014-04-08 17:26:21 -0400 | [diff] [blame] | 1381 | pr_info("Failed to register kprobe event: %s\n", |
Steven Rostedt (Red Hat) | 687fcc4 | 2015-05-13 14:20:14 -0400 | [diff] [blame] | 1382 | trace_event_name(call)); |
Lai Jiangshan | a342a028 | 2009-12-15 15:39:49 +0800 | [diff] [blame] | 1383 | kfree(call->print_fmt); |
Steven Rostedt (Red Hat) | 9023c93 | 2015-05-05 09:39:12 -0400 | [diff] [blame] | 1384 | unregister_trace_event(&call->event); |
Masami Hiramatsu | ff50d99 | 2009-08-13 16:35:34 -0400 | [diff] [blame] | 1385 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1386 | return ret; |
| 1387 | } |
| 1388 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1389 | static int unregister_kprobe_event(struct trace_kprobe *tk) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1390 | { |
Steven Rostedt (Red Hat) | 40c3259 | 2013-07-03 23:33:50 -0400 | [diff] [blame] | 1391 | int ret; |
| 1392 | |
Masami Hiramatsu | ff50d99 | 2009-08-13 16:35:34 -0400 | [diff] [blame] | 1393 | /* tp->event is unregistered in trace_remove_event_call() */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1394 | ret = trace_remove_event_call(&tk->tp.call); |
Steven Rostedt (Red Hat) | 40c3259 | 2013-07-03 23:33:50 -0400 | [diff] [blame] | 1395 | if (!ret) |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1396 | kfree(tk->tp.call.print_fmt); |
Steven Rostedt (Red Hat) | 40c3259 | 2013-07-03 23:33:50 -0400 | [diff] [blame] | 1397 | return ret; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1398 | } |
| 1399 | |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1400 | #ifdef CONFIG_PERF_EVENTS |
| 1401 | /* create a trace_kprobe, but don't add it to global lists */ |
| 1402 | struct trace_event_call * |
| 1403 | create_local_trace_kprobe(char *func, void *addr, unsigned long offs, |
| 1404 | bool is_return) |
| 1405 | { |
| 1406 | struct trace_kprobe *tk; |
| 1407 | int ret; |
| 1408 | char *event; |
| 1409 | |
| 1410 | /* |
| 1411 | * local trace_kprobes are not added to probe_list, so they are never |
| 1412 | * searched in find_trace_kprobe(). Therefore, there is no concern of |
| 1413 | * duplicated name here. |
| 1414 | */ |
| 1415 | event = func ? func : "DUMMY_EVENT"; |
| 1416 | |
| 1417 | tk = alloc_trace_kprobe(KPROBE_EVENT_SYSTEM, event, (void *)addr, func, |
| 1418 | offs, 0 /* maxactive */, 0 /* nargs */, |
| 1419 | is_return); |
| 1420 | |
| 1421 | if (IS_ERR(tk)) { |
| 1422 | pr_info("Failed to allocate trace_probe.(%d)\n", |
| 1423 | (int)PTR_ERR(tk)); |
| 1424 | return ERR_CAST(tk); |
| 1425 | } |
| 1426 | |
| 1427 | init_trace_event_call(tk, &tk->tp.call); |
| 1428 | |
Masami Hiramatsu | 0a46c85 | 2018-04-25 21:19:30 +0900 | [diff] [blame] | 1429 | if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) { |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1430 | ret = -ENOMEM; |
| 1431 | goto error; |
| 1432 | } |
| 1433 | |
| 1434 | ret = __register_trace_kprobe(tk); |
Jiri Olsa | 0fc8c35 | 2018-07-09 16:19:06 +0200 | [diff] [blame] | 1435 | if (ret < 0) { |
| 1436 | kfree(tk->tp.call.print_fmt); |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1437 | goto error; |
Jiri Olsa | 0fc8c35 | 2018-07-09 16:19:06 +0200 | [diff] [blame] | 1438 | } |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1439 | |
| 1440 | return &tk->tp.call; |
| 1441 | error: |
| 1442 | free_trace_kprobe(tk); |
| 1443 | return ERR_PTR(ret); |
| 1444 | } |
| 1445 | |
| 1446 | void destroy_local_trace_kprobe(struct trace_event_call *event_call) |
| 1447 | { |
| 1448 | struct trace_kprobe *tk; |
| 1449 | |
| 1450 | tk = container_of(event_call, struct trace_kprobe, tp.call); |
| 1451 | |
| 1452 | if (trace_probe_is_enabled(&tk->tp)) { |
| 1453 | WARN_ON(1); |
| 1454 | return; |
| 1455 | } |
| 1456 | |
| 1457 | __unregister_trace_kprobe(tk); |
Jiri Olsa | 0fc8c35 | 2018-07-09 16:19:06 +0200 | [diff] [blame] | 1458 | |
| 1459 | kfree(tk->tp.call.print_fmt); |
Song Liu | e12f03d | 2017-12-06 14:45:15 -0800 | [diff] [blame] | 1460 | free_trace_kprobe(tk); |
| 1461 | } |
| 1462 | #endif /* CONFIG_PERF_EVENTS */ |
| 1463 | |
Steven Rostedt (Red Hat) | 8434dc9 | 2015-01-20 12:13:40 -0500 | [diff] [blame] | 1464 | /* Make a tracefs interface for controlling probe points */ |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1465 | static __init int init_kprobe_trace(void) |
| 1466 | { |
| 1467 | struct dentry *d_tracer; |
| 1468 | struct dentry *entry; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1469 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1470 | if (register_module_notifier(&trace_kprobe_module_nb)) |
Masami Hiramatsu | 6142431 | 2011-06-27 16:26:56 +0900 | [diff] [blame] | 1471 | return -EINVAL; |
| 1472 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1473 | d_tracer = tracing_init_dentry(); |
Steven Rostedt (Red Hat) | 14a5ae4 | 2015-01-20 11:14:16 -0500 | [diff] [blame] | 1474 | if (IS_ERR(d_tracer)) |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1475 | return 0; |
| 1476 | |
Steven Rostedt (Red Hat) | 8434dc9 | 2015-01-20 12:13:40 -0500 | [diff] [blame] | 1477 | entry = tracefs_create_file("kprobe_events", 0644, d_tracer, |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1478 | NULL, &kprobe_events_ops); |
| 1479 | |
Masami Hiramatsu | cd7e7bd | 2009-08-13 16:35:42 -0400 | [diff] [blame] | 1480 | /* Event list interface */ |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1481 | if (!entry) |
Joe Perches | a395d6a | 2016-03-22 14:28:09 -0700 | [diff] [blame] | 1482 | pr_warn("Could not create tracefs 'kprobe_events' entry\n"); |
Masami Hiramatsu | cd7e7bd | 2009-08-13 16:35:42 -0400 | [diff] [blame] | 1483 | |
| 1484 | /* Profile interface */ |
Steven Rostedt (Red Hat) | 8434dc9 | 2015-01-20 12:13:40 -0500 | [diff] [blame] | 1485 | entry = tracefs_create_file("kprobe_profile", 0444, d_tracer, |
Masami Hiramatsu | cd7e7bd | 2009-08-13 16:35:42 -0400 | [diff] [blame] | 1486 | NULL, &kprobe_profile_ops); |
| 1487 | |
| 1488 | if (!entry) |
Joe Perches | a395d6a | 2016-03-22 14:28:09 -0700 | [diff] [blame] | 1489 | pr_warn("Could not create tracefs 'kprobe_profile' entry\n"); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1490 | return 0; |
| 1491 | } |
| 1492 | fs_initcall(init_kprobe_trace); |
| 1493 | |
| 1494 | |
| 1495 | #ifdef CONFIG_FTRACE_STARTUP_TEST |
Arnd Bergmann | 26a346f | 2017-02-01 17:57:56 +0100 | [diff] [blame] | 1496 | static __init struct trace_event_file * |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1497 | find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr) |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1498 | { |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1499 | struct trace_event_file *file; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1500 | |
| 1501 | list_for_each_entry(file, &tr->events, list) |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1502 | if (file->event_call == &tk->tp.call) |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1503 | return file; |
| 1504 | |
| 1505 | return NULL; |
| 1506 | } |
| 1507 | |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 1508 | /* |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1509 | * Nobody but us can call enable_trace_kprobe/disable_trace_kprobe at this |
Oleg Nesterov | 3fe3d61 | 2013-06-20 19:38:09 +0200 | [diff] [blame] | 1510 | * stage, we can do this lockless. |
| 1511 | */ |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1512 | static __init int kprobe_trace_self_tests_init(void) |
| 1513 | { |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1514 | int ret, warn = 0; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1515 | int (*target)(int, int, int, int, int, int); |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1516 | struct trace_kprobe *tk; |
Steven Rostedt (Red Hat) | 7f1d2f8 | 2015-05-05 10:09:53 -0400 | [diff] [blame] | 1517 | struct trace_event_file *file; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1518 | |
Yoshihiro YUNOMAE | 748ec3a | 2014-06-06 07:35:20 +0900 | [diff] [blame] | 1519 | if (tracing_is_disabled()) |
| 1520 | return -ENODEV; |
| 1521 | |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1522 | target = kprobe_trace_selftest_target; |
| 1523 | |
| 1524 | pr_info("Testing kprobe tracing: "); |
| 1525 | |
Tom Zanussi | 7e465ba | 2017-09-22 14:58:20 -0500 | [diff] [blame] | 1526 | ret = trace_run_command("p:testprobe kprobe_trace_selftest_target " |
| 1527 | "$stack $stack0 +0($stack)", |
| 1528 | create_trace_kprobe); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1529 | if (WARN_ON_ONCE(ret)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1530 | pr_warn("error on probing function entry.\n"); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1531 | warn++; |
| 1532 | } else { |
| 1533 | /* Enable trace point */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1534 | tk = find_trace_kprobe("testprobe", KPROBE_EVENT_SYSTEM); |
| 1535 | if (WARN_ON_ONCE(tk == NULL)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1536 | pr_warn("error on getting new probe.\n"); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1537 | warn++; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1538 | } else { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1539 | file = find_trace_probe_file(tk, top_trace_array()); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1540 | if (WARN_ON_ONCE(file == NULL)) { |
| 1541 | pr_warn("error on getting probe file.\n"); |
| 1542 | warn++; |
| 1543 | } else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1544 | enable_trace_kprobe(tk, file); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1545 | } |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1546 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1547 | |
Tom Zanussi | 7e465ba | 2017-09-22 14:58:20 -0500 | [diff] [blame] | 1548 | ret = trace_run_command("r:testprobe2 kprobe_trace_selftest_target " |
| 1549 | "$retval", create_trace_kprobe); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1550 | if (WARN_ON_ONCE(ret)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1551 | pr_warn("error on probing function return.\n"); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1552 | warn++; |
| 1553 | } else { |
| 1554 | /* Enable trace point */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1555 | tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM); |
| 1556 | if (WARN_ON_ONCE(tk == NULL)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1557 | pr_warn("error on getting 2nd new probe.\n"); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1558 | warn++; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1559 | } else { |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1560 | file = find_trace_probe_file(tk, top_trace_array()); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1561 | if (WARN_ON_ONCE(file == NULL)) { |
| 1562 | pr_warn("error on getting probe file.\n"); |
| 1563 | warn++; |
| 1564 | } else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1565 | enable_trace_kprobe(tk, file); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1566 | } |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1567 | } |
| 1568 | |
| 1569 | if (warn) |
| 1570 | goto end; |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1571 | |
| 1572 | ret = target(1, 2, 3, 4, 5, 6); |
| 1573 | |
Marcin Nowakowski | d4d7ccc | 2016-12-09 15:19:38 +0100 | [diff] [blame] | 1574 | /* |
| 1575 | * Not expecting an error here, the check is only to prevent the |
| 1576 | * optimizer from removing the call to target() as otherwise there |
| 1577 | * are no side-effects and the call is never performed. |
| 1578 | */ |
| 1579 | if (ret != 21) |
| 1580 | warn++; |
| 1581 | |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 1582 | /* Disable trace points before removing it */ |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1583 | tk = find_trace_kprobe("testprobe", KPROBE_EVENT_SYSTEM); |
| 1584 | if (WARN_ON_ONCE(tk == NULL)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1585 | pr_warn("error on getting test probe.\n"); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 1586 | warn++; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1587 | } else { |
Marcin Nowakowski | d4d7ccc | 2016-12-09 15:19:38 +0100 | [diff] [blame] | 1588 | if (trace_kprobe_nhit(tk) != 1) { |
| 1589 | pr_warn("incorrect number of testprobe hits\n"); |
| 1590 | warn++; |
| 1591 | } |
| 1592 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1593 | file = find_trace_probe_file(tk, top_trace_array()); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1594 | if (WARN_ON_ONCE(file == NULL)) { |
| 1595 | pr_warn("error on getting probe file.\n"); |
| 1596 | warn++; |
| 1597 | } else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1598 | disable_trace_kprobe(tk, file); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1599 | } |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 1600 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1601 | tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM); |
| 1602 | if (WARN_ON_ONCE(tk == NULL)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1603 | pr_warn("error on getting 2nd test probe.\n"); |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 1604 | warn++; |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1605 | } else { |
Marcin Nowakowski | d4d7ccc | 2016-12-09 15:19:38 +0100 | [diff] [blame] | 1606 | if (trace_kprobe_nhit(tk) != 1) { |
| 1607 | pr_warn("incorrect number of testprobe2 hits\n"); |
| 1608 | warn++; |
| 1609 | } |
| 1610 | |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1611 | file = find_trace_probe_file(tk, top_trace_array()); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1612 | if (WARN_ON_ONCE(file == NULL)) { |
| 1613 | pr_warn("error on getting probe file.\n"); |
| 1614 | warn++; |
| 1615 | } else |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1616 | disable_trace_kprobe(tk, file); |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1617 | } |
Masami Hiramatsu | 02ca152 | 2011-10-04 19:44:38 +0900 | [diff] [blame] | 1618 | |
Tom Zanussi | 7e465ba | 2017-09-22 14:58:20 -0500 | [diff] [blame] | 1619 | ret = trace_run_command("-:testprobe", create_trace_kprobe); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1620 | if (WARN_ON_ONCE(ret)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1621 | pr_warn("error on deleting a probe.\n"); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1622 | warn++; |
| 1623 | } |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1624 | |
Tom Zanussi | 7e465ba | 2017-09-22 14:58:20 -0500 | [diff] [blame] | 1625 | ret = trace_run_command("-:testprobe2", create_trace_kprobe); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1626 | if (WARN_ON_ONCE(ret)) { |
Masami Hiramatsu | 41a7dd4 | 2013-05-09 14:44:49 +0900 | [diff] [blame] | 1627 | pr_warn("error on deleting a probe.\n"); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1628 | warn++; |
| 1629 | } |
| 1630 | |
| 1631 | end: |
Namhyung Kim | c31ffb3 | 2013-07-03 13:50:51 +0900 | [diff] [blame] | 1632 | release_all_trace_kprobes(); |
Thomas Gleixner | 30e7d894 | 2017-05-17 10:19:49 +0200 | [diff] [blame] | 1633 | /* |
| 1634 | * Wait for the optimizer work to finish. Otherwise it might fiddle |
| 1635 | * with probes in already freed __init text. |
| 1636 | */ |
| 1637 | wait_for_kprobe_optimizer(); |
Masami Hiramatsu | 231e36f | 2010-01-14 00:12:12 -0500 | [diff] [blame] | 1638 | if (warn) |
| 1639 | pr_cont("NG: Some tests are failed. Please check them.\n"); |
| 1640 | else |
| 1641 | pr_cont("OK\n"); |
Masami Hiramatsu | 413d37d | 2009-08-13 16:35:11 -0400 | [diff] [blame] | 1642 | return 0; |
| 1643 | } |
| 1644 | |
| 1645 | late_initcall(kprobe_trace_self_tests_init); |
| 1646 | |
| 1647 | #endif |