aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace_event_perf.c15
-rw-r--r--kernel/trace/trace_events.c32
-rw-r--r--kernel/trace/trace_kprobe.c34
-rw-r--r--kernel/trace/trace_syscalls.c56
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
1307static __kprobes
1308int 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
1306static __kprobes 1328static __kprobes
1307int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs) 1329int 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;
15static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); 15static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
16static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); 16static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
17 17
18struct ftrace_event_class event_class_syscalls = { 18static int syscall_enter_register(struct ftrace_event_call *event,
19 .system = "syscalls" 19 enum trace_reg type);
20static int syscall_exit_register(struct ftrace_event_call *event,
21 enum trace_reg type);
22
23struct ftrace_event_class event_class_syscall_enter = {
24 .system = "syscalls",
25 .reg = syscall_enter_register
26};
27
28struct ftrace_event_class event_class_syscall_exit = {
29 .system = "syscalls",
30 .reg = syscall_exit_register
20}; 31};
21 32
22extern unsigned long __start_syscalls_metadata[]; 33extern 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
601static 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
622static 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}