diff options
-rw-r--r-- | include/linux/tracepoint.h | 3 | ||||
-rw-r--r-- | include/trace/irq_event_types.h | 24 | ||||
-rw-r--r-- | include/trace/sched_event_types.h | 124 | ||||
-rw-r--r-- | include/trace/trace_event_types.h | 4 | ||||
-rw-r--r-- | include/trace/trace_events.h | 4 | ||||
-rw-r--r-- | kernel/trace/events.c | 20 | ||||
-rw-r--r-- | kernel/trace/trace.c | 14 | ||||
-rw-r--r-- | kernel/trace/trace.h | 32 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 294 | ||||
-rw-r--r-- | kernel/trace/trace_events.h | 55 | ||||
-rw-r--r-- | kernel/trace/trace_events_stage_1.h | 34 | ||||
-rw-r--r-- | kernel/trace/trace_events_stage_2.h | 72 | ||||
-rw-r--r-- | kernel/trace/trace_events_stage_3.h | 219 |
13 files changed, 776 insertions, 123 deletions
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 62d13391a240..152b2f03fb86 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -157,4 +157,7 @@ static inline void tracepoint_synchronize_unregister(void) | |||
157 | #define TRACE_FORMAT(name, proto, args, fmt) \ | 157 | #define TRACE_FORMAT(name, proto, args, fmt) \ |
158 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) | 158 | DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) |
159 | 159 | ||
160 | #define TRACE_EVENT_FORMAT(name, proto, args, fmt, struct, tpfmt) \ | ||
161 | TRACE_FORMAT(name, PARAMS(proto), PARAMS(args), PARAMS(fmt)) | ||
162 | |||
160 | #endif | 163 | #endif |
diff --git a/include/trace/irq_event_types.h b/include/trace/irq_event_types.h index 5d0919fdd2d4..65850bc5ea06 100644 --- a/include/trace/irq_event_types.h +++ b/include/trace/irq_event_types.h | |||
@@ -5,13 +5,29 @@ | |||
5 | # error Unless you know what you are doing. | 5 | # error Unless you know what you are doing. |
6 | #endif | 6 | #endif |
7 | 7 | ||
8 | TRACE_FORMAT(irq_handler_entry, | 8 | #undef TRACE_SYSTEM |
9 | #define TRACE_SYSTEM irq | ||
10 | |||
11 | TRACE_EVENT_FORMAT(irq_handler_entry, | ||
9 | TPPROTO(int irq, struct irqaction *action), | 12 | TPPROTO(int irq, struct irqaction *action), |
10 | TPARGS(irq, action), | 13 | TPARGS(irq, action), |
11 | TPFMT("irq=%d handler=%s", irq, action->name)); | 14 | TPFMT("irq=%d handler=%s", irq, action->name), |
15 | TRACE_STRUCT( | ||
16 | TRACE_FIELD(int, irq, irq) | ||
17 | ), | ||
18 | TPRAWFMT("irq %d") | ||
19 | ); | ||
12 | 20 | ||
13 | TRACE_FORMAT(irq_handler_exit, | 21 | TRACE_EVENT_FORMAT(irq_handler_exit, |
14 | TPPROTO(int irq, struct irqaction *action, int ret), | 22 | TPPROTO(int irq, struct irqaction *action, int ret), |
15 | TPARGS(irq, action, ret), | 23 | TPARGS(irq, action, ret), |
16 | TPFMT("irq=%d handler=%s return=%s", | 24 | TPFMT("irq=%d handler=%s return=%s", |
17 | irq, action->name, ret ? "handled" : "unhandled")); | 25 | irq, action->name, ret ? "handled" : "unhandled"), |
26 | TRACE_STRUCT( | ||
27 | TRACE_FIELD(int, irq, irq) | ||
28 | TRACE_FIELD(int, ret, ret) | ||
29 | ), | ||
30 | TPRAWFMT("irq %d ret %d") | ||
31 | ); | ||
32 | |||
33 | #undef TRACE_SYSTEM | ||
diff --git a/include/trace/sched_event_types.h b/include/trace/sched_event_types.h index a3d3d66a51c8..ba059c10b58a 100644 --- a/include/trace/sched_event_types.h +++ b/include/trace/sched_event_types.h | |||
@@ -1,72 +1,146 @@ | |||
1 | 1 | ||
2 | /* use <trace/sched.h> instead */ | 2 | /* use <trace/sched.h> instead */ |
3 | #ifndef TRACE_FORMAT | 3 | #ifndef TRACE_EVENT_FORMAT |
4 | # error Do not include this file directly. | 4 | # error Do not include this file directly. |
5 | # error Unless you know what you are doing. | 5 | # error Unless you know what you are doing. |
6 | #endif | 6 | #endif |
7 | 7 | ||
8 | TRACE_FORMAT(sched_kthread_stop, | 8 | #undef TRACE_SYSTEM |
9 | #define TRACE_SYSTEM sched | ||
10 | |||
11 | TRACE_EVENT_FORMAT(sched_kthread_stop, | ||
9 | TPPROTO(struct task_struct *t), | 12 | TPPROTO(struct task_struct *t), |
10 | TPARGS(t), | 13 | TPARGS(t), |
11 | TPFMT("task %s:%d", t->comm, t->pid)); | 14 | TPFMT("task %s:%d", t->comm, t->pid), |
15 | TRACE_STRUCT( | ||
16 | TRACE_FIELD(pid_t, pid, t->pid) | ||
17 | ), | ||
18 | TPRAWFMT("task %d") | ||
19 | ); | ||
12 | 20 | ||
13 | TRACE_FORMAT(sched_kthread_stop_ret, | 21 | TRACE_EVENT_FORMAT(sched_kthread_stop_ret, |
14 | TPPROTO(int ret), | 22 | TPPROTO(int ret), |
15 | TPARGS(ret), | 23 | TPARGS(ret), |
16 | TPFMT("ret=%d", ret)); | 24 | TPFMT("ret=%d", ret), |
25 | TRACE_STRUCT( | ||
26 | TRACE_FIELD(int, ret, ret) | ||
27 | ), | ||
28 | TPRAWFMT("ret=%d") | ||
29 | ); | ||
17 | 30 | ||
18 | TRACE_FORMAT(sched_wait_task, | 31 | TRACE_EVENT_FORMAT(sched_wait_task, |
19 | TPPROTO(struct rq *rq, struct task_struct *p), | 32 | TPPROTO(struct rq *rq, struct task_struct *p), |
20 | TPARGS(rq, p), | 33 | TPARGS(rq, p), |
21 | TPFMT("task %s:%d", p->comm, p->pid)); | 34 | TPFMT("task %s:%d", p->comm, p->pid), |
35 | TRACE_STRUCT( | ||
36 | TRACE_FIELD(pid_t, pid, p->pid) | ||
37 | ), | ||
38 | TPRAWFMT("task %d") | ||
39 | ); | ||
22 | 40 | ||
23 | TRACE_FORMAT(sched_wakeup, | 41 | TRACE_EVENT_FORMAT(sched_wakeup, |
24 | TPPROTO(struct rq *rq, struct task_struct *p, int success), | 42 | TPPROTO(struct rq *rq, struct task_struct *p, int success), |
25 | TPARGS(rq, p, success), | 43 | TPARGS(rq, p, success), |
26 | TPFMT("task %s:%d %s", | 44 | TPFMT("task %s:%d %s", |
27 | p->comm, p->pid, success?"succeeded":"failed")); | 45 | p->comm, p->pid, success ? "succeeded" : "failed"), |
46 | TRACE_STRUCT( | ||
47 | TRACE_FIELD(pid_t, pid, p->pid) | ||
48 | TRACE_FIELD(int, success, success) | ||
49 | ), | ||
50 | TPRAWFMT("task %d success=%d") | ||
51 | ); | ||
28 | 52 | ||
29 | TRACE_FORMAT(sched_wakeup_new, | 53 | TRACE_EVENT_FORMAT(sched_wakeup_new, |
30 | TPPROTO(struct rq *rq, struct task_struct *p, int success), | 54 | TPPROTO(struct rq *rq, struct task_struct *p, int success), |
31 | TPARGS(rq, p, success), | 55 | TPARGS(rq, p, success), |
32 | TPFMT("task %s:%d", | 56 | TPFMT("task %s:%d", |
33 | p->comm, p->pid, success?"succeeded":"failed")); | 57 | p->comm, p->pid, success ? "succeeded" : "failed"), |
58 | TRACE_STRUCT( | ||
59 | TRACE_FIELD(pid_t, pid, p->pid) | ||
60 | TRACE_FIELD(int, success, success) | ||
61 | ), | ||
62 | TPRAWFMT("task %d success=%d") | ||
63 | ); | ||
34 | 64 | ||
35 | TRACE_FORMAT(sched_switch, | 65 | TRACE_EVENT_FORMAT(sched_switch, |
36 | TPPROTO(struct rq *rq, struct task_struct *prev, | 66 | TPPROTO(struct rq *rq, struct task_struct *prev, |
37 | struct task_struct *next), | 67 | struct task_struct *next), |
38 | TPARGS(rq, prev, next), | 68 | TPARGS(rq, prev, next), |
39 | TPFMT("task %s:%d ==> %s:%d", | 69 | TPFMT("task %s:%d ==> %s:%d", |
40 | prev->comm, prev->pid, next->comm, next->pid)); | 70 | prev->comm, prev->pid, next->comm, next->pid), |
71 | TRACE_STRUCT( | ||
72 | TRACE_FIELD(pid_t, prev_pid, prev->pid) | ||
73 | TRACE_FIELD(int, prev_prio, prev->prio) | ||
74 | TRACE_FIELD(pid_t, next_pid, next->pid) | ||
75 | TRACE_FIELD(int, next_prio, next->prio) | ||
76 | ), | ||
77 | TPRAWFMT("prev %d:%d ==> next %d:%d") | ||
78 | ); | ||
41 | 79 | ||
42 | TRACE_FORMAT(sched_migrate_task, | 80 | TRACE_EVENT_FORMAT(sched_migrate_task, |
43 | TPPROTO(struct task_struct *p, int orig_cpu, int dest_cpu), | 81 | TPPROTO(struct task_struct *p, int orig_cpu, int dest_cpu), |
44 | TPARGS(p, orig_cpu, dest_cpu), | 82 | TPARGS(p, orig_cpu, dest_cpu), |
45 | TPFMT("task %s:%d from: %d to: %d", | 83 | TPFMT("task %s:%d from: %d to: %d", |
46 | p->comm, p->pid, orig_cpu, dest_cpu)); | 84 | p->comm, p->pid, orig_cpu, dest_cpu), |
85 | TRACE_STRUCT( | ||
86 | TRACE_FIELD(pid_t, pid, p->pid) | ||
87 | TRACE_FIELD(int, orig_cpu, orig_cpu) | ||
88 | TRACE_FIELD(int, dest_cpu, dest_cpu) | ||
89 | ), | ||
90 | TPRAWFMT("task %d from: %d to: %d") | ||
91 | ); | ||
47 | 92 | ||
48 | TRACE_FORMAT(sched_process_free, | 93 | TRACE_EVENT_FORMAT(sched_process_free, |
49 | TPPROTO(struct task_struct *p), | 94 | TPPROTO(struct task_struct *p), |
50 | TPARGS(p), | 95 | TPARGS(p), |
51 | TPFMT("task %s:%d", p->comm, p->pid)); | 96 | TPFMT("task %s:%d", p->comm, p->pid), |
97 | TRACE_STRUCT( | ||
98 | TRACE_FIELD(pid_t, pid, p->pid) | ||
99 | ), | ||
100 | TPRAWFMT("task %d") | ||
101 | ); | ||
52 | 102 | ||
53 | TRACE_FORMAT(sched_process_exit, | 103 | TRACE_EVENT_FORMAT(sched_process_exit, |
54 | TPPROTO(struct task_struct *p), | 104 | TPPROTO(struct task_struct *p), |
55 | TPARGS(p), | 105 | TPARGS(p), |
56 | TPFMT("task %s:%d", p->comm, p->pid)); | 106 | TPFMT("task %s:%d", p->comm, p->pid), |
107 | TRACE_STRUCT( | ||
108 | TRACE_FIELD(pid_t, pid, p->pid) | ||
109 | ), | ||
110 | TPRAWFMT("task %d") | ||
111 | ); | ||
57 | 112 | ||
58 | TRACE_FORMAT(sched_process_wait, | 113 | TRACE_EVENT_FORMAT(sched_process_wait, |
59 | TPPROTO(struct pid *pid), | 114 | TPPROTO(struct pid *pid), |
60 | TPARGS(pid), | 115 | TPARGS(pid), |
61 | TPFMT("pid %d", pid)); | 116 | TPFMT("pid %d", pid_nr(pid)), |
117 | TRACE_STRUCT( | ||
118 | TRACE_FIELD(pid_t, pid, pid_nr(pid)) | ||
119 | ), | ||
120 | TPRAWFMT("task %d") | ||
121 | ); | ||
62 | 122 | ||
63 | TRACE_FORMAT(sched_process_fork, | 123 | TRACE_EVENT_FORMAT(sched_process_fork, |
64 | TPPROTO(struct task_struct *parent, struct task_struct *child), | 124 | TPPROTO(struct task_struct *parent, struct task_struct *child), |
65 | TPARGS(parent, child), | 125 | TPARGS(parent, child), |
66 | TPFMT("parent %s:%d child %s:%d", | 126 | TPFMT("parent %s:%d child %s:%d", |
67 | parent->comm, parent->pid, child->comm, child->pid)); | 127 | parent->comm, parent->pid, child->comm, child->pid), |
128 | TRACE_STRUCT( | ||
129 | TRACE_FIELD(pid_t, parent, parent->pid) | ||
130 | TRACE_FIELD(pid_t, child, child->pid) | ||
131 | ), | ||
132 | TPRAWFMT("parent %d child %d") | ||
133 | ); | ||
68 | 134 | ||
69 | TRACE_FORMAT(sched_signal_send, | 135 | TRACE_EVENT_FORMAT(sched_signal_send, |
70 | TPPROTO(int sig, struct task_struct *p), | 136 | TPPROTO(int sig, struct task_struct *p), |
71 | TPARGS(sig, p), | 137 | TPARGS(sig, p), |
72 | TPFMT("sig: %d task %s:%d", sig, p->comm, p->pid)); | 138 | TPFMT("sig: %d task %s:%d", sig, p->comm, p->pid), |
139 | TRACE_STRUCT( | ||
140 | TRACE_FIELD(int, sig, sig) | ||
141 | TRACE_FIELD(pid_t, pid, p->pid) | ||
142 | ), | ||
143 | TPRAWFMT("sig: %d task %d") | ||
144 | ); | ||
145 | |||
146 | #undef TRACE_SYSTEM | ||
diff --git a/include/trace/trace_event_types.h b/include/trace/trace_event_types.h new file mode 100644 index 000000000000..33c8ed5ccb6c --- /dev/null +++ b/include/trace/trace_event_types.h | |||
@@ -0,0 +1,4 @@ | |||
1 | /* trace/<type>_event_types.h here */ | ||
2 | |||
3 | #include <trace/sched_event_types.h> | ||
4 | #include <trace/irq_event_types.h> | ||
diff --git a/include/trace/trace_events.h b/include/trace/trace_events.h new file mode 100644 index 000000000000..ea2ef2051762 --- /dev/null +++ b/include/trace/trace_events.h | |||
@@ -0,0 +1,4 @@ | |||
1 | /* trace/<type>.h here */ | ||
2 | |||
3 | #include <trace/sched.h> | ||
4 | #include <trace/irq.h> | ||
diff --git a/kernel/trace/events.c b/kernel/trace/events.c index 3c75623893cc..f2509cbaacea 100644 --- a/kernel/trace/events.c +++ b/kernel/trace/events.c | |||
@@ -1,15 +1,17 @@ | |||
1 | /* | 1 | /* |
2 | * This is the place to register all trace points as events. | 2 | * This is the place to register all trace points as events. |
3 | * Include the trace/<type>.h at the top. | ||
4 | * Include the trace/<type>_event_types.h at the bottom. | ||
5 | */ | 3 | */ |
6 | 4 | ||
7 | /* trace/<type>.h here */ | 5 | /* someday this needs to go in a generic header */ |
8 | #include <trace/sched.h> | 6 | #define __STR(x) #x |
9 | #include <trace/irq.h> | 7 | #define STR(x) __STR(x) |
10 | 8 | ||
11 | #include "trace_events.h" | 9 | #include <trace/trace_events.h> |
12 | 10 | ||
13 | /* trace/<type>_event_types.h here */ | 11 | #include "trace_output.h" |
14 | #include <trace/sched_event_types.h> | 12 | |
15 | #include <trace/irq_event_types.h> | 13 | #include "trace_events_stage_1.h" |
14 | #include "trace_events_stage_2.h" | ||
15 | #include "trace_events_stage_3.h" | ||
16 | |||
17 | #include <trace/trace_event_types.h> | ||
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 9c5987aca74b..c5e39cd7310d 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -846,6 +846,20 @@ void trace_buffer_unlock_commit(struct trace_array *tr, | |||
846 | trace_wake_up(); | 846 | trace_wake_up(); |
847 | } | 847 | } |
848 | 848 | ||
849 | struct ring_buffer_event * | ||
850 | trace_current_buffer_lock_reserve(unsigned char type, unsigned long len, | ||
851 | unsigned long flags, int pc) | ||
852 | { | ||
853 | return trace_buffer_lock_reserve(&global_trace, | ||
854 | type, len, flags, pc); | ||
855 | } | ||
856 | |||
857 | void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, | ||
858 | unsigned long flags, int pc) | ||
859 | { | ||
860 | return trace_buffer_unlock_commit(&global_trace, event, flags, pc); | ||
861 | } | ||
862 | |||
849 | void | 863 | void |
850 | trace_function(struct trace_array *tr, | 864 | trace_function(struct trace_array *tr, |
851 | unsigned long ip, unsigned long parent_ip, unsigned long flags, | 865 | unsigned long ip, unsigned long parent_ip, unsigned long flags, |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 632191770aac..f6fa0b9f83a8 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -442,6 +442,12 @@ void trace_buffer_unlock_commit(struct trace_array *tr, | |||
442 | struct ring_buffer_event *event, | 442 | struct ring_buffer_event *event, |
443 | unsigned long flags, int pc); | 443 | unsigned long flags, int pc); |
444 | 444 | ||
445 | struct ring_buffer_event * | ||
446 | trace_current_buffer_lock_reserve(unsigned char type, unsigned long len, | ||
447 | unsigned long flags, int pc); | ||
448 | void trace_current_buffer_unlock_commit(struct ring_buffer_event *event, | ||
449 | unsigned long flags, int pc); | ||
450 | |||
445 | struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, | 451 | struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, |
446 | struct trace_array_cpu *data); | 452 | struct trace_array_cpu *data); |
447 | 453 | ||
@@ -720,4 +726,30 @@ static inline void trace_branch_disable(void) | |||
720 | } | 726 | } |
721 | #endif /* CONFIG_BRANCH_TRACER */ | 727 | #endif /* CONFIG_BRANCH_TRACER */ |
722 | 728 | ||
729 | /* trace event type bit fields, not numeric */ | ||
730 | enum { | ||
731 | TRACE_EVENT_TYPE_PRINTF = 1, | ||
732 | TRACE_EVENT_TYPE_RAW = 2, | ||
733 | }; | ||
734 | |||
735 | struct ftrace_event_call { | ||
736 | char *name; | ||
737 | char *system; | ||
738 | struct dentry *dir; | ||
739 | int enabled; | ||
740 | int (*regfunc)(void); | ||
741 | void (*unregfunc)(void); | ||
742 | int id; | ||
743 | struct dentry *raw_dir; | ||
744 | int raw_enabled; | ||
745 | int type; | ||
746 | int (*raw_init)(void); | ||
747 | int (*raw_reg)(void); | ||
748 | void (*raw_unreg)(void); | ||
749 | }; | ||
750 | |||
751 | void event_trace_printk(unsigned long ip, const char *fmt, ...); | ||
752 | extern struct ftrace_event_call __start_ftrace_events[]; | ||
753 | extern struct ftrace_event_call __stop_ftrace_events[]; | ||
754 | |||
723 | #endif /* _LINUX_KERNEL_TRACE_H */ | 755 | #endif /* _LINUX_KERNEL_TRACE_H */ |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 3bcb9df93342..1d07f800a9ce 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -10,7 +10,9 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/ctype.h> | 11 | #include <linux/ctype.h> |
12 | 12 | ||
13 | #include "trace_events.h" | 13 | #include "trace.h" |
14 | |||
15 | #define TRACE_SYSTEM "TRACE_SYSTEM" | ||
14 | 16 | ||
15 | #define events_for_each(event) \ | 17 | #define events_for_each(event) \ |
16 | for (event = __start_ftrace_events; \ | 18 | for (event = __start_ftrace_events; \ |
@@ -42,35 +44,87 @@ static void ftrace_clear_events(void) | |||
42 | } | 44 | } |
43 | } | 45 | } |
44 | 46 | ||
47 | static void ftrace_event_enable_disable(struct ftrace_event_call *call, | ||
48 | int enable) | ||
49 | { | ||
50 | |||
51 | switch (enable) { | ||
52 | case 0: | ||
53 | if (call->enabled) { | ||
54 | call->enabled = 0; | ||
55 | call->unregfunc(); | ||
56 | } | ||
57 | if (call->raw_enabled) { | ||
58 | call->raw_enabled = 0; | ||
59 | call->raw_unreg(); | ||
60 | } | ||
61 | break; | ||
62 | case 1: | ||
63 | if (!call->enabled && | ||
64 | (call->type & TRACE_EVENT_TYPE_PRINTF)) { | ||
65 | call->enabled = 1; | ||
66 | call->regfunc(); | ||
67 | } | ||
68 | if (!call->raw_enabled && | ||
69 | (call->type & TRACE_EVENT_TYPE_RAW)) { | ||
70 | call->raw_enabled = 1; | ||
71 | call->raw_reg(); | ||
72 | } | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | |||
45 | static int ftrace_set_clr_event(char *buf, int set) | 77 | static int ftrace_set_clr_event(char *buf, int set) |
46 | { | 78 | { |
47 | struct ftrace_event_call *call = __start_ftrace_events; | 79 | struct ftrace_event_call *call = __start_ftrace_events; |
48 | 80 | char *event = NULL, *sub = NULL, *match; | |
81 | int ret = -EINVAL; | ||
82 | |||
83 | /* | ||
84 | * The buf format can be <subsystem>:<event-name> | ||
85 | * *:<event-name> means any event by that name. | ||
86 | * :<event-name> is the same. | ||
87 | * | ||
88 | * <subsystem>:* means all events in that subsystem | ||
89 | * <subsystem>: means the same. | ||
90 | * | ||
91 | * <name> (no ':') means all events in a subsystem with | ||
92 | * the name <name> or any event that matches <name> | ||
93 | */ | ||
94 | |||
95 | match = strsep(&buf, ":"); | ||
96 | if (buf) { | ||
97 | sub = match; | ||
98 | event = buf; | ||
99 | match = NULL; | ||
100 | |||
101 | if (!strlen(sub) || strcmp(sub, "*") == 0) | ||
102 | sub = NULL; | ||
103 | if (!strlen(event) || strcmp(event, "*") == 0) | ||
104 | event = NULL; | ||
105 | } | ||
49 | 106 | ||
50 | events_for_each(call) { | 107 | events_for_each(call) { |
51 | 108 | ||
52 | if (!call->name) | 109 | if (!call->name) |
53 | continue; | 110 | continue; |
54 | 111 | ||
55 | if (strcmp(buf, call->name) != 0) | 112 | if (match && |
113 | strcmp(match, call->name) != 0 && | ||
114 | strcmp(match, call->system) != 0) | ||
56 | continue; | 115 | continue; |
57 | 116 | ||
58 | if (set) { | 117 | if (sub && strcmp(sub, call->system) != 0) |
59 | /* Already set? */ | 118 | continue; |
60 | if (call->enabled) | 119 | |
61 | return 0; | 120 | if (event && strcmp(event, call->name) != 0) |
62 | call->enabled = 1; | 121 | continue; |
63 | call->regfunc(); | 122 | |
64 | } else { | 123 | ftrace_event_enable_disable(call, set); |
65 | /* Already cleared? */ | 124 | |
66 | if (!call->enabled) | 125 | ret = 0; |
67 | return 0; | ||
68 | call->enabled = 0; | ||
69 | call->unregfunc(); | ||
70 | } | ||
71 | return 0; | ||
72 | } | 126 | } |
73 | return -EINVAL; | 127 | return ret; |
74 | } | 128 | } |
75 | 129 | ||
76 | /* 128 should be much more than enough */ | 130 | /* 128 should be much more than enough */ |
@@ -200,6 +254,8 @@ static int t_show(struct seq_file *m, void *v) | |||
200 | { | 254 | { |
201 | struct ftrace_event_call *call = v; | 255 | struct ftrace_event_call *call = v; |
202 | 256 | ||
257 | if (strcmp(call->system, TRACE_SYSTEM) != 0) | ||
258 | seq_printf(m, "%s:", call->system); | ||
203 | seq_printf(m, "%s\n", call->name); | 259 | seq_printf(m, "%s\n", call->name); |
204 | 260 | ||
205 | return 0; | 261 | return 0; |
@@ -236,7 +292,7 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
236 | struct ftrace_event_call *call = filp->private_data; | 292 | struct ftrace_event_call *call = filp->private_data; |
237 | char *buf; | 293 | char *buf; |
238 | 294 | ||
239 | if (call->enabled) | 295 | if (call->enabled || call->raw_enabled) |
240 | buf = "1\n"; | 296 | buf = "1\n"; |
241 | else | 297 | else |
242 | buf = "0\n"; | 298 | buf = "0\n"; |
@@ -267,18 +323,8 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
267 | 323 | ||
268 | switch (val) { | 324 | switch (val) { |
269 | case 0: | 325 | case 0: |
270 | if (!call->enabled) | ||
271 | break; | ||
272 | |||
273 | call->enabled = 0; | ||
274 | call->unregfunc(); | ||
275 | break; | ||
276 | case 1: | 326 | case 1: |
277 | if (call->enabled) | 327 | ftrace_event_enable_disable(call, val); |
278 | break; | ||
279 | |||
280 | call->enabled = 1; | ||
281 | call->regfunc(); | ||
282 | break; | 328 | break; |
283 | 329 | ||
284 | default: | 330 | default: |
@@ -290,6 +336,107 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, | |||
290 | return cnt; | 336 | return cnt; |
291 | } | 337 | } |
292 | 338 | ||
339 | static ssize_t | ||
340 | event_type_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
341 | loff_t *ppos) | ||
342 | { | ||
343 | struct ftrace_event_call *call = filp->private_data; | ||
344 | char buf[16]; | ||
345 | int r = 0; | ||
346 | |||
347 | if (call->type & TRACE_EVENT_TYPE_PRINTF) | ||
348 | r += sprintf(buf, "printf\n"); | ||
349 | |||
350 | if (call->type & TRACE_EVENT_TYPE_RAW) | ||
351 | r += sprintf(buf+r, "raw\n"); | ||
352 | |||
353 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
354 | } | ||
355 | |||
356 | static ssize_t | ||
357 | event_type_write(struct file *filp, const char __user *ubuf, size_t cnt, | ||
358 | loff_t *ppos) | ||
359 | { | ||
360 | struct ftrace_event_call *call = filp->private_data; | ||
361 | char buf[64]; | ||
362 | |||
363 | /* | ||
364 | * If there's only one type, we can't change it. | ||
365 | * And currently we always have printf type, and we | ||
366 | * may or may not have raw type. | ||
367 | * | ||
368 | * This is a redundant check, the file should be read | ||
369 | * only if this is the case anyway. | ||
370 | */ | ||
371 | |||
372 | if (!call->raw_init) | ||
373 | return -EPERM; | ||
374 | |||
375 | if (cnt >= sizeof(buf)) | ||
376 | return -EINVAL; | ||
377 | |||
378 | if (copy_from_user(&buf, ubuf, cnt)) | ||
379 | return -EFAULT; | ||
380 | |||
381 | buf[cnt] = 0; | ||
382 | |||
383 | if (!strncmp(buf, "printf", 6) && | ||
384 | (!buf[6] || isspace(buf[6]))) { | ||
385 | |||
386 | call->type = TRACE_EVENT_TYPE_PRINTF; | ||
387 | |||
388 | /* | ||
389 | * If raw enabled, the disable it and enable | ||
390 | * printf type. | ||
391 | */ | ||
392 | if (call->raw_enabled) { | ||
393 | call->raw_enabled = 0; | ||
394 | call->raw_unreg(); | ||
395 | |||
396 | call->enabled = 1; | ||
397 | call->regfunc(); | ||
398 | } | ||
399 | |||
400 | } else if (!strncmp(buf, "raw", 3) && | ||
401 | (!buf[3] || isspace(buf[3]))) { | ||
402 | |||
403 | call->type = TRACE_EVENT_TYPE_RAW; | ||
404 | |||
405 | /* | ||
406 | * If printf enabled, the disable it and enable | ||
407 | * raw type. | ||
408 | */ | ||
409 | if (call->enabled) { | ||
410 | call->enabled = 0; | ||
411 | call->unregfunc(); | ||
412 | |||
413 | call->raw_enabled = 1; | ||
414 | call->raw_reg(); | ||
415 | } | ||
416 | } else | ||
417 | return -EINVAL; | ||
418 | |||
419 | *ppos += cnt; | ||
420 | |||
421 | return cnt; | ||
422 | } | ||
423 | |||
424 | static ssize_t | ||
425 | event_available_types_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
426 | loff_t *ppos) | ||
427 | { | ||
428 | struct ftrace_event_call *call = filp->private_data; | ||
429 | char buf[16]; | ||
430 | int r = 0; | ||
431 | |||
432 | r += sprintf(buf, "printf\n"); | ||
433 | |||
434 | if (call->raw_init) | ||
435 | r += sprintf(buf+r, "raw\n"); | ||
436 | |||
437 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
438 | } | ||
439 | |||
293 | static const struct seq_operations show_event_seq_ops = { | 440 | static const struct seq_operations show_event_seq_ops = { |
294 | .start = t_start, | 441 | .start = t_start, |
295 | .next = t_next, | 442 | .next = t_next, |
@@ -325,6 +472,17 @@ static const struct file_operations ftrace_enable_fops = { | |||
325 | .write = event_enable_write, | 472 | .write = event_enable_write, |
326 | }; | 473 | }; |
327 | 474 | ||
475 | static const struct file_operations ftrace_type_fops = { | ||
476 | .open = tracing_open_generic, | ||
477 | .read = event_type_read, | ||
478 | .write = event_type_write, | ||
479 | }; | ||
480 | |||
481 | static const struct file_operations ftrace_available_types_fops = { | ||
482 | .open = tracing_open_generic, | ||
483 | .read = event_available_types_read, | ||
484 | }; | ||
485 | |||
328 | static struct dentry *event_trace_events_dir(void) | 486 | static struct dentry *event_trace_events_dir(void) |
329 | { | 487 | { |
330 | static struct dentry *d_tracer; | 488 | static struct dentry *d_tracer; |
@@ -345,10 +503,71 @@ static struct dentry *event_trace_events_dir(void) | |||
345 | return d_events; | 503 | return d_events; |
346 | } | 504 | } |
347 | 505 | ||
506 | struct event_subsystem { | ||
507 | struct list_head list; | ||
508 | const char *name; | ||
509 | struct dentry *entry; | ||
510 | }; | ||
511 | |||
512 | static LIST_HEAD(event_subsystems); | ||
513 | |||
514 | static struct dentry * | ||
515 | event_subsystem_dir(const char *name, struct dentry *d_events) | ||
516 | { | ||
517 | struct event_subsystem *system; | ||
518 | |||
519 | /* First see if we did not already create this dir */ | ||
520 | list_for_each_entry(system, &event_subsystems, list) { | ||
521 | if (strcmp(system->name, name) == 0) | ||
522 | return system->entry; | ||
523 | } | ||
524 | |||
525 | /* need to create new entry */ | ||
526 | system = kmalloc(sizeof(*system), GFP_KERNEL); | ||
527 | if (!system) { | ||
528 | pr_warning("No memory to create event subsystem %s\n", | ||
529 | name); | ||
530 | return d_events; | ||
531 | } | ||
532 | |||
533 | system->entry = debugfs_create_dir(name, d_events); | ||
534 | if (!system->entry) { | ||
535 | pr_warning("Could not create event subsystem %s\n", | ||
536 | name); | ||
537 | kfree(system); | ||
538 | return d_events; | ||
539 | } | ||
540 | |||
541 | system->name = name; | ||
542 | list_add(&system->list, &event_subsystems); | ||
543 | |||
544 | return system->entry; | ||
545 | } | ||
546 | |||
348 | static int | 547 | static int |
349 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | 548 | event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) |
350 | { | 549 | { |
351 | struct dentry *entry; | 550 | struct dentry *entry; |
551 | int ret; | ||
552 | |||
553 | /* | ||
554 | * If the trace point header did not define TRACE_SYSTEM | ||
555 | * then the system would be called "TRACE_SYSTEM". | ||
556 | */ | ||
557 | if (strcmp(call->system, "TRACE_SYSTEM") != 0) | ||
558 | d_events = event_subsystem_dir(call->system, d_events); | ||
559 | |||
560 | if (call->raw_init) { | ||
561 | ret = call->raw_init(); | ||
562 | if (ret < 0) { | ||
563 | pr_warning("Could not initialize trace point" | ||
564 | " events/%s\n", call->name); | ||
565 | return ret; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | /* default the output to printf */ | ||
570 | call->type = TRACE_EVENT_TYPE_PRINTF; | ||
352 | 571 | ||
353 | call->dir = debugfs_create_dir(call->name, d_events); | 572 | call->dir = debugfs_create_dir(call->name, d_events); |
354 | if (!call->dir) { | 573 | if (!call->dir) { |
@@ -363,6 +582,21 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events) | |||
363 | pr_warning("Could not create debugfs " | 582 | pr_warning("Could not create debugfs " |
364 | "'%s/enable' entry\n", call->name); | 583 | "'%s/enable' entry\n", call->name); |
365 | 584 | ||
585 | /* Only let type be writable, if we can change it */ | ||
586 | entry = debugfs_create_file("type", | ||
587 | call->raw_init ? 0644 : 0444, | ||
588 | call->dir, call, | ||
589 | &ftrace_type_fops); | ||
590 | if (!entry) | ||
591 | pr_warning("Could not create debugfs " | ||
592 | "'%s/type' entry\n", call->name); | ||
593 | |||
594 | entry = debugfs_create_file("available_types", 0444, call->dir, call, | ||
595 | &ftrace_available_types_fops); | ||
596 | if (!entry) | ||
597 | pr_warning("Could not create debugfs " | ||
598 | "'%s/type' available_types\n", call->name); | ||
599 | |||
366 | return 0; | 600 | return 0; |
367 | } | 601 | } |
368 | 602 | ||
diff --git a/kernel/trace/trace_events.h b/kernel/trace/trace_events.h deleted file mode 100644 index deb95e5006c8..000000000000 --- a/kernel/trace/trace_events.h +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | #ifndef _LINUX_KERNEL_TRACE_EVENTS_H | ||
2 | #define _LINUX_KERNEL_TRACE_EVENTS_H | ||
3 | |||
4 | #include <linux/debugfs.h> | ||
5 | #include <linux/ftrace.h> | ||
6 | #include "trace.h" | ||
7 | |||
8 | struct ftrace_event_call { | ||
9 | char *name; | ||
10 | struct dentry *dir; | ||
11 | int enabled; | ||
12 | int (*regfunc)(void); | ||
13 | void (*unregfunc)(void); | ||
14 | }; | ||
15 | |||
16 | |||
17 | #undef TPFMT | ||
18 | #define TPFMT(fmt, args...) fmt "\n", ##args | ||
19 | |||
20 | #undef TRACE_FORMAT | ||
21 | #define TRACE_FORMAT(call, proto, args, fmt) \ | ||
22 | static void ftrace_event_##call(proto) \ | ||
23 | { \ | ||
24 | event_trace_printk(_RET_IP_, "(" #call ") " fmt); \ | ||
25 | } \ | ||
26 | \ | ||
27 | static int ftrace_reg_event_##call(void) \ | ||
28 | { \ | ||
29 | int ret; \ | ||
30 | \ | ||
31 | ret = register_trace_##call(ftrace_event_##call); \ | ||
32 | if (!ret) \ | ||
33 | pr_info("event trace: Could not activate trace point " \ | ||
34 | "probe to " #call); \ | ||
35 | return ret; \ | ||
36 | } \ | ||
37 | \ | ||
38 | static void ftrace_unreg_event_##call(void) \ | ||
39 | { \ | ||
40 | unregister_trace_##call(ftrace_event_##call); \ | ||
41 | } \ | ||
42 | \ | ||
43 | static struct ftrace_event_call __used \ | ||
44 | __attribute__((__aligned__(4))) \ | ||
45 | __attribute__((section("_ftrace_events"))) event_##call = { \ | ||
46 | .name = #call, \ | ||
47 | .regfunc = ftrace_reg_event_##call, \ | ||
48 | .unregfunc = ftrace_unreg_event_##call, \ | ||
49 | } | ||
50 | |||
51 | void event_trace_printk(unsigned long ip, const char *fmt, ...); | ||
52 | extern struct ftrace_event_call __start_ftrace_events[]; | ||
53 | extern struct ftrace_event_call __stop_ftrace_events[]; | ||
54 | |||
55 | #endif /* _LINUX_KERNEL_TRACE_EVENTS_H */ | ||
diff --git a/kernel/trace/trace_events_stage_1.h b/kernel/trace/trace_events_stage_1.h new file mode 100644 index 000000000000..fd3bf9382d37 --- /dev/null +++ b/kernel/trace/trace_events_stage_1.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Stage 1 of the trace events. | ||
3 | * | ||
4 | * Override the macros in <trace/trace_event_types.h> to include the following: | ||
5 | * | ||
6 | * struct ftrace_raw_<call> { | ||
7 | * struct trace_entry ent; | ||
8 | * <type> <item>; | ||
9 | * [...] | ||
10 | * }; | ||
11 | * | ||
12 | * The <type> <item> is created by the TRACE_FIELD(type, item, assign) | ||
13 | * macro. We simply do "type item;", and that will create the fields | ||
14 | * in the structure. | ||
15 | */ | ||
16 | |||
17 | #undef TRACE_FORMAT | ||
18 | #define TRACE_FORMAT(call, proto, args, fmt) | ||
19 | |||
20 | #undef TRACE_EVENT_FORMAT | ||
21 | #define TRACE_EVENT_FORMAT(name, proto, args, fmt, tstruct, tpfmt) \ | ||
22 | struct ftrace_raw_##name { \ | ||
23 | struct trace_entry ent; \ | ||
24 | tstruct \ | ||
25 | }; \ | ||
26 | static struct ftrace_event_call event_##name | ||
27 | |||
28 | #undef TRACE_STRUCT | ||
29 | #define TRACE_STRUCT(args...) args | ||
30 | |||
31 | #define TRACE_FIELD(type, item, assign) \ | ||
32 | type item; | ||
33 | |||
34 | #include <trace/trace_event_types.h> | ||
diff --git a/kernel/trace/trace_events_stage_2.h b/kernel/trace/trace_events_stage_2.h new file mode 100644 index 000000000000..3eaaef5f19e1 --- /dev/null +++ b/kernel/trace/trace_events_stage_2.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Stage 2 of the trace events. | ||
3 | * | ||
4 | * Override the macros in <trace/trace_event_types.h> to include the following: | ||
5 | * | ||
6 | * enum print_line_t | ||
7 | * ftrace_raw_output_<call>(struct trace_iterator *iter, int flags) | ||
8 | * { | ||
9 | * struct trace_seq *s = &iter->seq; | ||
10 | * struct ftrace_raw_<call> *field; <-- defined in stage 1 | ||
11 | * struct trace_entry *entry; | ||
12 | * int ret; | ||
13 | * | ||
14 | * entry = iter->ent; | ||
15 | * | ||
16 | * if (entry->type != event_<call>.id) { | ||
17 | * WARN_ON_ONCE(1); | ||
18 | * return TRACE_TYPE_UNHANDLED; | ||
19 | * } | ||
20 | * | ||
21 | * field = (typeof(field))entry; | ||
22 | * | ||
23 | * ret = trace_seq_printf(s, <TPRAWFMT> "%s", <ARGS> "\n"); | ||
24 | * if (!ret) | ||
25 | * return TRACE_TYPE_PARTIAL_LINE; | ||
26 | * | ||
27 | * return TRACE_TYPE_HANDLED; | ||
28 | * } | ||
29 | * | ||
30 | * This is the method used to print the raw event to the trace | ||
31 | * output format. Note, this is not needed if the data is read | ||
32 | * in binary. | ||
33 | */ | ||
34 | |||
35 | #undef TRACE_STRUCT | ||
36 | #define TRACE_STRUCT(args...) args | ||
37 | |||
38 | #undef TRACE_FIELD | ||
39 | #define TRACE_FIELD(type, item, assign) \ | ||
40 | field->item, | ||
41 | |||
42 | |||
43 | #undef TPRAWFMT | ||
44 | #define TPRAWFMT(args...) args | ||
45 | |||
46 | #undef TRACE_EVENT_FORMAT | ||
47 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
48 | enum print_line_t \ | ||
49 | ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \ | ||
50 | { \ | ||
51 | struct trace_seq *s = &iter->seq; \ | ||
52 | struct ftrace_raw_##call *field; \ | ||
53 | struct trace_entry *entry; \ | ||
54 | int ret; \ | ||
55 | \ | ||
56 | entry = iter->ent; \ | ||
57 | \ | ||
58 | if (entry->type != event_##call.id) { \ | ||
59 | WARN_ON_ONCE(1); \ | ||
60 | return TRACE_TYPE_UNHANDLED; \ | ||
61 | } \ | ||
62 | \ | ||
63 | field = (typeof(field))entry; \ | ||
64 | \ | ||
65 | ret = trace_seq_printf(s, tpfmt "%s", tstruct "\n"); \ | ||
66 | if (!ret) \ | ||
67 | return TRACE_TYPE_PARTIAL_LINE; \ | ||
68 | \ | ||
69 | return TRACE_TYPE_HANDLED; \ | ||
70 | } | ||
71 | |||
72 | #include <trace/trace_event_types.h> | ||
diff --git a/kernel/trace/trace_events_stage_3.h b/kernel/trace/trace_events_stage_3.h new file mode 100644 index 000000000000..7a161c49deb4 --- /dev/null +++ b/kernel/trace/trace_events_stage_3.h | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * Stage 3 of the trace events. | ||
3 | * | ||
4 | * Override the macros in <trace/trace_event_types.h> to include the following: | ||
5 | * | ||
6 | * static void ftrace_event_<call>(proto) | ||
7 | * { | ||
8 | * event_trace_printk(_RET_IP_, "(<call>) " <fmt>); | ||
9 | * } | ||
10 | * | ||
11 | * static int ftrace_reg_event_<call>(void) | ||
12 | * { | ||
13 | * int ret; | ||
14 | * | ||
15 | * ret = register_trace_<call>(ftrace_event_<call>); | ||
16 | * if (!ret) | ||
17 | * pr_info("event trace: Could not activate trace point " | ||
18 | * "probe to <call>"); | ||
19 | * return ret; | ||
20 | * } | ||
21 | * | ||
22 | * static void ftrace_unreg_event_<call>(void) | ||
23 | * { | ||
24 | * unregister_trace_<call>(ftrace_event_<call>); | ||
25 | * } | ||
26 | * | ||
27 | * For those macros defined with TRACE_FORMAT: | ||
28 | * | ||
29 | * static struct ftrace_event_call __used | ||
30 | * __attribute__((__aligned__(4))) | ||
31 | * __attribute__((section("_ftrace_events"))) event_<call> = { | ||
32 | * .name = "<call>", | ||
33 | * .regfunc = ftrace_reg_event_<call>, | ||
34 | * .unregfunc = ftrace_unreg_event_<call>, | ||
35 | * } | ||
36 | * | ||
37 | * | ||
38 | * For those macros defined with TRACE_EVENT_FORMAT: | ||
39 | * | ||
40 | * static struct ftrace_event_call event_<call>; | ||
41 | * | ||
42 | * static void ftrace_raw_event_<call>(proto) | ||
43 | * { | ||
44 | * struct ring_buffer_event *event; | ||
45 | * struct ftrace_raw_<call> *entry; <-- defined in stage 1 | ||
46 | * unsigned long irq_flags; | ||
47 | * int pc; | ||
48 | * | ||
49 | * local_save_flags(irq_flags); | ||
50 | * pc = preempt_count(); | ||
51 | * | ||
52 | * event = trace_current_buffer_lock_reserve(event_<call>.id, | ||
53 | * sizeof(struct ftrace_raw_<call>), | ||
54 | * irq_flags, pc); | ||
55 | * if (!event) | ||
56 | * return; | ||
57 | * entry = ring_buffer_event_data(event); | ||
58 | * | ||
59 | * <tstruct>; <-- Here we assign the entries by the TRACE_FIELD. | ||
60 | * | ||
61 | * trace_current_buffer_unlock_commit(event, irq_flags, pc); | ||
62 | * } | ||
63 | * | ||
64 | * static int ftrace_raw_reg_event_<call>(void) | ||
65 | * { | ||
66 | * int ret; | ||
67 | * | ||
68 | * ret = register_trace_<call>(ftrace_raw_event_<call>); | ||
69 | * if (!ret) | ||
70 | * pr_info("event trace: Could not activate trace point " | ||
71 | * "probe to <call>"); | ||
72 | * return ret; | ||
73 | * } | ||
74 | * | ||
75 | * static void ftrace_unreg_event_<call>(void) | ||
76 | * { | ||
77 | * unregister_trace_<call>(ftrace_raw_event_<call>); | ||
78 | * } | ||
79 | * | ||
80 | * static struct trace_event ftrace_event_type_<call> = { | ||
81 | * .trace = ftrace_raw_output_<call>, <-- stage 2 | ||
82 | * }; | ||
83 | * | ||
84 | * static int ftrace_raw_init_event_<call>(void) | ||
85 | * { | ||
86 | * int id; | ||
87 | * | ||
88 | * id = register_ftrace_event(&ftrace_event_type_<call>); | ||
89 | * if (!id) | ||
90 | * return -ENODEV; | ||
91 | * event_<call>.id = id; | ||
92 | * return 0; | ||
93 | * } | ||
94 | * | ||
95 | * static struct ftrace_event_call __used | ||
96 | * __attribute__((__aligned__(4))) | ||
97 | * __attribute__((section("_ftrace_events"))) event_<call> = { | ||
98 | * .name = "<call>", | ||
99 | * .regfunc = ftrace_reg_event_<call>, | ||
100 | * .unregfunc = ftrace_unreg_event_<call>, | ||
101 | * .raw_init = ftrace_raw_init_event_<call>, | ||
102 | * .raw_reg = ftrace_raw_reg_event_<call>, | ||
103 | * .raw_unreg = ftrace_raw_unreg_event_<call>, | ||
104 | * } | ||
105 | * | ||
106 | */ | ||
107 | |||
108 | #undef TPFMT | ||
109 | #define TPFMT(fmt, args...) fmt "\n", ##args | ||
110 | |||
111 | #define _TRACE_FORMAT(call, proto, args, fmt) \ | ||
112 | static void ftrace_event_##call(proto) \ | ||
113 | { \ | ||
114 | event_trace_printk(_RET_IP_, "(" #call ") " fmt); \ | ||
115 | } \ | ||
116 | \ | ||
117 | static int ftrace_reg_event_##call(void) \ | ||
118 | { \ | ||
119 | int ret; \ | ||
120 | \ | ||
121 | ret = register_trace_##call(ftrace_event_##call); \ | ||
122 | if (!ret) \ | ||
123 | pr_info("event trace: Could not activate trace point " \ | ||
124 | "probe to " #call); \ | ||
125 | return ret; \ | ||
126 | } \ | ||
127 | \ | ||
128 | static void ftrace_unreg_event_##call(void) \ | ||
129 | { \ | ||
130 | unregister_trace_##call(ftrace_event_##call); \ | ||
131 | } \ | ||
132 | |||
133 | |||
134 | #undef TRACE_FORMAT | ||
135 | #define TRACE_FORMAT(call, proto, args, fmt) \ | ||
136 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ | ||
137 | static struct ftrace_event_call __used \ | ||
138 | __attribute__((__aligned__(4))) \ | ||
139 | __attribute__((section("_ftrace_events"))) event_##call = { \ | ||
140 | .name = #call, \ | ||
141 | .system = STR(TRACE_SYSTEM), \ | ||
142 | .regfunc = ftrace_reg_event_##call, \ | ||
143 | .unregfunc = ftrace_unreg_event_##call, \ | ||
144 | } | ||
145 | |||
146 | #undef TRACE_FIELD | ||
147 | #define TRACE_FIELD(type, item, assign)\ | ||
148 | entry->item = assign; | ||
149 | |||
150 | #undef TRACE_EVENT_FORMAT | ||
151 | #define TRACE_EVENT_FORMAT(call, proto, args, fmt, tstruct, tpfmt) \ | ||
152 | _TRACE_FORMAT(call, PARAMS(proto), PARAMS(args), PARAMS(fmt)) \ | ||
153 | \ | ||
154 | static struct ftrace_event_call event_##call; \ | ||
155 | \ | ||
156 | static void ftrace_raw_event_##call(proto) \ | ||
157 | { \ | ||
158 | struct ring_buffer_event *event; \ | ||
159 | struct ftrace_raw_##call *entry; \ | ||
160 | unsigned long irq_flags; \ | ||
161 | int pc; \ | ||
162 | \ | ||
163 | local_save_flags(irq_flags); \ | ||
164 | pc = preempt_count(); \ | ||
165 | \ | ||
166 | event = trace_current_buffer_lock_reserve(event_##call.id, \ | ||
167 | sizeof(struct ftrace_raw_##call), \ | ||
168 | irq_flags, pc); \ | ||
169 | if (!event) \ | ||
170 | return; \ | ||
171 | entry = ring_buffer_event_data(event); \ | ||
172 | \ | ||
173 | tstruct; \ | ||
174 | \ | ||
175 | trace_current_buffer_unlock_commit(event, irq_flags, pc); \ | ||
176 | } \ | ||
177 | \ | ||
178 | static int ftrace_raw_reg_event_##call(void) \ | ||
179 | { \ | ||
180 | int ret; \ | ||
181 | \ | ||
182 | ret = register_trace_##call(ftrace_raw_event_##call); \ | ||
183 | if (!ret) \ | ||
184 | pr_info("event trace: Could not activate trace point " \ | ||
185 | "probe to " #call); \ | ||
186 | return ret; \ | ||
187 | } \ | ||
188 | \ | ||
189 | static void ftrace_raw_unreg_event_##call(void) \ | ||
190 | { \ | ||
191 | unregister_trace_##call(ftrace_raw_event_##call); \ | ||
192 | } \ | ||
193 | \ | ||
194 | static struct trace_event ftrace_event_type_##call = { \ | ||
195 | .trace = ftrace_raw_output_##call, \ | ||
196 | }; \ | ||
197 | \ | ||
198 | static int ftrace_raw_init_event_##call(void) \ | ||
199 | { \ | ||
200 | int id; \ | ||
201 | \ | ||
202 | id = register_ftrace_event(&ftrace_event_type_##call); \ | ||
203 | if (!id) \ | ||
204 | return -ENODEV; \ | ||
205 | event_##call.id = id; \ | ||
206 | return 0; \ | ||
207 | } \ | ||
208 | \ | ||
209 | static struct ftrace_event_call __used \ | ||
210 | __attribute__((__aligned__(4))) \ | ||
211 | __attribute__((section("_ftrace_events"))) event_##call = { \ | ||
212 | .name = #call, \ | ||
213 | .system = STR(TRACE_SYSTEM), \ | ||
214 | .regfunc = ftrace_reg_event_##call, \ | ||
215 | .unregfunc = ftrace_unreg_event_##call, \ | ||
216 | .raw_init = ftrace_raw_init_event_##call, \ | ||
217 | .raw_reg = ftrace_raw_reg_event_##call, \ | ||
218 | .raw_unreg = ftrace_raw_unreg_event_##call, \ | ||
219 | } | ||