Blame view
kernel/trace/trace_kprobe.c
51.1 KB
bcea3f96e tracing: Add SPDX... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
413d37d1e tracing: Add kpro... |
2 |
/* |
77b44d1b7 tracing/kprobes: ... |
3 |
* Kprobes-based tracing events |
413d37d1e tracing: Add kpro... |
4 5 6 |
* * Created by Masami Hiramatsu <mhiramat@redhat.com> * |
413d37d1e tracing: Add kpro... |
7 |
*/ |
725763413 tracing/probe: Sh... |
8 |
#define pr_fmt(fmt) "trace_kprobe: " fmt |
413d37d1e tracing: Add kpro... |
9 |
|
17911ff38 tracing: Add lock... |
10 |
#include <linux/security.h> |
413d37d1e tracing: Add kpro... |
11 12 |
#include <linux/module.h> #include <linux/uaccess.h> |
b2d091031 sched/headers: Pr... |
13 |
#include <linux/rculist.h> |
540adea38 error-injection: ... |
14 |
#include <linux/error-injection.h> |
413d37d1e tracing: Add kpro... |
15 |
|
970988e19 tracing/kprobe: A... |
16 |
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */ |
6212dd296 tracing/kprobes: ... |
17 |
#include "trace_dynevent.h" |
d899926f5 selftest/ftrace: ... |
18 |
#include "trace_kprobe_selftest.h" |
8ab83f564 tracing: Extract ... |
19 |
#include "trace_probe.h" |
533059281 tracing: probeeve... |
20 |
#include "trace_probe_tmpl.h" |
1ff511e35 tracing/kprobes: ... |
21 |
|
8ab83f564 tracing: Extract ... |
22 |
#define KPROBE_EVENT_SYSTEM "kprobes" |
696ced4fb tracing/kprobes: ... |
23 |
#define KRETPROBE_MAXACTIVE_MAX 4096 |
970988e19 tracing/kprobe: A... |
24 25 26 27 28 29 30 |
/* Kprobe early definition from command line */ static char kprobe_boot_events_buf[COMMAND_LINE_SIZE] __initdata; static int __init set_kprobe_boot_events(char *str) { strlcpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE); |
f2d7cffc2 tracing: Disable ... |
31 |
disable_tracing_selftest("running kprobe events"); |
970988e19 tracing/kprobe: A... |
32 33 34 |
return 0; } __setup("kprobe_event=", set_kprobe_boot_events); |
e09c8614b tracing/kprobes: ... |
35 |
|
6212dd296 tracing/kprobes: ... |
36 37 38 39 40 |
static int trace_kprobe_create(int argc, const char **argv); static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev); static int trace_kprobe_release(struct dyn_event *ev); static bool trace_kprobe_is_busy(struct dyn_event *ev); static bool trace_kprobe_match(const char *system, const char *event, |
30199137c tracing/dynevent:... |
41 |
int argc, const char **argv, struct dyn_event *ev); |
6212dd296 tracing/kprobes: ... |
42 43 44 45 46 47 48 49 |
static struct dyn_event_operations trace_kprobe_ops = { .create = trace_kprobe_create, .show = trace_kprobe_show, .is_busy = trace_kprobe_is_busy, .free = trace_kprobe_release, .match = trace_kprobe_match, }; |
cede666e2 trace/probes: Rem... |
50 |
/* |
77b44d1b7 tracing/kprobes: ... |
51 |
* Kprobe event core functions |
413d37d1e tracing: Add kpro... |
52 |
*/ |
c31ffb3ff tracing/kprobes: ... |
53 |
struct trace_kprobe { |
6212dd296 tracing/kprobes: ... |
54 |
struct dyn_event devent; |
4a846b443 tracing/kprobes: ... |
55 |
struct kretprobe rp; /* Use rp.kp for kprobe use */ |
a7636d9ec kprobes: Optimize... |
56 |
unsigned long __percpu *nhit; |
413d37d1e tracing: Add kpro... |
57 |
const char *symbol; /* symbol name */ |
c31ffb3ff tracing/kprobes: ... |
58 |
struct trace_probe tp; |
413d37d1e tracing: Add kpro... |
59 |
}; |
6212dd296 tracing/kprobes: ... |
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
static bool is_trace_kprobe(struct dyn_event *ev) { return ev->ops == &trace_kprobe_ops; } static struct trace_kprobe *to_trace_kprobe(struct dyn_event *ev) { return container_of(ev, struct trace_kprobe, devent); } /** * for_each_trace_kprobe - iterate over the trace_kprobe list * @pos: the struct trace_kprobe * for each entry * @dpos: the struct dyn_event * to use as a loop cursor */ #define for_each_trace_kprobe(pos, dpos) \ for_each_dyn_event(dpos) \ if (is_trace_kprobe(dpos) && (pos = to_trace_kprobe(dpos))) |
c31ffb3ff tracing/kprobes: ... |
78 79 |
#define SIZEOF_TRACE_KPROBE(n) \ (offsetof(struct trace_kprobe, tp.args) + \ |
eca0d916f tracing/kprobes: ... |
80 |
(sizeof(struct probe_arg) * (n))) |
a82378d88 tracing: Kprobe-t... |
81 |
|
3da0f1800 kprobes, ftrace: ... |
82 |
static nokprobe_inline bool trace_kprobe_is_return(struct trace_kprobe *tk) |
413d37d1e tracing: Add kpro... |
83 |
{ |
c31ffb3ff tracing/kprobes: ... |
84 |
return tk->rp.handler != NULL; |
413d37d1e tracing: Add kpro... |
85 |
} |
3da0f1800 kprobes, ftrace: ... |
86 |
static nokprobe_inline const char *trace_kprobe_symbol(struct trace_kprobe *tk) |
413d37d1e tracing: Add kpro... |
87 |
{ |
c31ffb3ff tracing/kprobes: ... |
88 |
return tk->symbol ? tk->symbol : "unknown"; |
413d37d1e tracing: Add kpro... |
89 |
} |
3da0f1800 kprobes, ftrace: ... |
90 |
static nokprobe_inline unsigned long trace_kprobe_offset(struct trace_kprobe *tk) |
614243181 tracing/kprobes: ... |
91 |
{ |
c31ffb3ff tracing/kprobes: ... |
92 |
return tk->rp.kp.offset; |
614243181 tracing/kprobes: ... |
93 |
} |
3da0f1800 kprobes, ftrace: ... |
94 |
static nokprobe_inline bool trace_kprobe_has_gone(struct trace_kprobe *tk) |
614243181 tracing/kprobes: ... |
95 |
{ |
c31ffb3ff tracing/kprobes: ... |
96 |
return !!(kprobe_gone(&tk->rp.kp)); |
614243181 tracing/kprobes: ... |
97 |
} |
3da0f1800 kprobes, ftrace: ... |
98 |
static nokprobe_inline bool trace_kprobe_within_module(struct trace_kprobe *tk, |
c31ffb3ff tracing/kprobes: ... |
99 |
struct module *mod) |
614243181 tracing/kprobes: ... |
100 |
{ |
f3d364266 kprobes: Use modu... |
101 |
int len = strlen(module_name(mod)); |
c31ffb3ff tracing/kprobes: ... |
102 |
const char *name = trace_kprobe_symbol(tk); |
f3d364266 kprobes: Use modu... |
103 104 |
return strncmp(module_name(mod), name, len) == 0 && name[len] == ':'; |
614243181 tracing/kprobes: ... |
105 |
} |
59158ec4a tracing/kprobes: ... |
106 |
static nokprobe_inline bool trace_kprobe_module_exist(struct trace_kprobe *tk) |
614243181 tracing/kprobes: ... |
107 |
{ |
59158ec4a tracing/kprobes: ... |
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
char *p; bool ret; if (!tk->symbol) return false; p = strchr(tk->symbol, ':'); if (!p) return true; *p = '\0'; mutex_lock(&module_mutex); ret = !!find_module(tk->symbol); mutex_unlock(&module_mutex); *p = ':'; return ret; |
614243181 tracing/kprobes: ... |
123 |
} |
6212dd296 tracing/kprobes: ... |
124 125 126 127 128 129 |
static bool trace_kprobe_is_busy(struct dyn_event *ev) { struct trace_kprobe *tk = to_trace_kprobe(ev); return trace_probe_is_enabled(&tk->tp); } |
eb5bf8133 tracing/kprobe: A... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
static bool trace_kprobe_match_command_head(struct trace_kprobe *tk, int argc, const char **argv) { char buf[MAX_ARGSTR_LEN + 1]; if (!argc) return true; if (!tk->symbol) snprintf(buf, sizeof(buf), "0x%p", tk->rp.kp.addr); else if (tk->rp.kp.offset) snprintf(buf, sizeof(buf), "%s+%u", trace_kprobe_symbol(tk), tk->rp.kp.offset); else snprintf(buf, sizeof(buf), "%s", trace_kprobe_symbol(tk)); if (strcmp(buf, argv[0])) return false; argc--; argv++; return trace_probe_match_command_args(&tk->tp, argc, argv); } |
6212dd296 tracing/kprobes: ... |
151 |
static bool trace_kprobe_match(const char *system, const char *event, |
30199137c tracing/dynevent:... |
152 |
int argc, const char **argv, struct dyn_event *ev) |
6212dd296 tracing/kprobes: ... |
153 154 |
{ struct trace_kprobe *tk = to_trace_kprobe(ev); |
b55ce203a tracing/probe: Ad... |
155 |
return strcmp(trace_probe_name(&tk->tp), event) == 0 && |
eb5bf8133 tracing/kprobe: A... |
156 157 |
(!system || strcmp(trace_probe_group_name(&tk->tp), system) == 0) && trace_kprobe_match_command_head(tk, argc, argv); |
6212dd296 tracing/kprobes: ... |
158 |
} |
f18f97ac4 tracing/kprobes: ... |
159 160 161 162 163 164 165 166 167 168 |
static nokprobe_inline unsigned long trace_kprobe_nhit(struct trace_kprobe *tk) { unsigned long nhit = 0; int cpu; for_each_possible_cpu(cpu) nhit += *per_cpu_ptr(tk->nhit, cpu); return nhit; } |
715fa2fd4 tracing/kprobe: C... |
169 170 171 172 173 |
static nokprobe_inline bool trace_kprobe_is_registered(struct trace_kprobe *tk) { return !(list_empty(&tk->rp.kp.list) && hlist_unhashed(&tk->rp.kp.hlist)); } |
6bc6c77cf tracing/kprobes: ... |
174 |
/* Return 0 if it fails to find the symbol address */ |
45408c4f9 tracing: kprobes:... |
175 176 177 178 179 180 181 182 |
static nokprobe_inline unsigned long trace_kprobe_address(struct trace_kprobe *tk) { unsigned long addr; if (tk->symbol) { addr = (unsigned long) kallsyms_lookup_name(trace_kprobe_symbol(tk)); |
6bc6c77cf tracing/kprobes: ... |
183 184 |
if (addr) addr += tk->rp.kp.offset; |
45408c4f9 tracing: kprobes:... |
185 186 187 188 189 |
} else { addr = (unsigned long)tk->rp.kp.addr; } return addr; } |
60d53e2c3 tracing/probe: Sp... |
190 191 192 193 194 195 196 197 198 199 200 |
static nokprobe_inline struct trace_kprobe * trace_kprobe_primary_from_call(struct trace_event_call *call) { struct trace_probe *tp; tp = trace_probe_primary_from_call(call); if (WARN_ON_ONCE(!tp)) return NULL; return container_of(tp, struct trace_kprobe, tp); } |
b4da3340e tracing/kprobe: b... |
201 |
bool trace_kprobe_on_func_entry(struct trace_event_call *call) |
9802d8658 bpf: add a bpf_ov... |
202 |
{ |
60d53e2c3 tracing/probe: Sp... |
203 |
struct trace_kprobe *tk = trace_kprobe_primary_from_call(call); |
b4da3340e tracing/kprobe: b... |
204 |
|
60d53e2c3 tracing/probe: Sp... |
205 |
return tk ? kprobe_on_func_entry(tk->rp.kp.addr, |
b4da3340e tracing/kprobe: b... |
206 |
tk->rp.kp.addr ? NULL : tk->rp.kp.symbol_name, |
60d53e2c3 tracing/probe: Sp... |
207 |
tk->rp.kp.addr ? 0 : tk->rp.kp.offset) : false; |
9802d8658 bpf: add a bpf_ov... |
208 |
} |
b4da3340e tracing/kprobe: b... |
209 |
bool trace_kprobe_error_injectable(struct trace_event_call *call) |
9802d8658 bpf: add a bpf_ov... |
210 |
{ |
60d53e2c3 tracing/probe: Sp... |
211 |
struct trace_kprobe *tk = trace_kprobe_primary_from_call(call); |
9802d8658 bpf: add a bpf_ov... |
212 |
|
60d53e2c3 tracing/probe: Sp... |
213 214 |
return tk ? within_error_injection_list(trace_kprobe_address(tk)) : false; |
9802d8658 bpf: add a bpf_ov... |
215 |
} |
c31ffb3ff tracing/kprobes: ... |
216 217 |
static int register_kprobe_event(struct trace_kprobe *tk); static int unregister_kprobe_event(struct trace_kprobe *tk); |
413d37d1e tracing: Add kpro... |
218 |
|
50d780560 tracing/kprobes: ... |
219 220 221 |
static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); static int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs); |
455b28997 tracing/probe: Ad... |
222 223 224 225 226 227 228 229 230 |
static void free_trace_kprobe(struct trace_kprobe *tk) { if (tk) { trace_probe_cleanup(&tk->tp); kfree(tk->symbol); free_percpu(tk->nhit); kfree(tk); } } |
4a846b443 tracing/kprobes: ... |
231 232 233 |
/* * Allocate new trace_probe and initialize it (including kprobes). */ |
c31ffb3ff tracing/kprobes: ... |
234 |
static struct trace_kprobe *alloc_trace_kprobe(const char *group, |
f52487e9c tracing/kprobes: ... |
235 |
const char *event, |
4a846b443 tracing/kprobes: ... |
236 237 238 |
void *addr, const char *symbol, unsigned long offs, |
696ced4fb tracing/kprobes: ... |
239 |
int maxactive, |
3a6b76661 tracing: Modify i... |
240 |
int nargs, bool is_return) |
413d37d1e tracing: Add kpro... |
241 |
{ |
c31ffb3ff tracing/kprobes: ... |
242 |
struct trace_kprobe *tk; |
6f3cf4404 kprobe-tracer: Ch... |
243 |
int ret = -ENOMEM; |
413d37d1e tracing: Add kpro... |
244 |
|
c31ffb3ff tracing/kprobes: ... |
245 246 |
tk = kzalloc(SIZEOF_TRACE_KPROBE(nargs), GFP_KERNEL); if (!tk) |
6f3cf4404 kprobe-tracer: Ch... |
247 |
return ERR_PTR(ret); |
413d37d1e tracing: Add kpro... |
248 |
|
a7636d9ec kprobes: Optimize... |
249 250 251 |
tk->nhit = alloc_percpu(unsigned long); if (!tk->nhit) goto error; |
413d37d1e tracing: Add kpro... |
252 |
if (symbol) { |
c31ffb3ff tracing/kprobes: ... |
253 254 |
tk->symbol = kstrdup(symbol, GFP_KERNEL); if (!tk->symbol) |
413d37d1e tracing: Add kpro... |
255 |
goto error; |
c31ffb3ff tracing/kprobes: ... |
256 257 |
tk->rp.kp.symbol_name = tk->symbol; tk->rp.kp.offset = offs; |
4a846b443 tracing/kprobes: ... |
258 |
} else |
c31ffb3ff tracing/kprobes: ... |
259 |
tk->rp.kp.addr = addr; |
4a846b443 tracing/kprobes: ... |
260 261 |
if (is_return) |
c31ffb3ff tracing/kprobes: ... |
262 |
tk->rp.handler = kretprobe_dispatcher; |
4a846b443 tracing/kprobes: ... |
263 |
else |
c31ffb3ff tracing/kprobes: ... |
264 |
tk->rp.kp.pre_handler = kprobe_dispatcher; |
4a846b443 tracing/kprobes: ... |
265 |
|
696ced4fb tracing/kprobes: ... |
266 |
tk->rp.maxactive = maxactive; |
715fa2fd4 tracing/kprobe: C... |
267 268 |
INIT_HLIST_NODE(&tk->rp.kp.hlist); INIT_LIST_HEAD(&tk->rp.kp.list); |
696ced4fb tracing/kprobes: ... |
269 |
|
b61387cb7 tracing/uprobe: F... |
270 |
ret = trace_probe_init(&tk->tp, event, group, false); |
455b28997 tracing/probe: Ad... |
271 |
if (ret < 0) |
f52487e9c tracing/kprobes: ... |
272 |
goto error; |
6212dd296 tracing/kprobes: ... |
273 |
dyn_event_init(&tk->devent, &trace_kprobe_ops); |
c31ffb3ff tracing/kprobes: ... |
274 |
return tk; |
413d37d1e tracing: Add kpro... |
275 |
error: |
455b28997 tracing/probe: Ad... |
276 |
free_trace_kprobe(tk); |
6f3cf4404 kprobe-tracer: Ch... |
277 |
return ERR_PTR(ret); |
413d37d1e tracing: Add kpro... |
278 |
} |
c31ffb3ff tracing/kprobes: ... |
279 280 |
static struct trace_kprobe *find_trace_kprobe(const char *event, const char *group) |
413d37d1e tracing: Add kpro... |
281 |
{ |
6212dd296 tracing/kprobes: ... |
282 |
struct dyn_event *pos; |
c31ffb3ff tracing/kprobes: ... |
283 |
struct trace_kprobe *tk; |
413d37d1e tracing: Add kpro... |
284 |
|
6212dd296 tracing/kprobes: ... |
285 |
for_each_trace_kprobe(tk, pos) |
b55ce203a tracing/probe: Ad... |
286 287 |
if (strcmp(trace_probe_name(&tk->tp), event) == 0 && strcmp(trace_probe_group_name(&tk->tp), group) == 0) |
c31ffb3ff tracing/kprobes: ... |
288 |
return tk; |
413d37d1e tracing: Add kpro... |
289 290 |
return NULL; } |
87107a25a tracing/kprobes: ... |
291 292 293 |
static inline int __enable_trace_kprobe(struct trace_kprobe *tk) { int ret = 0; |
715fa2fd4 tracing/kprobe: C... |
294 |
if (trace_kprobe_is_registered(tk) && !trace_kprobe_has_gone(tk)) { |
87107a25a tracing/kprobes: ... |
295 296 297 298 299 300 301 302 |
if (trace_kprobe_is_return(tk)) ret = enable_kretprobe(&tk->rp); else ret = enable_kprobe(&tk->rp.kp); } return ret; } |
60d53e2c3 tracing/probe: Sp... |
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
static void __disable_trace_kprobe(struct trace_probe *tp) { struct trace_probe *pos; struct trace_kprobe *tk; list_for_each_entry(pos, trace_probe_probe_list(tp), list) { tk = container_of(pos, struct trace_kprobe, tp); if (!trace_kprobe_is_registered(tk)) continue; if (trace_kprobe_is_return(tk)) disable_kretprobe(&tk->rp); else disable_kprobe(&tk->rp.kp); } } |
3fe3d6193 tracing/kprobes: ... |
318 |
/* |
41a7dd420 tracing/kprobes: ... |
319 320 321 |
* Enable trace_probe * if the file is NULL, enable "perf" handler, or enable "trace" handler. */ |
60d53e2c3 tracing/probe: Sp... |
322 323 |
static int enable_trace_kprobe(struct trace_event_call *call, struct trace_event_file *file) |
1538f888f tracing/kprobes: ... |
324 |
{ |
60d53e2c3 tracing/probe: Sp... |
325 326 327 |
struct trace_probe *pos, *tp; struct trace_kprobe *tk; bool enabled; |
1538f888f tracing/kprobes: ... |
328 |
int ret = 0; |
60d53e2c3 tracing/probe: Sp... |
329 330 331 332 333 334 |
tp = trace_probe_primary_from_call(call); if (WARN_ON_ONCE(!tp)) return -ENODEV; enabled = trace_probe_is_enabled(tp); /* This also changes "enabled" state */ |
41a7dd420 tracing/kprobes: ... |
335 |
if (file) { |
60d53e2c3 tracing/probe: Sp... |
336 |
ret = trace_probe_add_file(tp, file); |
b5f935ee1 tracing/probe: Ad... |
337 338 339 |
if (ret) return ret; } else |
60d53e2c3 tracing/probe: Sp... |
340 |
trace_probe_set_flag(tp, TP_FLAG_PROFILE); |
41a7dd420 tracing/kprobes: ... |
341 |
|
b5f935ee1 tracing/probe: Ad... |
342 343 |
if (enabled) return 0; |
87107a25a tracing/kprobes: ... |
344 |
|
60d53e2c3 tracing/probe: Sp... |
345 346 347 348 349 |
list_for_each_entry(pos, trace_probe_probe_list(tp), list) { tk = container_of(pos, struct trace_kprobe, tp); if (trace_kprobe_has_gone(tk)) continue; ret = __enable_trace_kprobe(tk); |
44d00dc7c tracing/probe: Fi... |
350 |
if (ret) |
60d53e2c3 tracing/probe: Sp... |
351 |
break; |
60d53e2c3 tracing/probe: Sp... |
352 353 |
enabled = true; } |
44d00dc7c tracing/probe: Fi... |
354 355 356 357 |
if (ret) { /* Failed to enable one of them. Roll back all */ if (enabled) __disable_trace_kprobe(tp); |
b5f935ee1 tracing/probe: Ad... |
358 |
if (file) |
60d53e2c3 tracing/probe: Sp... |
359 |
trace_probe_remove_file(tp, file); |
b5f935ee1 tracing/probe: Ad... |
360 |
else |
60d53e2c3 tracing/probe: Sp... |
361 |
trace_probe_clear_flag(tp, TP_FLAG_PROFILE); |
57ea2a34a tracing/kprobes: ... |
362 |
} |
b5f935ee1 tracing/probe: Ad... |
363 |
|
1538f888f tracing/kprobes: ... |
364 365 |
return ret; } |
41a7dd420 tracing/kprobes: ... |
366 367 368 369 |
/* * Disable trace_probe * if the file is NULL, disable "perf" handler, or disable "trace" handler. */ |
60d53e2c3 tracing/probe: Sp... |
370 371 |
static int disable_trace_kprobe(struct trace_event_call *call, struct trace_event_file *file) |
1538f888f tracing/kprobes: ... |
372 |
{ |
60d53e2c3 tracing/probe: Sp... |
373 374 375 376 377 |
struct trace_probe *tp; tp = trace_probe_primary_from_call(call); if (WARN_ON_ONCE(!tp)) return -ENODEV; |
41a7dd420 tracing/kprobes: ... |
378 |
|
41a7dd420 tracing/kprobes: ... |
379 |
if (file) { |
b5f935ee1 tracing/probe: Ad... |
380 381 382 |
if (!trace_probe_get_file_link(tp, file)) return -ENOENT; if (!trace_probe_has_single_file(tp)) |
b04d52e36 tracing/kprobes: ... |
383 |
goto out; |
747774d6b tracing/probe: Ad... |
384 |
trace_probe_clear_flag(tp, TP_FLAG_TRACE); |
41a7dd420 tracing/kprobes: ... |
385 |
} else |
747774d6b tracing/probe: Ad... |
386 |
trace_probe_clear_flag(tp, TP_FLAG_PROFILE); |
41a7dd420 tracing/kprobes: ... |
387 |
|
60d53e2c3 tracing/probe: Sp... |
388 389 |
if (!trace_probe_is_enabled(tp)) __disable_trace_kprobe(tp); |
e12f03d70 perf/core: Implem... |
390 |
|
3fe3d6193 tracing/kprobes: ... |
391 |
out: |
b5f935ee1 tracing/probe: Ad... |
392 |
if (file) |
a232e270d tracing/kprobe: W... |
393 |
/* |
b5f935ee1 tracing/probe: Ad... |
394 395 396 397 |
* Synchronization is done in below function. For perf event, * file == NULL and perf_trace_event_unreg() calls * tracepoint_synchronize_unregister() to ensure synchronize * event. We don't need to care about it. |
a232e270d tracing/kprobe: W... |
398 |
*/ |
b5f935ee1 tracing/probe: Ad... |
399 |
trace_probe_remove_file(tp, file); |
a232e270d tracing/kprobe: W... |
400 |
|
60d53e2c3 tracing/probe: Sp... |
401 |
return 0; |
1538f888f tracing/kprobes: ... |
402 |
} |
759423706 tracing/kprobes: ... |
403 |
#if defined(CONFIG_DYNAMIC_FTRACE) && \ |
45408c4f9 tracing: kprobes:... |
404 |
!defined(CONFIG_KPROBE_EVENTS_ON_NOTRACE) |
c7411a1a1 tracing/kprobe: C... |
405 |
static bool __within_notrace_func(unsigned long addr) |
45408c4f9 tracing: kprobes:... |
406 |
{ |
c7411a1a1 tracing/kprobe: C... |
407 |
unsigned long offset, size; |
45408c4f9 tracing: kprobes:... |
408 |
|
6bc6c77cf tracing/kprobes: ... |
409 410 |
if (!addr || !kallsyms_lookup_size_offset(addr, &size, &offset)) return false; |
45408c4f9 tracing: kprobes:... |
411 |
|
9161a864f tracing/kprobes: ... |
412 413 414 415 416 417 418 419 |
/* Get the entry address of the target function */ addr -= offset; /* * Since ftrace_location_range() does inclusive range check, we need * to subtract 1 byte from the end address. */ return !ftrace_location_range(addr, addr + size - 1); |
45408c4f9 tracing: kprobes:... |
420 |
} |
c7411a1a1 tracing/kprobe: C... |
421 422 423 |
static bool within_notrace_func(struct trace_kprobe *tk) { |
dcbd21c9f tracing/kprobes: ... |
424 |
unsigned long addr = trace_kprobe_address(tk); |
c7411a1a1 tracing/kprobe: C... |
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
char symname[KSYM_NAME_LEN], *p; if (!__within_notrace_func(addr)) return false; /* Check if the address is on a suffixed-symbol */ if (!lookup_symbol_name(addr, symname)) { p = strchr(symname, '.'); if (!p) return true; *p = '\0'; addr = (unsigned long)kprobe_lookup_name(symname, 0); if (addr) return __within_notrace_func(addr); } return true; } |
45408c4f9 tracing: kprobes:... |
443 444 445 |
#else #define within_notrace_func(tk) (false) #endif |
614243181 tracing/kprobes: ... |
446 |
/* Internal register function - just handle k*probes and flags */ |
c31ffb3ff tracing/kprobes: ... |
447 |
static int __register_trace_kprobe(struct trace_kprobe *tk) |
413d37d1e tracing: Add kpro... |
448 |
{ |
a6682814f tracing/kprobes: ... |
449 |
int i, ret; |
614243181 tracing/kprobes: ... |
450 |
|
a94549dd8 lockdown: Lock do... |
451 452 453 |
ret = security_locked_down(LOCKDOWN_KPROBES); if (ret) return ret; |
715fa2fd4 tracing/kprobe: C... |
454 |
if (trace_kprobe_is_registered(tk)) |
614243181 tracing/kprobes: ... |
455 |
return -EINVAL; |
45408c4f9 tracing: kprobes:... |
456 457 458 459 460 461 |
if (within_notrace_func(tk)) { pr_warn("Could not probe notrace function %s ", trace_kprobe_symbol(tk)); return -EINVAL; } |
a6682814f tracing/kprobes: ... |
462 463 464 465 466 |
for (i = 0; i < tk->tp.nr_args; i++) { ret = traceprobe_update_arg(&tk->tp.args[i]); if (ret) return ret; } |
614243181 tracing/kprobes: ... |
467 |
/* Set/clear disabled flag according to tp->flag */ |
c31ffb3ff tracing/kprobes: ... |
468 469 |
if (trace_probe_is_enabled(&tk->tp)) tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; |
614243181 tracing/kprobes: ... |
470 |
else |
c31ffb3ff tracing/kprobes: ... |
471 |
tk->rp.kp.flags |= KPROBE_FLAG_DISABLED; |
614243181 tracing/kprobes: ... |
472 |
|
c31ffb3ff tracing/kprobes: ... |
473 474 |
if (trace_kprobe_is_return(tk)) ret = register_kretprobe(&tk->rp); |
413d37d1e tracing: Add kpro... |
475 |
else |
c31ffb3ff tracing/kprobes: ... |
476 |
ret = register_kprobe(&tk->rp.kp); |
614243181 tracing/kprobes: ... |
477 |
|
614243181 tracing/kprobes: ... |
478 479 480 481 |
return ret; } /* Internal unregister function - just handle k*probes and flags */ |
c31ffb3ff tracing/kprobes: ... |
482 |
static void __unregister_trace_kprobe(struct trace_kprobe *tk) |
614243181 tracing/kprobes: ... |
483 |
{ |
715fa2fd4 tracing/kprobe: C... |
484 |
if (trace_kprobe_is_registered(tk)) { |
c31ffb3ff tracing/kprobes: ... |
485 486 |
if (trace_kprobe_is_return(tk)) unregister_kretprobe(&tk->rp); |
614243181 tracing/kprobes: ... |
487 |
else |
c31ffb3ff tracing/kprobes: ... |
488 |
unregister_kprobe(&tk->rp.kp); |
715fa2fd4 tracing/kprobe: C... |
489 490 491 |
/* Cleanup kprobe for reuse and mark it unregistered */ INIT_HLIST_NODE(&tk->rp.kp.hlist); INIT_LIST_HEAD(&tk->rp.kp.list); |
c31ffb3ff tracing/kprobes: ... |
492 493 |
if (tk->rp.kp.symbol_name) tk->rp.kp.addr = NULL; |
614243181 tracing/kprobes: ... |
494 495 |
} } |
6212dd296 tracing/kprobes: ... |
496 |
/* Unregister a trace_probe and probe_event */ |
c31ffb3ff tracing/kprobes: ... |
497 |
static int unregister_trace_kprobe(struct trace_kprobe *tk) |
614243181 tracing/kprobes: ... |
498 |
{ |
ca89bc071 tracing/kprobe: A... |
499 500 501 |
/* If other probes are on the event, just unregister kprobe */ if (trace_probe_has_sibling(&tk->tp)) goto unreg; |
02ca1521a ftrace/kprobes: F... |
502 |
/* Enabled event can not be unregistered */ |
c31ffb3ff tracing/kprobes: ... |
503 |
if (trace_probe_is_enabled(&tk->tp)) |
02ca1521a ftrace/kprobes: F... |
504 |
return -EBUSY; |
40c325926 tracing/kprobes: ... |
505 |
/* Will fail if probe is being used by ftrace or perf */ |
c31ffb3ff tracing/kprobes: ... |
506 |
if (unregister_kprobe_event(tk)) |
40c325926 tracing/kprobes: ... |
507 |
return -EBUSY; |
ca89bc071 tracing/kprobe: A... |
508 |
unreg: |
c31ffb3ff tracing/kprobes: ... |
509 |
__unregister_trace_kprobe(tk); |
6212dd296 tracing/kprobes: ... |
510 |
dyn_event_remove(&tk->devent); |
ca89bc071 tracing/kprobe: A... |
511 |
trace_probe_unlink(&tk->tp); |
02ca1521a ftrace/kprobes: F... |
512 513 |
return 0; |
413d37d1e tracing: Add kpro... |
514 |
} |
fe60b0ce8 tracing/probe: Re... |
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
static bool trace_kprobe_has_same_kprobe(struct trace_kprobe *orig, struct trace_kprobe *comp) { struct trace_probe_event *tpe = orig->tp.event; struct trace_probe *pos; int i; list_for_each_entry(pos, &tpe->probes, list) { orig = container_of(pos, struct trace_kprobe, tp); if (strcmp(trace_kprobe_symbol(orig), trace_kprobe_symbol(comp)) || trace_kprobe_offset(orig) != trace_kprobe_offset(comp)) continue; /* * trace_probe_compare_arg_type() ensured that nr_args and * each argument name and type are same. Let's compare comm. */ for (i = 0; i < orig->tp.nr_args; i++) { if (strcmp(orig->tp.args[i].comm, comp->tp.args[i].comm)) |
f8d7ab2bd tracing/probe: Fi... |
536 |
break; |
fe60b0ce8 tracing/probe: Re... |
537 |
} |
f8d7ab2bd tracing/probe: Fi... |
538 539 |
if (i == orig->tp.nr_args) return true; |
fe60b0ce8 tracing/probe: Re... |
540 541 542 543 |
} return false; } |
ca89bc071 tracing/kprobe: A... |
544 545 546 |
static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprobe *to) { int ret; |
fe60b0ce8 tracing/probe: Re... |
547 548 549 550 551 552 553 554 555 556 557 558 |
ret = trace_probe_compare_arg_type(&tk->tp, &to->tp); if (ret) { /* Note that argument starts index = 2 */ trace_probe_log_set_index(ret + 1); trace_probe_log_err(0, DIFF_ARG_TYPE); return -EEXIST; } if (trace_kprobe_has_same_kprobe(to, tk)) { trace_probe_log_set_index(0); trace_probe_log_err(0, SAME_PROBE); return -EEXIST; } |
ca89bc071 tracing/kprobe: A... |
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
/* Append to existing event */ ret = trace_probe_append(&tk->tp, &to->tp); if (ret) return ret; /* Register k*probe */ ret = __register_trace_kprobe(tk); if (ret == -ENOENT && !trace_kprobe_module_exist(tk)) { pr_warn("This probe might be able to register after target module is loaded. Continue. "); ret = 0; } if (ret) trace_probe_unlink(&tk->tp); else dyn_event_add(&tk->devent); return ret; } |
413d37d1e tracing: Add kpro... |
579 |
/* Register a trace_probe and probe_event */ |
c31ffb3ff tracing/kprobes: ... |
580 |
static int register_trace_kprobe(struct trace_kprobe *tk) |
413d37d1e tracing: Add kpro... |
581 |
{ |
c31ffb3ff tracing/kprobes: ... |
582 |
struct trace_kprobe *old_tk; |
413d37d1e tracing: Add kpro... |
583 |
int ret; |
6212dd296 tracing/kprobes: ... |
584 |
mutex_lock(&event_mutex); |
413d37d1e tracing: Add kpro... |
585 |
|
b55ce203a tracing/probe: Ad... |
586 587 |
old_tk = find_trace_kprobe(trace_probe_name(&tk->tp), trace_probe_group_name(&tk->tp)); |
c31ffb3ff tracing/kprobes: ... |
588 |
if (old_tk) { |
ca89bc071 tracing/kprobe: A... |
589 590 591 592 593 |
if (trace_kprobe_is_return(tk) != trace_kprobe_is_return(old_tk)) { trace_probe_log_set_index(0); trace_probe_log_err(0, DIFF_PROBE_TYPE); ret = -EEXIST; } else { |
fe60b0ce8 tracing/probe: Re... |
594 |
ret = append_trace_kprobe(tk, old_tk); |
ca89bc071 tracing/kprobe: A... |
595 596 |
} goto end; |
2d5e067ed tracing/kprobes: ... |
597 |
} |
614243181 tracing/kprobes: ... |
598 599 |
/* Register new event */ |
c31ffb3ff tracing/kprobes: ... |
600 |
ret = register_kprobe_event(tk); |
2d5e067ed tracing/kprobes: ... |
601 |
if (ret) { |
a395d6a7e kernel/...: conve... |
602 603 |
pr_warn("Failed to register probe event(%d) ", ret); |
2d5e067ed tracing/kprobes: ... |
604 605 |
goto end; } |
614243181 tracing/kprobes: ... |
606 |
/* Register k*probe */ |
c31ffb3ff tracing/kprobes: ... |
607 |
ret = __register_trace_kprobe(tk); |
59158ec4a tracing/kprobes: ... |
608 609 610 611 612 |
if (ret == -ENOENT && !trace_kprobe_module_exist(tk)) { pr_warn("This probe might be able to register after target module is loaded. Continue. "); ret = 0; } |
614243181 tracing/kprobes: ... |
613 |
if (ret < 0) |
c31ffb3ff tracing/kprobes: ... |
614 |
unregister_kprobe_event(tk); |
614243181 tracing/kprobes: ... |
615 |
else |
6212dd296 tracing/kprobes: ... |
616 |
dyn_event_add(&tk->devent); |
614243181 tracing/kprobes: ... |
617 |
|
413d37d1e tracing: Add kpro... |
618 |
end: |
6212dd296 tracing/kprobes: ... |
619 |
mutex_unlock(&event_mutex); |
413d37d1e tracing: Add kpro... |
620 621 |
return ret; } |
614243181 tracing/kprobes: ... |
622 |
/* Module notifier call back, checking event on the module */ |
c31ffb3ff tracing/kprobes: ... |
623 |
static int trace_kprobe_module_callback(struct notifier_block *nb, |
614243181 tracing/kprobes: ... |
624 625 626 |
unsigned long val, void *data) { struct module *mod = data; |
6212dd296 tracing/kprobes: ... |
627 |
struct dyn_event *pos; |
c31ffb3ff tracing/kprobes: ... |
628 |
struct trace_kprobe *tk; |
614243181 tracing/kprobes: ... |
629 630 631 632 633 634 |
int ret; if (val != MODULE_STATE_COMING) return NOTIFY_DONE; /* Update probes on coming module */ |
6212dd296 tracing/kprobes: ... |
635 636 |
mutex_lock(&event_mutex); for_each_trace_kprobe(tk, pos) { |
c31ffb3ff tracing/kprobes: ... |
637 |
if (trace_kprobe_within_module(tk, mod)) { |
02ca1521a ftrace/kprobes: F... |
638 |
/* Don't need to check busy - this should have gone. */ |
c31ffb3ff tracing/kprobes: ... |
639 640 |
__unregister_trace_kprobe(tk); ret = __register_trace_kprobe(tk); |
614243181 tracing/kprobes: ... |
641 |
if (ret) |
a395d6a7e kernel/...: conve... |
642 643 |
pr_warn("Failed to re-register probe %s on %s: %d ", |
b55ce203a tracing/probe: Ad... |
644 |
trace_probe_name(&tk->tp), |
f3d364266 kprobes: Use modu... |
645 |
module_name(mod), ret); |
614243181 tracing/kprobes: ... |
646 647 |
} } |
6212dd296 tracing/kprobes: ... |
648 |
mutex_unlock(&event_mutex); |
614243181 tracing/kprobes: ... |
649 650 651 |
return NOTIFY_DONE; } |
c31ffb3ff tracing/kprobes: ... |
652 653 |
static struct notifier_block trace_kprobe_module_nb = { .notifier_call = trace_kprobe_module_callback, |
614243181 tracing/kprobes: ... |
654 655 |
.priority = 1 /* Invoked after kprobe module callback */ }; |
fca18a47c trace/kprobes: Sa... |
656 657 658 659 660 661 662 |
/* Convert certain expected symbols into '_' when generating event names */ static inline void sanitize_event_name(char *name) { while (*name++ != '\0') if (*name == ':' || *name == '.') *name = '_'; } |
6212dd296 tracing/kprobes: ... |
663 |
static int trace_kprobe_create(int argc, const char *argv[]) |
413d37d1e tracing: Add kpro... |
664 665 666 |
{ /* * Argument syntax: |
696ced4fb tracing/kprobes: ... |
667 668 669 670 |
* - Add kprobe: * p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS] * - Add kretprobe: * r[MAXACTIVE][:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS] |
4725cd899 tracing/kprobes: ... |
671 672 673 |
* Or * p:[GRP/]EVENT] [MOD:]KSYM[+0]%return [FETCHARGS] * |
413d37d1e tracing: Add kpro... |
674 |
* Fetch args: |
2e06ff638 tracing/kprobes: ... |
675 676 677 |
* $retval : fetch return value * $stack : fetch stack address * $stackN : fetch Nth of stack (N:0-) |
35abb67de tracing: expose c... |
678 |
* $comm : fetch current task comm |
413d37d1e tracing: Add kpro... |
679 680 681 |
* @ADDR : fetch memory at ADDR (ADDR should be in kernel) * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol) * %REG : fetch register REG |
93ccae7a2 tracing/kprobes: ... |
682 |
* Dereferencing memory fetch: |
413d37d1e tracing: Add kpro... |
683 |
* +|-offs(ARG) : fetch memory at ARG +|- offs address. |
eca0d916f tracing/kprobes: ... |
684 685 |
* Alias name of args: * NAME=FETCHARG : set NAME as alias of FETCHARG. |
93ccae7a2 tracing/kprobes: ... |
686 687 |
* Type of args: * FETCHARG:TYPE : use TYPE instead of unsigned long. |
413d37d1e tracing: Add kpro... |
688 |
*/ |
ab105a4fb tracing: Use trac... |
689 |
struct trace_kprobe *tk = NULL; |
6212dd296 tracing/kprobes: ... |
690 691 692 693 |
int i, len, ret = 0; bool is_return = false; char *symbol = NULL, *tmp = NULL; const char *event = NULL, *group = KPROBE_EVENT_SYSTEM; |
696ced4fb tracing/kprobes: ... |
694 |
int maxactive = 0; |
c5d343b6b tracing: probeeve... |
695 |
long offset = 0; |
413d37d1e tracing: Add kpro... |
696 |
void *addr = NULL; |
4a846b443 tracing/kprobes: ... |
697 |
char buf[MAX_EVENT_NAME_LEN]; |
a1303af5d tracing: probeeve... |
698 |
unsigned int flags = TPARG_FL_KERNEL; |
413d37d1e tracing: Add kpro... |
699 |
|
8b05a3a75 tracing/kprobes: ... |
700 701 |
switch (argv[0][0]) { case 'r': |
3a6b76661 tracing: Modify i... |
702 |
is_return = true; |
8b05a3a75 tracing/kprobes: ... |
703 704 705 706 707 708 709 |
break; case 'p': break; default: return -ECANCELED; } if (argc < 2) |
6212dd296 tracing/kprobes: ... |
710 |
return -ECANCELED; |
413d37d1e tracing: Add kpro... |
711 |
|
ab105a4fb tracing: Use trac... |
712 |
trace_probe_log_init("trace_kprobe", argc, argv); |
696ced4fb tracing/kprobes: ... |
713 |
event = strchr(&argv[0][1], ':'); |
6212dd296 tracing/kprobes: ... |
714 |
if (event) |
696ced4fb tracing/kprobes: ... |
715 |
event++; |
6212dd296 tracing/kprobes: ... |
716 |
|
287c038c0 tracing/probe: Ch... |
717 718 |
if (isdigit(argv[0][1])) { if (!is_return) { |
ab105a4fb tracing: Use trac... |
719 720 |
trace_probe_log_err(1, MAXACT_NO_KPROBE); goto parse_error; |
287c038c0 tracing/probe: Ch... |
721 |
} |
6212dd296 tracing/kprobes: ... |
722 723 724 725 |
if (event) len = event - &argv[0][1] - 1; else len = strlen(&argv[0][1]); |
ab105a4fb tracing: Use trac... |
726 727 728 729 |
if (len > MAX_EVENT_NAME_LEN - 1) { trace_probe_log_err(1, BAD_MAXACT); goto parse_error; } |
6212dd296 tracing/kprobes: ... |
730 731 732 |
memcpy(buf, &argv[0][1], len); buf[len] = '\0'; ret = kstrtouint(buf, 0, &maxactive); |
287c038c0 tracing/probe: Ch... |
733 |
if (ret || !maxactive) { |
ab105a4fb tracing: Use trac... |
734 735 |
trace_probe_log_err(1, BAD_MAXACT); goto parse_error; |
696ced4fb tracing/kprobes: ... |
736 737 738 739 740 |
} /* kretprobes instances are iterated over via a list. The * maximum should stay reasonable. */ if (maxactive > KRETPROBE_MAXACTIVE_MAX) { |
ab105a4fb tracing: Use trac... |
741 742 |
trace_probe_log_err(1, MAXACT_TOO_BIG); goto parse_error; |
696ced4fb tracing/kprobes: ... |
743 744 |
} } |
9e52b3256 tracing/kprobes: ... |
745 746 747 |
/* try to parse an address. if that fails, try to read the * input as a symbol. */ if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) { |
ab105a4fb tracing: Use trac... |
748 |
trace_probe_log_set_index(1); |
6212dd296 tracing/kprobes: ... |
749 |
/* Check whether uprobe event specified */ |
ab105a4fb tracing: Use trac... |
750 751 752 753 |
if (strchr(argv[1], '/') && strchr(argv[1], ':')) { ret = -ECANCELED; goto error; } |
413d37d1e tracing: Add kpro... |
754 |
/* a symbol specified */ |
6212dd296 tracing/kprobes: ... |
755 756 757 |
symbol = kstrdup(argv[1], GFP_KERNEL); if (!symbol) return -ENOMEM; |
4725cd899 tracing/kprobes: ... |
758 759 760 761 762 763 764 765 766 767 768 |
tmp = strchr(symbol, '%'); if (tmp) { if (!strcmp(tmp, "%return")) { *tmp = '\0'; is_return = true; } else { trace_probe_log_err(tmp - symbol, BAD_ADDR_SUFFIX); goto parse_error; } } |
413d37d1e tracing: Add kpro... |
769 |
/* TODO: support .init module functions */ |
8ab83f564 tracing: Extract ... |
770 |
ret = traceprobe_split_symbol_offset(symbol, &offset); |
c5d343b6b tracing: probeeve... |
771 |
if (ret || offset < 0 || offset > UINT_MAX) { |
ab105a4fb tracing: Use trac... |
772 773 |
trace_probe_log_err(0, BAD_PROBE_ADDR); goto parse_error; |
e63cc2397 tracing/kprobes: ... |
774 |
} |
4725cd899 tracing/kprobes: ... |
775 776 |
if (is_return) flags |= TPARG_FL_RETURN; |
a1303af5d tracing: probeeve... |
777 778 779 |
if (kprobe_on_func_entry(NULL, symbol, offset)) flags |= TPARG_FL_FENTRY; if (offset && is_return && !(flags & TPARG_FL_FENTRY)) { |
ab105a4fb tracing: Use trac... |
780 781 |
trace_probe_log_err(0, BAD_RETPROBE); goto parse_error; |
e63cc2397 tracing/kprobes: ... |
782 |
} |
413d37d1e tracing: Add kpro... |
783 |
} |
ab105a4fb tracing: Use trac... |
784 |
trace_probe_log_set_index(0); |
6212dd296 tracing/kprobes: ... |
785 |
if (event) { |
ab105a4fb tracing: Use trac... |
786 787 |
ret = traceprobe_parse_event_name(&event, &group, buf, event - argv[0]); |
6212dd296 tracing/kprobes: ... |
788 |
if (ret) |
ab105a4fb tracing: Use trac... |
789 |
goto parse_error; |
6212dd296 tracing/kprobes: ... |
790 |
} else { |
4263565d4 tracing: Generate... |
791 |
/* Make a new event name */ |
4263565d4 tracing: Generate... |
792 |
if (symbol) |
6f3cf4404 kprobe-tracer: Ch... |
793 |
snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_%ld", |
4263565d4 tracing: Generate... |
794 795 |
is_return ? 'r' : 'p', symbol, offset); else |
6f3cf4404 kprobe-tracer: Ch... |
796 |
snprintf(buf, MAX_EVENT_NAME_LEN, "%c_0x%p", |
4263565d4 tracing: Generate... |
797 |
is_return ? 'r' : 'p', addr); |
fca18a47c trace/kprobes: Sa... |
798 |
sanitize_event_name(buf); |
4a846b443 tracing/kprobes: ... |
799 800 |
event = buf; } |
6212dd296 tracing/kprobes: ... |
801 802 |
/* setup a probe */ |
696ced4fb tracing/kprobes: ... |
803 |
tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive, |
ab105a4fb tracing: Use trac... |
804 |
argc - 2, is_return); |
c31ffb3ff tracing/kprobes: ... |
805 |
if (IS_ERR(tk)) { |
6212dd296 tracing/kprobes: ... |
806 |
ret = PTR_ERR(tk); |
ab105a4fb tracing: Use trac... |
807 |
/* This must return -ENOMEM, else there is a bug */ |
a039480e9 tracing/probe: Ve... |
808 |
WARN_ON_ONCE(ret != -ENOMEM); |
ab105a4fb tracing: Use trac... |
809 |
goto out; /* We know tk is not allocated */ |
e63cc2397 tracing/kprobes: ... |
810 |
} |
ab105a4fb tracing: Use trac... |
811 |
argc -= 2; argv += 2; |
413d37d1e tracing: Add kpro... |
812 |
|
413d37d1e tracing: Add kpro... |
813 |
/* parse arguments */ |
a82378d88 tracing: Kprobe-t... |
814 |
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { |
6212dd296 tracing/kprobes: ... |
815 816 |
tmp = kstrdup(argv[i], GFP_KERNEL); if (!tmp) { |
ba8665d7d trace_kprobes: Fi... |
817 |
ret = -ENOMEM; |
413d37d1e tracing: Add kpro... |
818 819 |
goto error; } |
da34634fd tracing/kprobe: F... |
820 |
|
ab105a4fb tracing: Use trac... |
821 |
trace_probe_log_set_index(i + 2); |
6212dd296 tracing/kprobes: ... |
822 823 |
ret = traceprobe_parse_probe_arg(&tk->tp, i, tmp, flags); kfree(tmp); |
d00bbea94 tracing: Integrat... |
824 |
if (ret) |
ab105a4fb tracing: Use trac... |
825 |
goto error; /* This can be -ENOMEM */ |
413d37d1e tracing: Add kpro... |
826 |
} |
413d37d1e tracing: Add kpro... |
827 |
|
f730e0f2d tracing/kprobe: S... |
828 829 830 |
ret = traceprobe_set_print_fmt(&tk->tp, is_return); if (ret < 0) goto error; |
c31ffb3ff tracing/kprobes: ... |
831 |
ret = register_trace_kprobe(tk); |
ab105a4fb tracing: Use trac... |
832 833 834 835 836 837 |
if (ret) { trace_probe_log_set_index(1); if (ret == -EILSEQ) trace_probe_log_err(0, BAD_INSN_BNDRY); else if (ret == -ENOENT) trace_probe_log_err(0, BAD_PROBE_ADDR); |
ca89bc071 tracing/kprobe: A... |
838 |
else if (ret != -ENOMEM && ret != -EEXIST) |
ab105a4fb tracing: Use trac... |
839 |
trace_probe_log_err(0, FAIL_REG_PROBE); |
413d37d1e tracing: Add kpro... |
840 |
goto error; |
ab105a4fb tracing: Use trac... |
841 |
} |
6212dd296 tracing/kprobes: ... |
842 |
out: |
ab105a4fb tracing: Use trac... |
843 |
trace_probe_log_clear(); |
6212dd296 tracing/kprobes: ... |
844 845 |
kfree(symbol); return ret; |
413d37d1e tracing: Add kpro... |
846 |
|
ab105a4fb tracing: Use trac... |
847 848 |
parse_error: ret = -EINVAL; |
413d37d1e tracing: Add kpro... |
849 |
error: |
c31ffb3ff tracing/kprobes: ... |
850 |
free_trace_kprobe(tk); |
6212dd296 tracing/kprobes: ... |
851 |
goto out; |
413d37d1e tracing: Add kpro... |
852 |
} |
6212dd296 tracing/kprobes: ... |
853 |
static int create_or_delete_trace_kprobe(int argc, char **argv) |
413d37d1e tracing: Add kpro... |
854 |
{ |
6212dd296 tracing/kprobes: ... |
855 |
int ret; |
02ca1521a ftrace/kprobes: F... |
856 |
|
6212dd296 tracing/kprobes: ... |
857 858 |
if (argv[0][0] == '-') return dyn_event_release(argc, argv, &trace_kprobe_ops); |
413d37d1e tracing: Add kpro... |
859 |
|
6212dd296 tracing/kprobes: ... |
860 861 |
ret = trace_kprobe_create(argc, (const char **)argv); return ret == -ECANCELED ? -EINVAL : ret; |
413d37d1e tracing: Add kpro... |
862 |
} |
29a154810 tracing: Change t... |
863 |
static int trace_kprobe_run_command(struct dynevent_cmd *cmd) |
2a588dd1d tracing: Add kpro... |
864 |
{ |
2b90927c7 tracing: Use seq_... |
865 |
return trace_run_command(cmd->seq.buffer, create_or_delete_trace_kprobe); |
2a588dd1d tracing: Add kpro... |
866 867 868 869 870 871 872 873 874 875 876 877 878 879 |
} /** * kprobe_event_cmd_init - Initialize a kprobe event command object * @cmd: A pointer to the dynevent_cmd struct representing the new event * @buf: A pointer to the buffer used to build the command * @maxlen: The length of the buffer passed in @buf * * Initialize a synthetic event command object. Use this before * calling any of the other kprobe_event functions. */ void kprobe_event_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen) { dynevent_cmd_init(cmd, buf, maxlen, DYNEVENT_TYPE_KPROBE, |
29a154810 tracing: Change t... |
880 |
trace_kprobe_run_command); |
2a588dd1d tracing: Add kpro... |
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 |
} EXPORT_SYMBOL_GPL(kprobe_event_cmd_init); /** * __kprobe_event_gen_cmd_start - Generate a kprobe event command from arg list * @cmd: A pointer to the dynevent_cmd struct representing the new event * @name: The name of the kprobe event * @loc: The location of the kprobe event * @kretprobe: Is this a return probe? * @args: Variable number of arg (pairs), one pair for each field * * NOTE: Users normally won't want to call this function directly, but * rather use the kprobe_event_gen_cmd_start() wrapper, which automatically * adds a NULL to the end of the arg list. If this function is used * directly, make sure the last arg in the variable arg list is NULL. * * Generate a kprobe event command to be executed by * kprobe_event_gen_cmd_end(). This function can be used to generate the * complete command or only the first part of it; in the latter case, * kprobe_event_add_fields() can be used to add more fields following this. * |
5b4dcd2d2 tracing/kprobes: ... |
902 903 904 |
* Unlikely the synth_event_gen_cmd_start(), @loc must be specified. This * returns -EINVAL if @loc == NULL. * |
2a588dd1d tracing: Add kpro... |
905 906 907 908 909 910 911 912 913 914 915 916 |
* Return: 0 if successful, error otherwise. */ int __kprobe_event_gen_cmd_start(struct dynevent_cmd *cmd, bool kretprobe, const char *name, const char *loc, ...) { char buf[MAX_EVENT_NAME_LEN]; struct dynevent_arg arg; va_list args; int ret; if (cmd->type != DYNEVENT_TYPE_KPROBE) return -EINVAL; |
5b4dcd2d2 tracing/kprobes: ... |
917 918 |
if (!loc) return -EINVAL; |
2a588dd1d tracing: Add kpro... |
919 920 921 922 923 924 925 926 |
if (kretprobe) snprintf(buf, MAX_EVENT_NAME_LEN, "r:kprobes/%s", name); else snprintf(buf, MAX_EVENT_NAME_LEN, "p:kprobes/%s", name); ret = dynevent_str_add(cmd, buf); if (ret) return ret; |
74403b6c5 tracing: Remove c... |
927 |
dynevent_arg_init(&arg, 0); |
2a588dd1d tracing: Add kpro... |
928 |
arg.str = loc; |
74403b6c5 tracing: Remove c... |
929 |
ret = dynevent_arg_add(cmd, &arg, NULL); |
2a588dd1d tracing: Add kpro... |
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 |
if (ret) return ret; va_start(args, loc); for (;;) { const char *field; field = va_arg(args, const char *); if (!field) break; if (++cmd->n_fields > MAX_TRACE_ARGS) { ret = -EINVAL; break; } arg.str = field; |
74403b6c5 tracing: Remove c... |
947 |
ret = dynevent_arg_add(cmd, &arg, NULL); |
2a588dd1d tracing: Add kpro... |
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 |
if (ret) break; } va_end(args); return ret; } EXPORT_SYMBOL_GPL(__kprobe_event_gen_cmd_start); /** * __kprobe_event_add_fields - Add probe fields to a kprobe command from arg list * @cmd: A pointer to the dynevent_cmd struct representing the new event * @args: Variable number of arg (pairs), one pair for each field * * NOTE: Users normally won't want to call this function directly, but * rather use the kprobe_event_add_fields() wrapper, which * automatically adds a NULL to the end of the arg list. If this * function is used directly, make sure the last arg in the variable * arg list is NULL. * * Add probe fields to an existing kprobe command using a variable * list of args. Fields are added in the same order they're listed. * * Return: 0 if successful, error otherwise. */ int __kprobe_event_add_fields(struct dynevent_cmd *cmd, ...) { struct dynevent_arg arg; va_list args; |
10f129cb5 tracing/kprobe: F... |
977 |
int ret = 0; |
2a588dd1d tracing: Add kpro... |
978 979 980 |
if (cmd->type != DYNEVENT_TYPE_KPROBE) return -EINVAL; |
74403b6c5 tracing: Remove c... |
981 |
dynevent_arg_init(&arg, 0); |
2a588dd1d tracing: Add kpro... |
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
va_start(args, cmd); for (;;) { const char *field; field = va_arg(args, const char *); if (!field) break; if (++cmd->n_fields > MAX_TRACE_ARGS) { ret = -EINVAL; break; } arg.str = field; |
74403b6c5 tracing: Remove c... |
997 |
ret = dynevent_arg_add(cmd, &arg, NULL); |
2a588dd1d tracing: Add kpro... |
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
if (ret) break; } va_end(args); return ret; } EXPORT_SYMBOL_GPL(__kprobe_event_add_fields); /** * kprobe_event_delete - Delete a kprobe event * @name: The name of the kprobe event to delete * * Delete a kprobe event with the give @name from kernel code rather * than directly from the command line. * * Return: 0 if successful, error otherwise. */ int kprobe_event_delete(const char *name) { char buf[MAX_EVENT_NAME_LEN]; snprintf(buf, MAX_EVENT_NAME_LEN, "-:%s", name); return trace_run_command(buf, create_or_delete_trace_kprobe); } EXPORT_SYMBOL_GPL(kprobe_event_delete); |
6212dd296 tracing/kprobes: ... |
1025 |
static int trace_kprobe_release(struct dyn_event *ev) |
413d37d1e tracing: Add kpro... |
1026 |
{ |
6212dd296 tracing/kprobes: ... |
1027 1028 |
struct trace_kprobe *tk = to_trace_kprobe(ev); int ret = unregister_trace_kprobe(tk); |
413d37d1e tracing: Add kpro... |
1029 |
|
6212dd296 tracing/kprobes: ... |
1030 1031 1032 |
if (!ret) free_trace_kprobe(tk); return ret; |
413d37d1e tracing: Add kpro... |
1033 |
} |
6212dd296 tracing/kprobes: ... |
1034 |
static int trace_kprobe_show(struct seq_file *m, struct dyn_event *ev) |
413d37d1e tracing: Add kpro... |
1035 |
{ |
6212dd296 tracing/kprobes: ... |
1036 |
struct trace_kprobe *tk = to_trace_kprobe(ev); |
93ccae7a2 tracing/kprobes: ... |
1037 |
int i; |
413d37d1e tracing: Add kpro... |
1038 |
|
fa6f0cc75 tracing: Replace ... |
1039 |
seq_putc(m, trace_kprobe_is_return(tk) ? 'r' : 'p'); |
6a13a0d7b ftrace/kprobe: Sh... |
1040 1041 |
if (trace_kprobe_is_return(tk) && tk->rp.maxactive) seq_printf(m, "%d", tk->rp.maxactive); |
b55ce203a tracing/probe: Ad... |
1042 1043 |
seq_printf(m, ":%s/%s", trace_probe_group_name(&tk->tp), trace_probe_name(&tk->tp)); |
413d37d1e tracing: Add kpro... |
1044 |
|
c31ffb3ff tracing/kprobes: ... |
1045 1046 1047 1048 1049 |
if (!tk->symbol) seq_printf(m, " 0x%p", tk->rp.kp.addr); else if (tk->rp.kp.offset) seq_printf(m, " %s+%u", trace_kprobe_symbol(tk), tk->rp.kp.offset); |
413d37d1e tracing: Add kpro... |
1050 |
else |
c31ffb3ff tracing/kprobes: ... |
1051 |
seq_printf(m, " %s", trace_kprobe_symbol(tk)); |
413d37d1e tracing: Add kpro... |
1052 |
|
c31ffb3ff tracing/kprobes: ... |
1053 1054 |
for (i = 0; i < tk->tp.nr_args; i++) seq_printf(m, " %s=%s", tk->tp.args[i].name, tk->tp.args[i].comm); |
fa6f0cc75 tracing: Replace ... |
1055 1056 |
seq_putc(m, ' '); |
93ccae7a2 tracing/kprobes: ... |
1057 |
|
413d37d1e tracing: Add kpro... |
1058 1059 |
return 0; } |
6212dd296 tracing/kprobes: ... |
1060 1061 1062 1063 1064 1065 1066 1067 1068 |
static int probes_seq_show(struct seq_file *m, void *v) { struct dyn_event *ev = v; if (!is_trace_kprobe(ev)) return 0; return trace_kprobe_show(m, ev); } |
413d37d1e tracing: Add kpro... |
1069 |
static const struct seq_operations probes_seq_op = { |
6212dd296 tracing/kprobes: ... |
1070 1071 1072 |
.start = dyn_event_seq_start, .next = dyn_event_seq_next, .stop = dyn_event_seq_stop, |
413d37d1e tracing: Add kpro... |
1073 1074 1075 1076 1077 |
.show = probes_seq_show }; static int probes_open(struct inode *inode, struct file *file) { |
02ca1521a ftrace/kprobes: F... |
1078 |
int ret; |
17911ff38 tracing: Add lock... |
1079 1080 1081 |
ret = security_locked_down(LOCKDOWN_TRACEFS); if (ret) return ret; |
02ca1521a ftrace/kprobes: F... |
1082 |
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { |
6212dd296 tracing/kprobes: ... |
1083 |
ret = dyn_events_release_all(&trace_kprobe_ops); |
02ca1521a ftrace/kprobes: F... |
1084 1085 1086 |
if (ret < 0) return ret; } |
413d37d1e tracing: Add kpro... |
1087 1088 1089 |
return seq_open(file, &probes_seq_op); } |
413d37d1e tracing: Add kpro... |
1090 1091 1092 |
static ssize_t probes_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { |
7e465baa8 tracing: Make tra... |
1093 |
return trace_parse_run_command(file, buffer, count, ppos, |
6212dd296 tracing/kprobes: ... |
1094 |
create_or_delete_trace_kprobe); |
413d37d1e tracing: Add kpro... |
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 |
} static const struct file_operations kprobe_events_ops = { .owner = THIS_MODULE, .open = probes_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .write = probes_write, }; |
cd7e7bd5e tracing: Add kpro... |
1105 1106 1107 |
/* Probes profiling interfaces */ static int probes_profile_seq_show(struct seq_file *m, void *v) { |
6212dd296 tracing/kprobes: ... |
1108 1109 |
struct dyn_event *ev = v; struct trace_kprobe *tk; |
cd7e7bd5e tracing: Add kpro... |
1110 |
|
6212dd296 tracing/kprobes: ... |
1111 1112 |
if (!is_trace_kprobe(ev)) return 0; |
cd7e7bd5e tracing: Add kpro... |
1113 |
|
6212dd296 tracing/kprobes: ... |
1114 |
tk = to_trace_kprobe(ev); |
de7b29739 tracepoint: Use s... |
1115 1116 |
seq_printf(m, " %-44s %15lu %15lu ", |
b55ce203a tracing/probe: Ad... |
1117 |
trace_probe_name(&tk->tp), |
f18f97ac4 tracing/kprobes: ... |
1118 |
trace_kprobe_nhit(tk), |
c31ffb3ff tracing/kprobes: ... |
1119 |
tk->rp.kp.nmissed); |
cd7e7bd5e tracing: Add kpro... |
1120 1121 1122 1123 1124 |
return 0; } static const struct seq_operations profile_seq_op = { |
6212dd296 tracing/kprobes: ... |
1125 1126 1127 |
.start = dyn_event_seq_start, .next = dyn_event_seq_next, .stop = dyn_event_seq_stop, |
cd7e7bd5e tracing: Add kpro... |
1128 1129 1130 1131 1132 |
.show = probes_profile_seq_show }; static int profile_open(struct inode *inode, struct file *file) { |
17911ff38 tracing: Add lock... |
1133 1134 1135 1136 1137 |
int ret; ret = security_locked_down(LOCKDOWN_TRACEFS); if (ret) return ret; |
cd7e7bd5e tracing: Add kpro... |
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 |
return seq_open(file, &profile_seq_op); } static const struct file_operations kprobe_profile_ops = { .owner = THIS_MODULE, .open = profile_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; |
533059281 tracing: probeeve... |
1148 1149 1150 |
/* Kprobe specific fetch functions */ /* Return the length of string -- including null terminal byte */ |
9178412dd tracing: probeeve... |
1151 |
static nokprobe_inline int |
9de1fec50 tracing/kprobes: ... |
1152 1153 1154 1155 1156 1157 1158 1159 1160 |
fetch_store_strlen_user(unsigned long addr) { const void __user *uaddr = (__force const void __user *)addr; return strnlen_user_nofault(uaddr, MAX_STRING_SIZE); } /* Return the length of string -- including null terminal byte */ static nokprobe_inline int |
9178412dd tracing: probeeve... |
1161 |
fetch_store_strlen(unsigned long addr) |
533059281 tracing: probeeve... |
1162 |
{ |
533059281 tracing: probeeve... |
1163 1164 |
int ret, len = 0; u8 c; |
9de1fec50 tracing/kprobes: ... |
1165 1166 1167 1168 |
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE if (addr < TASK_SIZE) return fetch_store_strlen_user(addr); #endif |
533059281 tracing: probeeve... |
1169 |
do { |
fe557319a maccess: rename p... |
1170 |
ret = copy_from_kernel_nofault(&c, (u8 *)addr + len, 1); |
533059281 tracing: probeeve... |
1171 1172 |
len++; } while (c && ret == 0 && len < MAX_STRING_SIZE); |
9178412dd tracing: probeeve... |
1173 |
return (ret < 0) ? ret : len; |
533059281 tracing: probeeve... |
1174 1175 1176 |
} /* |
9de1fec50 tracing/kprobes: ... |
1177 1178 |
* Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf * with max length and relative data location. |
533059281 tracing: probeeve... |
1179 |
*/ |
9178412dd tracing: probeeve... |
1180 |
static nokprobe_inline int |
9de1fec50 tracing/kprobes: ... |
1181 |
fetch_store_string_user(unsigned long addr, void *dest, void *base) |
533059281 tracing: probeeve... |
1182 |
{ |
9de1fec50 tracing/kprobes: ... |
1183 |
const void __user *uaddr = (__force const void __user *)addr; |
9178412dd tracing: probeeve... |
1184 |
int maxlen = get_loc_len(*(u32 *)dest); |
88903c464 tracing/probe: Ad... |
1185 |
void *__dest; |
533059281 tracing: probeeve... |
1186 |
long ret; |
9178412dd tracing: probeeve... |
1187 1188 |
if (unlikely(!maxlen)) return -ENOMEM; |
88903c464 tracing/probe: Ad... |
1189 1190 |
__dest = get_loc_data(dest, base); |
9de1fec50 tracing/kprobes: ... |
1191 |
ret = strncpy_from_user_nofault(__dest, uaddr, maxlen); |
88903c464 tracing/probe: Ad... |
1192 1193 1194 1195 1196 |
if (ret >= 0) *(u32 *)dest = make_data_loc(ret, __dest - base); return ret; } |
533059281 tracing: probeeve... |
1197 |
|
88903c464 tracing/probe: Ad... |
1198 |
/* |
9de1fec50 tracing/kprobes: ... |
1199 1200 |
* Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max * length and relative data location. |
88903c464 tracing/probe: Ad... |
1201 1202 |
*/ static nokprobe_inline int |
9de1fec50 tracing/kprobes: ... |
1203 |
fetch_store_string(unsigned long addr, void *dest, void *base) |
88903c464 tracing/probe: Ad... |
1204 |
{ |
88903c464 tracing/probe: Ad... |
1205 1206 1207 |
int maxlen = get_loc_len(*(u32 *)dest); void *__dest; long ret; |
9de1fec50 tracing/kprobes: ... |
1208 1209 1210 1211 |
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE if ((unsigned long)addr < TASK_SIZE) return fetch_store_string_user(addr, dest, base); #endif |
88903c464 tracing/probe: Ad... |
1212 1213 1214 1215 |
if (unlikely(!maxlen)) return -ENOMEM; __dest = get_loc_data(dest, base); |
9de1fec50 tracing/kprobes: ... |
1216 1217 1218 1219 1220 |
/* * Try to get string again, since the string can be changed while * probing. */ ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen); |
9178412dd tracing: probeeve... |
1221 |
if (ret >= 0) |
88903c464 tracing/probe: Ad... |
1222 |
*(u32 *)dest = make_data_loc(ret, __dest - base); |
9178412dd tracing: probeeve... |
1223 |
return ret; |
533059281 tracing: probeeve... |
1224 |
} |
9b960a388 tracing: probeeve... |
1225 |
static nokprobe_inline int |
e65f7ae7f tracing/probe: Su... |
1226 1227 |
probe_mem_read_user(void *dest, void *src, size_t size) { |
539b75b2b tracing/kprobe: C... |
1228 |
const void __user *uaddr = (__force const void __user *)src; |
c0ee37e85 maccess: rename p... |
1229 |
return copy_from_user_nofault(dest, uaddr, size); |
e65f7ae7f tracing/probe: Su... |
1230 |
} |
9de1fec50 tracing/kprobes: ... |
1231 1232 1233 1234 1235 1236 1237 |
static nokprobe_inline int probe_mem_read(void *dest, void *src, size_t size) { #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE if ((unsigned long)src < TASK_SIZE) return probe_mem_read_user(dest, src, size); #endif |
fe557319a maccess: rename p... |
1238 |
return copy_from_kernel_nofault(dest, src, size); |
9de1fec50 tracing/kprobes: ... |
1239 |
} |
533059281 tracing: probeeve... |
1240 1241 1242 |
/* Note that we don't verify it, since the code does not come from user space */ static int process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest, |
9178412dd tracing: probeeve... |
1243 |
void *base) |
533059281 tracing: probeeve... |
1244 1245 |
{ unsigned long val; |
533059281 tracing: probeeve... |
1246 |
|
a6682814f tracing/kprobes: ... |
1247 |
retry: |
533059281 tracing: probeeve... |
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 |
/* 1st stage: get value from context */ switch (code->op) { case FETCH_OP_REG: val = regs_get_register(regs, code->param); break; case FETCH_OP_STACK: val = regs_get_kernel_stack_nth(regs, code->param); break; case FETCH_OP_STACKP: val = kernel_stack_pointer(regs); break; case FETCH_OP_RETVAL: val = regs_return_value(regs); break; case FETCH_OP_IMM: val = code->immediate; break; case FETCH_OP_COMM: val = (unsigned long)current->comm; break; |
a42e3c4de tracing/probe: Ad... |
1268 1269 1270 |
case FETCH_OP_DATA: val = (unsigned long)code->data; break; |
a1303af5d tracing: probeeve... |
1271 1272 1273 1274 1275 |
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API case FETCH_OP_ARG: val = regs_get_kernel_argument(regs, code->param); break; #endif |
a6682814f tracing/kprobes: ... |
1276 1277 1278 |
case FETCH_NOP_SYMBOL: /* Ignore a place holder */ code++; goto retry; |
533059281 tracing: probeeve... |
1279 1280 1281 1282 |
default: return -EILSEQ; } code++; |
9b960a388 tracing: probeeve... |
1283 |
return process_fetch_insn_bottom(code, val, dest, base); |
533059281 tracing: probeeve... |
1284 1285 |
} NOKPROBE_SYMBOL(process_fetch_insn) |
413d37d1e tracing: Add kpro... |
1286 |
/* Kprobe handler */ |
3da0f1800 kprobes, ftrace: ... |
1287 |
static nokprobe_inline void |
c31ffb3ff tracing/kprobes: ... |
1288 |
__kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs, |
7f1d2f821 tracing: Rename f... |
1289 |
struct trace_event_file *trace_file) |
413d37d1e tracing: Add kpro... |
1290 |
{ |
93ccae7a2 tracing/kprobes: ... |
1291 |
struct kprobe_trace_entry_head *entry; |
e3dc9f898 tracing/probe: Ad... |
1292 |
struct trace_event_call *call = trace_probe_event_call(&tk->tp); |
8cfcf1550 tracing: kprobes:... |
1293 1294 |
struct trace_event_buffer fbuffer; int dsize; |
413d37d1e tracing: Add kpro... |
1295 |
|
7f1d2f821 tracing: Rename f... |
1296 |
WARN_ON(call != trace_file->event_call); |
41a7dd420 tracing/kprobes: ... |
1297 |
|
09a5059aa tracing: Rename f... |
1298 |
if (trace_trigger_soft_disabled(trace_file)) |
13a1e4aef tracing: Consolid... |
1299 |
return; |
b8820084f tracing/kprobes: ... |
1300 |
|
8cfcf1550 tracing: kprobes:... |
1301 1302 1303 |
local_save_flags(fbuffer.flags); fbuffer.pc = preempt_count(); fbuffer.trace_file = trace_file; |
413d37d1e tracing: Add kpro... |
1304 |
|
c31ffb3ff tracing/kprobes: ... |
1305 |
dsize = __get_data_size(&tk->tp, regs); |
413d37d1e tracing: Add kpro... |
1306 |
|
8cfcf1550 tracing: kprobes:... |
1307 1308 1309 1310 1311 1312 |
fbuffer.event = trace_event_buffer_lock_reserve(&fbuffer.buffer, trace_file, call->event.type, sizeof(*entry) + tk->tp.size + dsize, fbuffer.flags, fbuffer.pc); if (!fbuffer.event) |
1e12a4a7a tracing/kprobe: C... |
1313 |
return; |
413d37d1e tracing: Add kpro... |
1314 |
|
8cfcf1550 tracing: kprobes:... |
1315 1316 |
fbuffer.regs = regs; entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event); |
c31ffb3ff tracing/kprobes: ... |
1317 |
entry->ip = (unsigned long)tk->rp.kp.addr; |
9178412dd tracing: probeeve... |
1318 |
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
413d37d1e tracing: Add kpro... |
1319 |
|
8cfcf1550 tracing: kprobes:... |
1320 |
trace_event_buffer_commit(&fbuffer); |
413d37d1e tracing: Add kpro... |
1321 |
} |
3da0f1800 kprobes, ftrace: ... |
1322 |
static void |
c31ffb3ff tracing/kprobes: ... |
1323 |
kprobe_trace_func(struct trace_kprobe *tk, struct pt_regs *regs) |
41a7dd420 tracing/kprobes: ... |
1324 |
{ |
b04d52e36 tracing/kprobes: ... |
1325 |
struct event_file_link *link; |
41a7dd420 tracing/kprobes: ... |
1326 |
|
b5f935ee1 tracing/probe: Ad... |
1327 |
trace_probe_for_each_link_rcu(link, &tk->tp) |
c31ffb3ff tracing/kprobes: ... |
1328 |
__kprobe_trace_func(tk, regs, link->file); |
41a7dd420 tracing/kprobes: ... |
1329 |
} |
3da0f1800 kprobes, ftrace: ... |
1330 |
NOKPROBE_SYMBOL(kprobe_trace_func); |
41a7dd420 tracing/kprobes: ... |
1331 |
|
413d37d1e tracing: Add kpro... |
1332 |
/* Kretprobe handler */ |
3da0f1800 kprobes, ftrace: ... |
1333 |
static nokprobe_inline void |
c31ffb3ff tracing/kprobes: ... |
1334 |
__kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
41a7dd420 tracing/kprobes: ... |
1335 |
struct pt_regs *regs, |
7f1d2f821 tracing: Rename f... |
1336 |
struct trace_event_file *trace_file) |
413d37d1e tracing: Add kpro... |
1337 |
{ |
93ccae7a2 tracing/kprobes: ... |
1338 |
struct kretprobe_trace_entry_head *entry; |
8cfcf1550 tracing: kprobes:... |
1339 |
struct trace_event_buffer fbuffer; |
e3dc9f898 tracing/probe: Ad... |
1340 |
struct trace_event_call *call = trace_probe_event_call(&tk->tp); |
8cfcf1550 tracing: kprobes:... |
1341 |
int dsize; |
413d37d1e tracing: Add kpro... |
1342 |
|
7f1d2f821 tracing: Rename f... |
1343 |
WARN_ON(call != trace_file->event_call); |
41a7dd420 tracing/kprobes: ... |
1344 |
|
09a5059aa tracing: Rename f... |
1345 |
if (trace_trigger_soft_disabled(trace_file)) |
13a1e4aef tracing: Consolid... |
1346 |
return; |
b8820084f tracing/kprobes: ... |
1347 |
|
8cfcf1550 tracing: kprobes:... |
1348 1349 1350 |
local_save_flags(fbuffer.flags); fbuffer.pc = preempt_count(); fbuffer.trace_file = trace_file; |
413d37d1e tracing: Add kpro... |
1351 |
|
c31ffb3ff tracing/kprobes: ... |
1352 |
dsize = __get_data_size(&tk->tp, regs); |
8cfcf1550 tracing: kprobes:... |
1353 1354 1355 1356 1357 1358 |
fbuffer.event = trace_event_buffer_lock_reserve(&fbuffer.buffer, trace_file, call->event.type, sizeof(*entry) + tk->tp.size + dsize, fbuffer.flags, fbuffer.pc); if (!fbuffer.event) |
1e12a4a7a tracing/kprobe: C... |
1359 |
return; |
413d37d1e tracing: Add kpro... |
1360 |
|
8cfcf1550 tracing: kprobes:... |
1361 1362 |
fbuffer.regs = regs; entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event); |
c31ffb3ff tracing/kprobes: ... |
1363 |
entry->func = (unsigned long)tk->rp.kp.addr; |
413d37d1e tracing: Add kpro... |
1364 |
entry->ret_ip = (unsigned long)ri->ret_addr; |
9178412dd tracing: probeeve... |
1365 |
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
413d37d1e tracing: Add kpro... |
1366 |
|
8cfcf1550 tracing: kprobes:... |
1367 |
trace_event_buffer_commit(&fbuffer); |
413d37d1e tracing: Add kpro... |
1368 |
} |
3da0f1800 kprobes, ftrace: ... |
1369 |
static void |
c31ffb3ff tracing/kprobes: ... |
1370 |
kretprobe_trace_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
41a7dd420 tracing/kprobes: ... |
1371 1372 |
struct pt_regs *regs) { |
b04d52e36 tracing/kprobes: ... |
1373 |
struct event_file_link *link; |
41a7dd420 tracing/kprobes: ... |
1374 |
|
b5f935ee1 tracing/probe: Ad... |
1375 |
trace_probe_for_each_link_rcu(link, &tk->tp) |
c31ffb3ff tracing/kprobes: ... |
1376 |
__kretprobe_trace_func(tk, ri, regs, link->file); |
41a7dd420 tracing/kprobes: ... |
1377 |
} |
3da0f1800 kprobes, ftrace: ... |
1378 |
NOKPROBE_SYMBOL(kretprobe_trace_func); |
41a7dd420 tracing/kprobes: ... |
1379 |
|
413d37d1e tracing: Add kpro... |
1380 |
/* Event entry printers */ |
b62fdd97f tracing/kprobes: ... |
1381 |
static enum print_line_t |
a9a577638 tracing: Allow ev... |
1382 1383 |
print_kprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event) |
413d37d1e tracing: Add kpro... |
1384 |
{ |
93ccae7a2 tracing/kprobes: ... |
1385 |
struct kprobe_trace_entry_head *field; |
413d37d1e tracing: Add kpro... |
1386 |
struct trace_seq *s = &iter->seq; |
eca0d916f tracing/kprobes: ... |
1387 |
struct trace_probe *tp; |
413d37d1e tracing: Add kpro... |
1388 |
|
93ccae7a2 tracing/kprobes: ... |
1389 |
field = (struct kprobe_trace_entry_head *)iter->ent; |
60d53e2c3 tracing/probe: Sp... |
1390 1391 1392 1393 |
tp = trace_probe_primary_from_call( container_of(event, struct trace_event_call, event)); if (WARN_ON_ONCE(!tp)) goto out; |
413d37d1e tracing: Add kpro... |
1394 |
|
b55ce203a tracing/probe: Ad... |
1395 |
trace_seq_printf(s, "%s: (", trace_probe_name(tp)); |
6e9f23d16 tracing/kprobes: ... |
1396 |
|
413d37d1e tracing: Add kpro... |
1397 |
if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET)) |
85224da0b kprobes/tracing: ... |
1398 |
goto out; |
413d37d1e tracing: Add kpro... |
1399 |
|
85224da0b kprobes/tracing: ... |
1400 |
trace_seq_putc(s, ')'); |
413d37d1e tracing: Add kpro... |
1401 |
|
56de76305 tracing: probeeve... |
1402 1403 1404 |
if (print_probe_args(s, tp->args, tp->nr_args, (u8 *)&field[1], field) < 0) goto out; |
413d37d1e tracing: Add kpro... |
1405 |
|
85224da0b kprobes/tracing: ... |
1406 1407 1408 1409 |
trace_seq_putc(s, ' '); out: return trace_handle_return(s); |
413d37d1e tracing: Add kpro... |
1410 |
} |
b62fdd97f tracing/kprobes: ... |
1411 |
static enum print_line_t |
a9a577638 tracing: Allow ev... |
1412 1413 |
print_kretprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event) |
413d37d1e tracing: Add kpro... |
1414 |
{ |
93ccae7a2 tracing/kprobes: ... |
1415 |
struct kretprobe_trace_entry_head *field; |
413d37d1e tracing: Add kpro... |
1416 |
struct trace_seq *s = &iter->seq; |
eca0d916f tracing/kprobes: ... |
1417 |
struct trace_probe *tp; |
413d37d1e tracing: Add kpro... |
1418 |
|
93ccae7a2 tracing/kprobes: ... |
1419 |
field = (struct kretprobe_trace_entry_head *)iter->ent; |
60d53e2c3 tracing/probe: Sp... |
1420 1421 1422 1423 |
tp = trace_probe_primary_from_call( container_of(event, struct trace_event_call, event)); if (WARN_ON_ONCE(!tp)) goto out; |
413d37d1e tracing: Add kpro... |
1424 |
|
b55ce203a tracing/probe: Ad... |
1425 |
trace_seq_printf(s, "%s: (", trace_probe_name(tp)); |
6e9f23d16 tracing/kprobes: ... |
1426 |
|
413d37d1e tracing: Add kpro... |
1427 |
if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET)) |
85224da0b kprobes/tracing: ... |
1428 |
goto out; |
413d37d1e tracing: Add kpro... |
1429 |
|
85224da0b kprobes/tracing: ... |
1430 |
trace_seq_puts(s, " <- "); |
413d37d1e tracing: Add kpro... |
1431 1432 |
if (!seq_print_ip_sym(s, field->func, flags & ~TRACE_ITER_SYM_OFFSET)) |
85224da0b kprobes/tracing: ... |
1433 |
goto out; |
413d37d1e tracing: Add kpro... |
1434 |
|
85224da0b kprobes/tracing: ... |
1435 |
trace_seq_putc(s, ')'); |
413d37d1e tracing: Add kpro... |
1436 |
|
56de76305 tracing: probeeve... |
1437 1438 1439 |
if (print_probe_args(s, tp->args, tp->nr_args, (u8 *)&field[1], field) < 0) goto out; |
413d37d1e tracing: Add kpro... |
1440 |
|
85224da0b kprobes/tracing: ... |
1441 1442 |
trace_seq_putc(s, ' '); |
413d37d1e tracing: Add kpro... |
1443 |
|
85224da0b kprobes/tracing: ... |
1444 1445 |
out: return trace_handle_return(s); |
413d37d1e tracing: Add kpro... |
1446 |
} |
413d37d1e tracing: Add kpro... |
1447 |
|
2425bcb92 tracing: Rename f... |
1448 |
static int kprobe_event_define_fields(struct trace_event_call *event_call) |
413d37d1e tracing: Add kpro... |
1449 |
{ |
eeb07b061 tracing: probeeve... |
1450 |
int ret; |
93ccae7a2 tracing/kprobes: ... |
1451 |
struct kprobe_trace_entry_head field; |
60d53e2c3 tracing/probe: Sp... |
1452 1453 1454 1455 1456 |
struct trace_probe *tp; tp = trace_probe_primary_from_call(event_call); if (WARN_ON_ONCE(!tp)) return -ENOENT; |
413d37d1e tracing: Add kpro... |
1457 |
|
a703d946e tracing/kprobes: ... |
1458 |
DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0); |
c31ffb3ff tracing/kprobes: ... |
1459 |
|
60d53e2c3 tracing/probe: Sp... |
1460 |
return traceprobe_define_arg_fields(event_call, sizeof(field), tp); |
413d37d1e tracing: Add kpro... |
1461 |
} |
2425bcb92 tracing: Rename f... |
1462 |
static int kretprobe_event_define_fields(struct trace_event_call *event_call) |
413d37d1e tracing: Add kpro... |
1463 |
{ |
eeb07b061 tracing: probeeve... |
1464 |
int ret; |
93ccae7a2 tracing/kprobes: ... |
1465 |
struct kretprobe_trace_entry_head field; |
60d53e2c3 tracing/probe: Sp... |
1466 1467 1468 1469 1470 |
struct trace_probe *tp; tp = trace_probe_primary_from_call(event_call); if (WARN_ON_ONCE(!tp)) return -ENOENT; |
413d37d1e tracing: Add kpro... |
1471 |
|
a703d946e tracing/kprobes: ... |
1472 1473 |
DEFINE_FIELD(unsigned long, func, FIELD_STRING_FUNC, 0); DEFINE_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP, 0); |
c31ffb3ff tracing/kprobes: ... |
1474 |
|
60d53e2c3 tracing/probe: Sp... |
1475 |
return traceprobe_define_arg_fields(event_call, sizeof(field), tp); |
413d37d1e tracing: Add kpro... |
1476 |
} |
07b139c8c perf events: Remo... |
1477 |
#ifdef CONFIG_PERF_EVENTS |
e08d1c657 tracing/kprobes: ... |
1478 1479 |
/* Kprobe profile handler */ |
9802d8658 bpf: add a bpf_ov... |
1480 |
static int |
c31ffb3ff tracing/kprobes: ... |
1481 |
kprobe_perf_func(struct trace_kprobe *tk, struct pt_regs *regs) |
e08d1c657 tracing/kprobes: ... |
1482 |
{ |
e3dc9f898 tracing/probe: Ad... |
1483 |
struct trace_event_call *call = trace_probe_event_call(&tk->tp); |
93ccae7a2 tracing/kprobes: ... |
1484 |
struct kprobe_trace_entry_head *entry; |
1c024eca5 perf, trace: Opti... |
1485 |
struct hlist_head *head; |
e09c8614b tracing/kprobes: ... |
1486 |
int size, __size, dsize; |
4ed7c92d6 perf_events: Undo... |
1487 |
int rctx; |
e08d1c657 tracing/kprobes: ... |
1488 |
|
9802d8658 bpf: add a bpf_ov... |
1489 |
if (bpf_prog_array_valid(call)) { |
66665ad2f tracing/kprobe: b... |
1490 |
unsigned long orig_ip = instruction_pointer(regs); |
9802d8658 bpf: add a bpf_ov... |
1491 1492 1493 1494 1495 1496 |
int ret; ret = trace_call_bpf(call, regs); /* * We need to check and see if we modified the pc of the |
cce188bd5 bpf/error-inject/... |
1497 1498 |
* pt_regs, and if so return 1 so that we don't do the * single stepping. |
9802d8658 bpf: add a bpf_ov... |
1499 |
*/ |
cce188bd5 bpf/error-inject/... |
1500 |
if (orig_ip != instruction_pointer(regs)) |
9802d8658 bpf: add a bpf_ov... |
1501 |
return 1; |
9802d8658 bpf: add a bpf_ov... |
1502 1503 1504 |
if (!ret) return 0; } |
2541517c3 tracing, perf: Im... |
1505 |
|
288e984e6 tracing/kprobes: ... |
1506 1507 |
head = this_cpu_ptr(call->perf_events); if (hlist_empty(head)) |
9802d8658 bpf: add a bpf_ov... |
1508 |
return 0; |
288e984e6 tracing/kprobes: ... |
1509 |
|
c31ffb3ff tracing/kprobes: ... |
1510 1511 |
dsize = __get_data_size(&tk->tp, regs); __size = sizeof(*entry) + tk->tp.size + dsize; |
74ebb63e7 tracing/kprobes: ... |
1512 1513 |
size = ALIGN(__size + sizeof(u32), sizeof(u64)); size -= sizeof(u32); |
ce71b9df8 tracing: Use the ... |
1514 |
|
1e1dcd93b perf: split perf_... |
1515 |
entry = perf_trace_buf_alloc(size, NULL, &rctx); |
430ad5a60 perf: Factorize t... |
1516 |
if (!entry) |
9802d8658 bpf: add a bpf_ov... |
1517 |
return 0; |
a1a138d05 tracing/kprobes: ... |
1518 |
|
c31ffb3ff tracing/kprobes: ... |
1519 |
entry->ip = (unsigned long)tk->rp.kp.addr; |
e09c8614b tracing/kprobes: ... |
1520 |
memset(&entry[1], 0, dsize); |
9178412dd tracing: probeeve... |
1521 |
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
1e1dcd93b perf: split perf_... |
1522 |
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, |
8fd0fbbe8 perf/ftrace: Reve... |
1523 |
head, NULL); |
9802d8658 bpf: add a bpf_ov... |
1524 |
return 0; |
e08d1c657 tracing/kprobes: ... |
1525 |
} |
3da0f1800 kprobes, ftrace: ... |
1526 |
NOKPROBE_SYMBOL(kprobe_perf_func); |
e08d1c657 tracing/kprobes: ... |
1527 1528 |
/* Kretprobe profile handler */ |
3da0f1800 kprobes, ftrace: ... |
1529 |
static void |
c31ffb3ff tracing/kprobes: ... |
1530 |
kretprobe_perf_func(struct trace_kprobe *tk, struct kretprobe_instance *ri, |
2b106aabe tracing/kprobes: ... |
1531 |
struct pt_regs *regs) |
e08d1c657 tracing/kprobes: ... |
1532 |
{ |
e3dc9f898 tracing/probe: Ad... |
1533 |
struct trace_event_call *call = trace_probe_event_call(&tk->tp); |
93ccae7a2 tracing/kprobes: ... |
1534 |
struct kretprobe_trace_entry_head *entry; |
1c024eca5 perf, trace: Opti... |
1535 |
struct hlist_head *head; |
e09c8614b tracing/kprobes: ... |
1536 |
int size, __size, dsize; |
4ed7c92d6 perf_events: Undo... |
1537 |
int rctx; |
e08d1c657 tracing/kprobes: ... |
1538 |
|
e87c6bc38 bpf: permit multi... |
1539 |
if (bpf_prog_array_valid(call) && !trace_call_bpf(call, regs)) |
2541517c3 tracing, perf: Im... |
1540 |
return; |
288e984e6 tracing/kprobes: ... |
1541 1542 1543 |
head = this_cpu_ptr(call->perf_events); if (hlist_empty(head)) return; |
c31ffb3ff tracing/kprobes: ... |
1544 1545 |
dsize = __get_data_size(&tk->tp, regs); __size = sizeof(*entry) + tk->tp.size + dsize; |
74ebb63e7 tracing/kprobes: ... |
1546 1547 |
size = ALIGN(__size + sizeof(u32), sizeof(u64)); size -= sizeof(u32); |
444a2a3bc tracing, perf_eve... |
1548 |
|
1e1dcd93b perf: split perf_... |
1549 |
entry = perf_trace_buf_alloc(size, NULL, &rctx); |
430ad5a60 perf: Factorize t... |
1550 |
if (!entry) |
1e12a4a7a tracing/kprobe: C... |
1551 |
return; |
e08d1c657 tracing/kprobes: ... |
1552 |
|
c31ffb3ff tracing/kprobes: ... |
1553 |
entry->func = (unsigned long)tk->rp.kp.addr; |
a1a138d05 tracing/kprobes: ... |
1554 |
entry->ret_ip = (unsigned long)ri->ret_addr; |
9178412dd tracing: probeeve... |
1555 |
store_trace_args(&entry[1], &tk->tp, regs, sizeof(*entry), dsize); |
1e1dcd93b perf: split perf_... |
1556 |
perf_trace_buf_submit(entry, size, rctx, call->event.type, 1, regs, |
8fd0fbbe8 perf/ftrace: Reve... |
1557 |
head, NULL); |
e08d1c657 tracing/kprobes: ... |
1558 |
} |
3da0f1800 kprobes, ftrace: ... |
1559 |
NOKPROBE_SYMBOL(kretprobe_perf_func); |
41bdc4b40 bpf: introduce bp... |
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 |
int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type, const char **symbol, u64 *probe_offset, u64 *probe_addr, bool perf_type_tracepoint) { const char *pevent = trace_event_name(event->tp_event); const char *group = event->tp_event->class->system; struct trace_kprobe *tk; if (perf_type_tracepoint) tk = find_trace_kprobe(pevent, group); else |
22d5bd686 tracing/probe: Fi... |
1572 |
tk = trace_kprobe_primary_from_call(event->tp_event); |
41bdc4b40 bpf: introduce bp... |
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 |
if (!tk) return -EINVAL; *fd_type = trace_kprobe_is_return(tk) ? BPF_FD_TYPE_KRETPROBE : BPF_FD_TYPE_KPROBE; if (tk->symbol) { *symbol = tk->symbol; *probe_offset = tk->rp.kp.offset; *probe_addr = 0; } else { *symbol = NULL; *probe_offset = 0; *probe_addr = (unsigned long)tk->rp.kp.addr; } return 0; } |
07b139c8c perf events: Remo... |
1589 |
#endif /* CONFIG_PERF_EVENTS */ |
50d780560 tracing/kprobes: ... |
1590 |
|
3fe3d6193 tracing/kprobes: ... |
1591 1592 1593 1594 1595 1596 |
/* * called by perf_trace_init() or __ftrace_set_clr_event() under event_mutex. * * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe * lockless, but we can't race with this __init function. */ |
2425bcb92 tracing: Rename f... |
1597 |
static int kprobe_register(struct trace_event_call *event, |
fbc1963d2 kprobes, ftrace: ... |
1598 |
enum trace_reg type, void *data) |
2239291ae tracing: Remove p... |
1599 |
{ |
7f1d2f821 tracing: Rename f... |
1600 |
struct trace_event_file *file = data; |
1538f888f tracing/kprobes: ... |
1601 |
|
2239291ae tracing: Remove p... |
1602 1603 |
switch (type) { case TRACE_REG_REGISTER: |
60d53e2c3 tracing/probe: Sp... |
1604 |
return enable_trace_kprobe(event, file); |
2239291ae tracing: Remove p... |
1605 |
case TRACE_REG_UNREGISTER: |
60d53e2c3 tracing/probe: Sp... |
1606 |
return disable_trace_kprobe(event, file); |
2239291ae tracing: Remove p... |
1607 1608 1609 |
#ifdef CONFIG_PERF_EVENTS case TRACE_REG_PERF_REGISTER: |
60d53e2c3 tracing/probe: Sp... |
1610 |
return enable_trace_kprobe(event, NULL); |
2239291ae tracing: Remove p... |
1611 |
case TRACE_REG_PERF_UNREGISTER: |
60d53e2c3 tracing/probe: Sp... |
1612 |
return disable_trace_kprobe(event, NULL); |
ceec0b6fc ftrace, perf: Add... |
1613 1614 |
case TRACE_REG_PERF_OPEN: case TRACE_REG_PERF_CLOSE: |
489c75c3b ftrace, perf: Add... |
1615 1616 |
case TRACE_REG_PERF_ADD: case TRACE_REG_PERF_DEL: |
ceec0b6fc ftrace, perf: Add... |
1617 |
return 0; |
2239291ae tracing: Remove p... |
1618 1619 1620 1621 |
#endif } return 0; } |
50d780560 tracing/kprobes: ... |
1622 |
|
3da0f1800 kprobes, ftrace: ... |
1623 |
static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) |
50d780560 tracing/kprobes: ... |
1624 |
{ |
c31ffb3ff tracing/kprobes: ... |
1625 |
struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); |
9802d8658 bpf: add a bpf_ov... |
1626 |
int ret = 0; |
e08d1c657 tracing/kprobes: ... |
1627 |
|
a7636d9ec kprobes: Optimize... |
1628 |
raw_cpu_inc(*tk->nhit); |
48182bd22 tracing/kprobes: ... |
1629 |
|
747774d6b tracing/probe: Ad... |
1630 |
if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE)) |
c31ffb3ff tracing/kprobes: ... |
1631 |
kprobe_trace_func(tk, regs); |
07b139c8c perf events: Remo... |
1632 |
#ifdef CONFIG_PERF_EVENTS |
747774d6b tracing/probe: Ad... |
1633 |
if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE)) |
9802d8658 bpf: add a bpf_ov... |
1634 |
ret = kprobe_perf_func(tk, regs); |
07b139c8c perf events: Remo... |
1635 |
#endif |
9802d8658 bpf: add a bpf_ov... |
1636 |
return ret; |
50d780560 tracing/kprobes: ... |
1637 |
} |
3da0f1800 kprobes, ftrace: ... |
1638 |
NOKPROBE_SYMBOL(kprobe_dispatcher); |
50d780560 tracing/kprobes: ... |
1639 |
|
3da0f1800 kprobes, ftrace: ... |
1640 1641 |
static int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs) |
50d780560 tracing/kprobes: ... |
1642 |
{ |
c31ffb3ff tracing/kprobes: ... |
1643 |
struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp); |
50d780560 tracing/kprobes: ... |
1644 |
|
a7636d9ec kprobes: Optimize... |
1645 |
raw_cpu_inc(*tk->nhit); |
48182bd22 tracing/kprobes: ... |
1646 |
|
747774d6b tracing/probe: Ad... |
1647 |
if (trace_probe_test_flag(&tk->tp, TP_FLAG_TRACE)) |
c31ffb3ff tracing/kprobes: ... |
1648 |
kretprobe_trace_func(tk, ri, regs); |
07b139c8c perf events: Remo... |
1649 |
#ifdef CONFIG_PERF_EVENTS |
747774d6b tracing/probe: Ad... |
1650 |
if (trace_probe_test_flag(&tk->tp, TP_FLAG_PROFILE)) |
c31ffb3ff tracing/kprobes: ... |
1651 |
kretprobe_perf_func(tk, ri, regs); |
07b139c8c perf events: Remo... |
1652 |
#endif |
50d780560 tracing/kprobes: ... |
1653 1654 |
return 0; /* We don't tweek kernel, so just return 0 */ } |
3da0f1800 kprobes, ftrace: ... |
1655 |
NOKPROBE_SYMBOL(kretprobe_dispatcher); |
e08d1c657 tracing/kprobes: ... |
1656 |
|
a9a577638 tracing: Allow ev... |
1657 1658 1659 1660 1661 1662 1663 |
static struct trace_event_functions kretprobe_funcs = { .trace = print_kretprobe_event }; static struct trace_event_functions kprobe_funcs = { .trace = print_kprobe_event }; |
04ae87a52 ftrace: Rework ev... |
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 |
static struct trace_event_fields kretprobe_fields_array[] = { { .type = TRACE_FUNCTION_TYPE, .define_fields = kretprobe_event_define_fields }, {} }; static struct trace_event_fields kprobe_fields_array[] = { { .type = TRACE_FUNCTION_TYPE, .define_fields = kprobe_event_define_fields }, {} }; |
e3dc9f898 tracing/probe: Ad... |
1675 |
static inline void init_trace_event_call(struct trace_kprobe *tk) |
413d37d1e tracing: Add kpro... |
1676 |
{ |
e3dc9f898 tracing/probe: Ad... |
1677 |
struct trace_event_call *call = trace_probe_event_call(&tk->tp); |
c31ffb3ff tracing/kprobes: ... |
1678 |
if (trace_kprobe_is_return(tk)) { |
80decc70a tracing: Move pri... |
1679 |
call->event.funcs = &kretprobe_funcs; |
04ae87a52 ftrace: Rework ev... |
1680 |
call->class->fields_array = kretprobe_fields_array; |
413d37d1e tracing: Add kpro... |
1681 |
} else { |
80decc70a tracing: Move pri... |
1682 |
call->event.funcs = &kprobe_funcs; |
04ae87a52 ftrace: Rework ev... |
1683 |
call->class->fields_array = kprobe_fields_array; |
413d37d1e tracing: Add kpro... |
1684 |
} |
e12f03d70 perf/core: Implem... |
1685 1686 1687 |
call->flags = TRACE_EVENT_FL_KPROBE; call->class->reg = kprobe_register; |
e12f03d70 perf/core: Implem... |
1688 1689 1690 1691 |
} static int register_kprobe_event(struct trace_kprobe *tk) { |
e3dc9f898 tracing/probe: Ad... |
1692 |
init_trace_event_call(tk); |
f730e0f2d tracing/kprobe: S... |
1693 |
|
46e5376d4 tracing/probe: Ad... |
1694 |
return trace_probe_register_event_call(&tk->tp); |
413d37d1e tracing: Add kpro... |
1695 |
} |
c31ffb3ff tracing/kprobes: ... |
1696 |
static int unregister_kprobe_event(struct trace_kprobe *tk) |
413d37d1e tracing: Add kpro... |
1697 |
{ |
46e5376d4 tracing/probe: Ad... |
1698 |
return trace_probe_unregister_event_call(&tk->tp); |
413d37d1e tracing: Add kpro... |
1699 |
} |
e12f03d70 perf/core: Implem... |
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 |
#ifdef CONFIG_PERF_EVENTS /* create a trace_kprobe, but don't add it to global lists */ struct trace_event_call * create_local_trace_kprobe(char *func, void *addr, unsigned long offs, bool is_return) { struct trace_kprobe *tk; int ret; char *event; /* |
6212dd296 tracing/kprobes: ... |
1711 |
* local trace_kprobes are not added to dyn_event, so they are never |
e12f03d70 perf/core: Implem... |
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 |
* searched in find_trace_kprobe(). Therefore, there is no concern of * duplicated name here. */ event = func ? func : "DUMMY_EVENT"; tk = alloc_trace_kprobe(KPROBE_EVENT_SYSTEM, event, (void *)addr, func, offs, 0 /* maxactive */, 0 /* nargs */, is_return); if (IS_ERR(tk)) { pr_info("Failed to allocate trace_probe.(%d) ", (int)PTR_ERR(tk)); return ERR_CAST(tk); } |
e3dc9f898 tracing/probe: Ad... |
1727 |
init_trace_event_call(tk); |
e12f03d70 perf/core: Implem... |
1728 |
|
0a46c8549 tracing: probeeve... |
1729 |
if (traceprobe_set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) { |
e12f03d70 perf/core: Implem... |
1730 1731 1732 1733 1734 |
ret = -ENOMEM; goto error; } ret = __register_trace_kprobe(tk); |
f730e0f2d tracing/kprobe: S... |
1735 |
if (ret < 0) |
e12f03d70 perf/core: Implem... |
1736 |
goto error; |
e3dc9f898 tracing/probe: Ad... |
1737 |
return trace_probe_event_call(&tk->tp); |
e12f03d70 perf/core: Implem... |
1738 1739 1740 1741 1742 1743 1744 1745 |
error: free_trace_kprobe(tk); return ERR_PTR(ret); } void destroy_local_trace_kprobe(struct trace_event_call *event_call) { struct trace_kprobe *tk; |
60d53e2c3 tracing/probe: Sp... |
1746 1747 1748 |
tk = trace_kprobe_primary_from_call(event_call); if (unlikely(!tk)) return; |
e12f03d70 perf/core: Implem... |
1749 1750 1751 1752 1753 1754 1755 |
if (trace_probe_is_enabled(&tk->tp)) { WARN_ON(1); return; } __unregister_trace_kprobe(tk); |
0fc8c3581 tracing/kprobe: R... |
1756 |
|
e12f03d70 perf/core: Implem... |
1757 1758 1759 |
free_trace_kprobe(tk); } #endif /* CONFIG_PERF_EVENTS */ |
970988e19 tracing/kprobe: A... |
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 |
static __init void enable_boot_kprobe_events(void) { struct trace_array *tr = top_trace_array(); struct trace_event_file *file; struct trace_kprobe *tk; struct dyn_event *pos; mutex_lock(&event_mutex); for_each_trace_kprobe(tk, pos) { list_for_each_entry(file, &tr->events, list) |
e3dc9f898 tracing/probe: Ad... |
1770 |
if (file->event_call == trace_probe_event_call(&tk->tp)) |
970988e19 tracing/kprobe: A... |
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 |
trace_event_enable_disable(file, 1, 0); } mutex_unlock(&event_mutex); } static __init void setup_boot_kprobe_events(void) { char *p, *cmd = kprobe_boot_events_buf; int ret; strreplace(kprobe_boot_events_buf, ',', ' '); while (cmd && *cmd != '\0') { p = strchr(cmd, ';'); if (p) *p++ = '\0'; ret = trace_run_command(cmd, create_or_delete_trace_kprobe); if (ret) pr_warn("Failed to add event(%d): %s ", ret, cmd); cmd = p; } enable_boot_kprobe_events(); } |
d8d4c6d0e tracing: kprobes:... |
1798 |
/* |
ba0fbfbb2 tracing/boot, kpr... |
1799 1800 |
* Register dynevent at core_initcall. This allows kernel to setup kprobe * events in postcore_initcall without tracefs. |
d8d4c6d0e tracing: kprobes:... |
1801 1802 |
*/ static __init int init_kprobe_trace_early(void) |
413d37d1e tracing: Add kpro... |
1803 |
{ |
6212dd296 tracing/kprobes: ... |
1804 1805 1806 1807 1808 |
int ret; ret = dyn_event_register(&trace_kprobe_ops); if (ret) return ret; |
413d37d1e tracing: Add kpro... |
1809 |
|
c31ffb3ff tracing/kprobes: ... |
1810 |
if (register_module_notifier(&trace_kprobe_module_nb)) |
614243181 tracing/kprobes: ... |
1811 |
return -EINVAL; |
d8d4c6d0e tracing: kprobes:... |
1812 1813 |
return 0; } |
ba0fbfbb2 tracing/boot, kpr... |
1814 |
core_initcall(init_kprobe_trace_early); |
d8d4c6d0e tracing: kprobes:... |
1815 1816 1817 1818 |
/* Make a tracefs interface for controlling probe points */ static __init int init_kprobe_trace(void) { |
22c36b182 tracing: make tra... |
1819 |
int ret; |
d8d4c6d0e tracing: kprobes:... |
1820 |
struct dentry *entry; |
22c36b182 tracing: make tra... |
1821 1822 |
ret = tracing_init_dentry(); if (ret) |
413d37d1e tracing: Add kpro... |
1823 |
return 0; |
22c36b182 tracing: make tra... |
1824 |
entry = tracefs_create_file("kprobe_events", 0644, NULL, |
413d37d1e tracing: Add kpro... |
1825 |
NULL, &kprobe_events_ops); |
cd7e7bd5e tracing: Add kpro... |
1826 |
/* Event list interface */ |
413d37d1e tracing: Add kpro... |
1827 |
if (!entry) |
a395d6a7e kernel/...: conve... |
1828 1829 |
pr_warn("Could not create tracefs 'kprobe_events' entry "); |
cd7e7bd5e tracing: Add kpro... |
1830 1831 |
/* Profile interface */ |
22c36b182 tracing: make tra... |
1832 |
entry = tracefs_create_file("kprobe_profile", 0444, NULL, |
cd7e7bd5e tracing: Add kpro... |
1833 1834 1835 |
NULL, &kprobe_profile_ops); if (!entry) |
a395d6a7e kernel/...: conve... |
1836 1837 |
pr_warn("Could not create tracefs 'kprobe_profile' entry "); |
970988e19 tracing/kprobe: A... |
1838 1839 |
setup_boot_kprobe_events(); |
413d37d1e tracing: Add kpro... |
1840 1841 1842 1843 1844 1845 |
return 0; } fs_initcall(init_kprobe_trace); #ifdef CONFIG_FTRACE_STARTUP_TEST |
26a346f23 tracing/kprobes: ... |
1846 |
static __init struct trace_event_file * |
c31ffb3ff tracing/kprobes: ... |
1847 |
find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr) |
41a7dd420 tracing/kprobes: ... |
1848 |
{ |
7f1d2f821 tracing: Rename f... |
1849 |
struct trace_event_file *file; |
41a7dd420 tracing/kprobes: ... |
1850 1851 |
list_for_each_entry(file, &tr->events, list) |
e3dc9f898 tracing/probe: Ad... |
1852 |
if (file->event_call == trace_probe_event_call(&tk->tp)) |
41a7dd420 tracing/kprobes: ... |
1853 1854 1855 1856 |
return file; return NULL; } |
3fe3d6193 tracing/kprobes: ... |
1857 |
/* |
c31ffb3ff tracing/kprobes: ... |
1858 |
* Nobody but us can call enable_trace_kprobe/disable_trace_kprobe at this |
3fe3d6193 tracing/kprobes: ... |
1859 1860 |
* stage, we can do this lockless. */ |
413d37d1e tracing: Add kpro... |
1861 1862 |
static __init int kprobe_trace_self_tests_init(void) { |
231e36f4d tracing/kprobe: U... |
1863 |
int ret, warn = 0; |
413d37d1e tracing: Add kpro... |
1864 |
int (*target)(int, int, int, int, int, int); |
c31ffb3ff tracing/kprobes: ... |
1865 |
struct trace_kprobe *tk; |
7f1d2f821 tracing: Rename f... |
1866 |
struct trace_event_file *file; |
413d37d1e tracing: Add kpro... |
1867 |
|
748ec3a20 tracing/kprobes: ... |
1868 1869 |
if (tracing_is_disabled()) return -ENODEV; |
f2d7cffc2 tracing: Disable ... |
1870 |
if (tracing_selftest_disabled) |
b6399cc78 tracing/kprobe: D... |
1871 |
return 0; |
b6399cc78 tracing/kprobe: D... |
1872 |
|
413d37d1e tracing: Add kpro... |
1873 1874 1875 |
target = kprobe_trace_selftest_target; pr_info("Testing kprobe tracing: "); |
6212dd296 tracing/kprobes: ... |
1876 1877 |
ret = trace_run_command("p:testprobe kprobe_trace_selftest_target $stack $stack0 +0($stack)", create_or_delete_trace_kprobe); |
231e36f4d tracing/kprobe: U... |
1878 |
if (WARN_ON_ONCE(ret)) { |
41a7dd420 tracing/kprobes: ... |
1879 1880 |
pr_warn("error on probing function entry. "); |
231e36f4d tracing/kprobe: U... |
1881 1882 1883 |
warn++; } else { /* Enable trace point */ |
c31ffb3ff tracing/kprobes: ... |
1884 1885 |
tk = find_trace_kprobe("testprobe", KPROBE_EVENT_SYSTEM); if (WARN_ON_ONCE(tk == NULL)) { |
41a7dd420 tracing/kprobes: ... |
1886 1887 |
pr_warn("error on getting new probe. "); |
231e36f4d tracing/kprobe: U... |
1888 |
warn++; |
41a7dd420 tracing/kprobes: ... |
1889 |
} else { |
c31ffb3ff tracing/kprobes: ... |
1890 |
file = find_trace_probe_file(tk, top_trace_array()); |
41a7dd420 tracing/kprobes: ... |
1891 1892 1893 1894 1895 |
if (WARN_ON_ONCE(file == NULL)) { pr_warn("error on getting probe file. "); warn++; } else |
60d53e2c3 tracing/probe: Sp... |
1896 1897 |
enable_trace_kprobe( trace_probe_event_call(&tk->tp), file); |
41a7dd420 tracing/kprobes: ... |
1898 |
} |
231e36f4d tracing/kprobe: U... |
1899 |
} |
413d37d1e tracing: Add kpro... |
1900 |
|
6212dd296 tracing/kprobes: ... |
1901 1902 |
ret = trace_run_command("r:testprobe2 kprobe_trace_selftest_target $retval", create_or_delete_trace_kprobe); |
231e36f4d tracing/kprobe: U... |
1903 |
if (WARN_ON_ONCE(ret)) { |
41a7dd420 tracing/kprobes: ... |
1904 1905 |
pr_warn("error on probing function return. "); |
231e36f4d tracing/kprobe: U... |
1906 1907 1908 |
warn++; } else { /* Enable trace point */ |
c31ffb3ff tracing/kprobes: ... |
1909 1910 |
tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM); if (WARN_ON_ONCE(tk == NULL)) { |
41a7dd420 tracing/kprobes: ... |
1911 1912 |
pr_warn("error on getting 2nd new probe. "); |
231e36f4d tracing/kprobe: U... |
1913 |
warn++; |
41a7dd420 tracing/kprobes: ... |
1914 |
} else { |
c31ffb3ff tracing/kprobes: ... |
1915 |
file = find_trace_probe_file(tk, top_trace_array()); |
41a7dd420 tracing/kprobes: ... |
1916 1917 1918 1919 1920 |
if (WARN_ON_ONCE(file == NULL)) { pr_warn("error on getting probe file. "); warn++; } else |
60d53e2c3 tracing/probe: Sp... |
1921 1922 |
enable_trace_kprobe( trace_probe_event_call(&tk->tp), file); |
41a7dd420 tracing/kprobes: ... |
1923 |
} |
231e36f4d tracing/kprobe: U... |
1924 1925 1926 1927 |
} if (warn) goto end; |
413d37d1e tracing: Add kpro... |
1928 1929 |
ret = target(1, 2, 3, 4, 5, 6); |
d4d7ccc83 kprobes/trace: Fi... |
1930 1931 1932 1933 1934 1935 1936 |
/* * Not expecting an error here, the check is only to prevent the * optimizer from removing the call to target() as otherwise there * are no side-effects and the call is never performed. */ if (ret != 21) warn++; |
02ca1521a ftrace/kprobes: F... |
1937 |
/* Disable trace points before removing it */ |
c31ffb3ff tracing/kprobes: ... |
1938 1939 |
tk = find_trace_kprobe("testprobe", KPROBE_EVENT_SYSTEM); if (WARN_ON_ONCE(tk == NULL)) { |
41a7dd420 tracing/kprobes: ... |
1940 1941 |
pr_warn("error on getting test probe. "); |
02ca1521a ftrace/kprobes: F... |
1942 |
warn++; |
41a7dd420 tracing/kprobes: ... |
1943 |
} else { |
d4d7ccc83 kprobes/trace: Fi... |
1944 1945 1946 1947 1948 |
if (trace_kprobe_nhit(tk) != 1) { pr_warn("incorrect number of testprobe hits "); warn++; } |
c31ffb3ff tracing/kprobes: ... |
1949 |
file = find_trace_probe_file(tk, top_trace_array()); |
41a7dd420 tracing/kprobes: ... |
1950 1951 1952 1953 1954 |
if (WARN_ON_ONCE(file == NULL)) { pr_warn("error on getting probe file. "); warn++; } else |
60d53e2c3 tracing/probe: Sp... |
1955 1956 |
disable_trace_kprobe( trace_probe_event_call(&tk->tp), file); |
41a7dd420 tracing/kprobes: ... |
1957 |
} |
02ca1521a ftrace/kprobes: F... |
1958 |
|
c31ffb3ff tracing/kprobes: ... |
1959 1960 |
tk = find_trace_kprobe("testprobe2", KPROBE_EVENT_SYSTEM); if (WARN_ON_ONCE(tk == NULL)) { |
41a7dd420 tracing/kprobes: ... |
1961 1962 |
pr_warn("error on getting 2nd test probe. "); |
02ca1521a ftrace/kprobes: F... |
1963 |
warn++; |
41a7dd420 tracing/kprobes: ... |
1964 |
} else { |
d4d7ccc83 kprobes/trace: Fi... |
1965 1966 1967 1968 1969 |
if (trace_kprobe_nhit(tk) != 1) { pr_warn("incorrect number of testprobe2 hits "); warn++; } |
c31ffb3ff tracing/kprobes: ... |
1970 |
file = find_trace_probe_file(tk, top_trace_array()); |
41a7dd420 tracing/kprobes: ... |
1971 1972 1973 1974 1975 |
if (WARN_ON_ONCE(file == NULL)) { pr_warn("error on getting probe file. "); warn++; } else |
60d53e2c3 tracing/probe: Sp... |
1976 1977 |
disable_trace_kprobe( trace_probe_event_call(&tk->tp), file); |
41a7dd420 tracing/kprobes: ... |
1978 |
} |
02ca1521a ftrace/kprobes: F... |
1979 |
|
6212dd296 tracing/kprobes: ... |
1980 |
ret = trace_run_command("-:testprobe", create_or_delete_trace_kprobe); |
231e36f4d tracing/kprobe: U... |
1981 |
if (WARN_ON_ONCE(ret)) { |
41a7dd420 tracing/kprobes: ... |
1982 1983 |
pr_warn("error on deleting a probe. "); |
231e36f4d tracing/kprobe: U... |
1984 1985 |
warn++; } |
6212dd296 tracing/kprobes: ... |
1986 |
ret = trace_run_command("-:testprobe2", create_or_delete_trace_kprobe); |
231e36f4d tracing/kprobe: U... |
1987 |
if (WARN_ON_ONCE(ret)) { |
41a7dd420 tracing/kprobes: ... |
1988 1989 |
pr_warn("error on deleting a probe. "); |
231e36f4d tracing/kprobe: U... |
1990 1991 |
warn++; } |
413d37d1e tracing: Add kpro... |
1992 |
|
231e36f4d tracing/kprobe: U... |
1993 |
end: |
6212dd296 tracing/kprobes: ... |
1994 1995 1996 1997 1998 1999 |
ret = dyn_events_release_all(&trace_kprobe_ops); if (WARN_ON_ONCE(ret)) { pr_warn("error on cleaning up probes. "); warn++; } |
30e7d894c tracing/kprobes: ... |
2000 2001 2002 2003 2004 |
/* * Wait for the optimizer work to finish. Otherwise it might fiddle * with probes in already freed __init text. */ wait_for_kprobe_optimizer(); |
231e36f4d tracing/kprobe: U... |
2005 2006 2007 2008 2009 2010 |
if (warn) pr_cont("NG: Some tests are failed. Please check them. "); else pr_cont("OK "); |
413d37d1e tracing: Add kpro... |
2011 2012 2013 2014 2015 2016 |
return 0; } late_initcall(kprobe_trace_self_tests_init); #endif |