diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_event_perf.c | 15 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 32 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 34 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 56 |
4 files changed, 114 insertions, 23 deletions
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 0565bb42566f..196fe9d26773 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -49,7 +49,12 @@ static int perf_trace_event_enable(struct ftrace_event_call *event) | |||
49 | rcu_assign_pointer(perf_trace_buf_nmi, buf); | 49 | rcu_assign_pointer(perf_trace_buf_nmi, buf); |
50 | } | 50 | } |
51 | 51 | ||
52 | ret = event->perf_event_enable(event); | 52 | if (event->class->reg) |
53 | ret = event->class->reg(event, TRACE_REG_PERF_REGISTER); | ||
54 | else | ||
55 | ret = tracepoint_probe_register(event->name, | ||
56 | event->class->perf_probe, | ||
57 | event); | ||
53 | if (!ret) { | 58 | if (!ret) { |
54 | total_ref_count++; | 59 | total_ref_count++; |
55 | return 0; | 60 | return 0; |
@@ -75,7 +80,8 @@ int perf_trace_enable(int event_id) | |||
75 | 80 | ||
76 | mutex_lock(&event_mutex); | 81 | mutex_lock(&event_mutex); |
77 | list_for_each_entry(event, &ftrace_events, list) { | 82 | list_for_each_entry(event, &ftrace_events, list) { |
78 | if (event->id == event_id && event->perf_event_enable && | 83 | if (event->id == event_id && |
84 | event->class && event->class->perf_probe && | ||
79 | try_module_get(event->mod)) { | 85 | try_module_get(event->mod)) { |
80 | ret = perf_trace_event_enable(event); | 86 | ret = perf_trace_event_enable(event); |
81 | break; | 87 | break; |
@@ -93,7 +99,10 @@ static void perf_trace_event_disable(struct ftrace_event_call *event) | |||
93 | if (--event->perf_refcount > 0) | 99 | if (--event->perf_refcount > 0) |
94 | return; | 100 | return; |
95 | 101 | ||
96 | event->perf_event_disable(event); | 102 | if (event->class->reg) |
103 | event->class->reg(event, TRACE_REG_PERF_UNREGISTER); | ||
104 | else | ||
105 | tracepoint_probe_unregister(event->name, event->class->perf_probe, event); | ||
97 | 106 | ||
98 | if (!--total_ref_count) { | 107 | if (!--total_ref_count) { |
99 | buf = perf_trace_buf; | 108 | buf = perf_trace_buf; |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 2f54b48d3632..19d1eb0a7188 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -127,13 +127,23 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call, | |||
127 | if (call->enabled) { | 127 | if (call->enabled) { |
128 | call->enabled = 0; | 128 | call->enabled = 0; |
129 | tracing_stop_cmdline_record(); | 129 | tracing_stop_cmdline_record(); |
130 | call->unregfunc(call); | 130 | if (call->class->reg) |
131 | call->class->reg(call, TRACE_REG_UNREGISTER); | ||
132 | else | ||
133 | tracepoint_probe_unregister(call->name, | ||
134 | call->class->probe, | ||
135 | call); | ||
131 | } | 136 | } |
132 | break; | 137 | break; |
133 | case 1: | 138 | case 1: |
134 | if (!call->enabled) { | 139 | if (!call->enabled) { |
135 | tracing_start_cmdline_record(); | 140 | tracing_start_cmdline_record(); |
136 | ret = call->regfunc(call); | 141 | if (call->class->reg) |
142 | ret = call->class->reg(call, TRACE_REG_REGISTER); | ||
143 | else | ||
144 | ret = tracepoint_probe_register(call->name, | ||
145 | call->class->probe, | ||
146 | call); | ||
137 | if (ret) { | 147 | if (ret) { |
138 | tracing_stop_cmdline_record(); | 148 | tracing_stop_cmdline_record(); |
139 | pr_info("event trace: Could not enable event " | 149 | pr_info("event trace: Could not enable event " |
@@ -171,7 +181,8 @@ static int __ftrace_set_clr_event(const char *match, const char *sub, | |||
171 | mutex_lock(&event_mutex); | 181 | mutex_lock(&event_mutex); |
172 | list_for_each_entry(call, &ftrace_events, list) { | 182 | list_for_each_entry(call, &ftrace_events, list) { |
173 | 183 | ||
174 | if (!call->name || !call->regfunc) | 184 | if (!call->name || !call->class || |
185 | (!call->class->probe && !call->class->reg)) | ||
175 | continue; | 186 | continue; |
176 | 187 | ||
177 | if (match && | 188 | if (match && |
@@ -297,7 +308,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
297 | * The ftrace subsystem is for showing formats only. | 308 | * The ftrace subsystem is for showing formats only. |
298 | * They can not be enabled or disabled via the event files. | 309 | * They can not be enabled or disabled via the event files. |
299 | */ | 310 | */ |
300 | if (call->regfunc) | 311 | if (call->class && (call->class->probe || call->class->reg)) |
301 | return call; | 312 | return call; |
302 | } | 313 | } |
303 | 314 | ||
@@ -450,7 +461,8 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
450 | 461 | ||
451 | mutex_lock(&event_mutex); | 462 | mutex_lock(&event_mutex); |
452 | list_for_each_entry(call, &ftrace_events, list) { | 463 | list_for_each_entry(call, &ftrace_events, list) { |
453 | if (!call->name || !call->regfunc) | 464 | if (!call->name || !call->class || |
465 | (!call->class->probe && !call->class->reg)) | ||
454 | continue; | 466 | continue; |
455 | 467 | ||
456 | if (system && strcmp(call->class->system, system) != 0) | 468 | if (system && strcmp(call->class->system, system) != 0) |
@@ -935,13 +947,15 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
935 | return -1; | 947 | return -1; |
936 | } | 948 | } |
937 | 949 | ||
938 | if (call->regfunc) | 950 | if (call->class->probe || call->class->reg) |
939 | trace_create_file("enable", 0644, call->dir, call, | 951 | trace_create_file("enable", 0644, call->dir, call, |
940 | enable); | 952 | enable); |
941 | 953 | ||
942 | if (call->id && call->perf_event_enable) | 954 | #ifdef CONFIG_PERF_EVENTS |
955 | if (call->id && (call->class->perf_probe || call->class->reg)) | ||
943 | trace_create_file("id", 0444, call->dir, call, | 956 | trace_create_file("id", 0444, call->dir, call, |
944 | id); | 957 | id); |
958 | #endif | ||
945 | 959 | ||
946 | if (call->define_fields) { | 960 | if (call->define_fields) { |
947 | ret = trace_define_common_fields(call); | 961 | ret = trace_define_common_fields(call); |
@@ -1388,8 +1402,8 @@ static __init void event_trace_self_tests(void) | |||
1388 | 1402 | ||
1389 | list_for_each_entry(call, &ftrace_events, list) { | 1403 | list_for_each_entry(call, &ftrace_events, list) { |
1390 | 1404 | ||
1391 | /* Only test those that have a regfunc */ | 1405 | /* Only test those that have a probe */ |
1392 | if (!call->regfunc) | 1406 | if (!call->class || !call->class->probe) |
1393 | continue; | 1407 | continue; |
1394 | 1408 | ||
1395 | /* | 1409 | /* |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index eda220bf2065..f8af21a53f0c 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -202,6 +202,7 @@ struct trace_probe { | |||
202 | unsigned long nhit; | 202 | unsigned long nhit; |
203 | unsigned int flags; /* For TP_FLAG_* */ | 203 | unsigned int flags; /* For TP_FLAG_* */ |
204 | const char *symbol; /* symbol name */ | 204 | const char *symbol; /* symbol name */ |
205 | struct ftrace_event_class class; | ||
205 | struct ftrace_event_call call; | 206 | struct ftrace_event_call call; |
206 | struct trace_event event; | 207 | struct trace_event event; |
207 | unsigned int nr_args; | 208 | unsigned int nr_args; |
@@ -323,6 +324,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
323 | goto error; | 324 | goto error; |
324 | } | 325 | } |
325 | 326 | ||
327 | tp->call.class = &tp->class; | ||
326 | tp->call.name = kstrdup(event, GFP_KERNEL); | 328 | tp->call.name = kstrdup(event, GFP_KERNEL); |
327 | if (!tp->call.name) | 329 | if (!tp->call.name) |
328 | goto error; | 330 | goto error; |
@@ -332,8 +334,8 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
332 | goto error; | 334 | goto error; |
333 | } | 335 | } |
334 | 336 | ||
335 | tp->call.class->system = kstrdup(group, GFP_KERNEL); | 337 | tp->class.system = kstrdup(group, GFP_KERNEL); |
336 | if (!tp->call.class->system) | 338 | if (!tp->class.system) |
337 | goto error; | 339 | goto error; |
338 | 340 | ||
339 | INIT_LIST_HEAD(&tp->list); | 341 | INIT_LIST_HEAD(&tp->list); |
@@ -1302,6 +1304,26 @@ static void probe_perf_disable(struct ftrace_event_call *call) | |||
1302 | } | 1304 | } |
1303 | #endif /* CONFIG_PERF_EVENTS */ | 1305 | #endif /* CONFIG_PERF_EVENTS */ |
1304 | 1306 | ||
1307 | static __kprobes | ||
1308 | int kprobe_register(struct ftrace_event_call *event, enum trace_reg type) | ||
1309 | { | ||
1310 | switch (type) { | ||
1311 | case TRACE_REG_REGISTER: | ||
1312 | return probe_event_enable(event); | ||
1313 | case TRACE_REG_UNREGISTER: | ||
1314 | probe_event_disable(event); | ||
1315 | return 0; | ||
1316 | |||
1317 | #ifdef CONFIG_PERF_EVENTS | ||
1318 | case TRACE_REG_PERF_REGISTER: | ||
1319 | return probe_perf_enable(event); | ||
1320 | case TRACE_REG_PERF_UNREGISTER: | ||
1321 | probe_perf_disable(event); | ||
1322 | return 0; | ||
1323 | #endif | ||
1324 | } | ||
1325 | return 0; | ||
1326 | } | ||
1305 | 1327 | ||
1306 | static __kprobes | 1328 | static __kprobes |
1307 | int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) | 1329 | int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) |
@@ -1355,13 +1377,7 @@ static int register_probe_event(struct trace_probe *tp) | |||
1355 | return -ENODEV; | 1377 | return -ENODEV; |
1356 | } | 1378 | } |
1357 | call->enabled = 0; | 1379 | call->enabled = 0; |
1358 | call->regfunc = probe_event_enable; | 1380 | call->class->reg = kprobe_register; |
1359 | call->unregfunc = probe_event_disable; | ||
1360 | |||
1361 | #ifdef CONFIG_PERF_EVENTS | ||
1362 | call->perf_event_enable = probe_perf_enable; | ||
1363 | call->perf_event_disable = probe_perf_disable; | ||
1364 | #endif | ||
1365 | call->data = tp; | 1381 | call->data = tp; |
1366 | ret = trace_add_event_call(call); | 1382 | ret = trace_add_event_call(call); |
1367 | if (ret) { | 1383 | if (ret) { |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index b8d30e7ecd05..a21d366cae46 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -15,8 +15,19 @@ static int sys_refcount_exit; | |||
15 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); | 15 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); |
16 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); | 16 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
17 | 17 | ||
18 | struct ftrace_event_class event_class_syscalls = { | 18 | static int syscall_enter_register(struct ftrace_event_call *event, |
19 | .system = "syscalls" | 19 | enum trace_reg type); |
20 | static int syscall_exit_register(struct ftrace_event_call *event, | ||
21 | enum trace_reg type); | ||
22 | |||
23 | struct ftrace_event_class event_class_syscall_enter = { | ||
24 | .system = "syscalls", | ||
25 | .reg = syscall_enter_register | ||
26 | }; | ||
27 | |||
28 | struct ftrace_event_class event_class_syscall_exit = { | ||
29 | .system = "syscalls", | ||
30 | .reg = syscall_exit_register | ||
20 | }; | 31 | }; |
21 | 32 | ||
22 | extern unsigned long __start_syscalls_metadata[]; | 33 | extern unsigned long __start_syscalls_metadata[]; |
@@ -587,3 +598,44 @@ void perf_sysexit_disable(struct ftrace_event_call *call) | |||
587 | 598 | ||
588 | #endif /* CONFIG_PERF_EVENTS */ | 599 | #endif /* CONFIG_PERF_EVENTS */ |
589 | 600 | ||
601 | static int syscall_enter_register(struct ftrace_event_call *event, | ||
602 | enum trace_reg type) | ||
603 | { | ||
604 | switch (type) { | ||
605 | case TRACE_REG_REGISTER: | ||
606 | return reg_event_syscall_enter(event); | ||
607 | case TRACE_REG_UNREGISTER: | ||
608 | unreg_event_syscall_enter(event); | ||
609 | return 0; | ||
610 | |||
611 | #ifdef CONFIG_PERF_EVENTS | ||
612 | case TRACE_REG_PERF_REGISTER: | ||
613 | return perf_sysenter_enable(event); | ||
614 | case TRACE_REG_PERF_UNREGISTER: | ||
615 | perf_sysenter_disable(event); | ||
616 | return 0; | ||
617 | #endif | ||
618 | } | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int syscall_exit_register(struct ftrace_event_call *event, | ||
623 | enum trace_reg type) | ||
624 | { | ||
625 | switch (type) { | ||
626 | case TRACE_REG_REGISTER: | ||
627 | return reg_event_syscall_exit(event); | ||
628 | case TRACE_REG_UNREGISTER: | ||
629 | unreg_event_syscall_exit(event); | ||
630 | return 0; | ||
631 | |||
632 | #ifdef CONFIG_PERF_EVENTS | ||
633 | case TRACE_REG_PERF_REGISTER: | ||
634 | return perf_sysexit_enable(event); | ||
635 | case TRACE_REG_PERF_UNREGISTER: | ||
636 | perf_sysexit_disable(event); | ||
637 | return 0; | ||
638 | #endif | ||
639 | } | ||
640 | return 0; | ||
641 | } | ||