]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - kernel/trace/trace_syscalls.c
tracing: Add ftrace_event_call void * 'data' field
[mirror_ubuntu-artful-kernel.git] / kernel / trace / trace_syscalls.c
CommitLineData
47788c58 1#include <trace/syscall.h>
ee08c6ec 2#include <linux/kernel.h>
ee08c6ec
FW
3#include <asm/syscall.h>
4
5#include "trace_output.h"
6#include "trace.h"
7
5be71b61
FW
8/* Keep a counter of the syscall tracing users */
9static int refcount;
10
11/* Prevent from races on thread flags toggling */
12static DEFINE_MUTEX(syscall_trace_lock);
ee08c6ec 13
64044345 14/* Option to display the parameters types */
bed1ffca
FW
15enum {
16 TRACE_SYSCALLS_OPT_TYPES = 0x1,
17};
18
19static struct tracer_opt syscalls_opts[] = {
20 { TRACER_OPT(syscall_arg_type, TRACE_SYSCALLS_OPT_TYPES) },
21 { }
22};
23
24static struct tracer_flags syscalls_flags = {
64044345 25 .val = 0, /* By default: no parameters types */
bed1ffca
FW
26 .opts = syscalls_opts
27};
28
29enum print_line_t
30print_syscall_enter(struct trace_iterator *iter, int flags)
31{
32 struct trace_seq *s = &iter->seq;
33 struct trace_entry *ent = iter->ent;
34 struct syscall_trace_enter *trace;
35 struct syscall_metadata *entry;
36 int i, ret, syscall;
37
38 trace_assign_type(trace, ent);
39
40 syscall = trace->nr;
41
42 entry = syscall_nr_to_meta(syscall);
43 if (!entry)
44 goto end;
45
46 ret = trace_seq_printf(s, "%s(", entry->name);
47 if (!ret)
48 return TRACE_TYPE_PARTIAL_LINE;
49
50 for (i = 0; i < entry->nb_args; i++) {
51 /* parameter types */
52 if (syscalls_flags.val & TRACE_SYSCALLS_OPT_TYPES) {
53 ret = trace_seq_printf(s, "%s ", entry->types[i]);
54 if (!ret)
55 return TRACE_TYPE_PARTIAL_LINE;
56 }
57 /* parameter values */
58 ret = trace_seq_printf(s, "%s: %lx%s ", entry->args[i],
59 trace->args[i],
60 i == entry->nb_args - 1 ? ")" : ",");
61 if (!ret)
62 return TRACE_TYPE_PARTIAL_LINE;
63 }
64
65end:
66 trace_seq_printf(s, "\n");
67 return TRACE_TYPE_HANDLED;
68}
69
70enum print_line_t
71print_syscall_exit(struct trace_iterator *iter, int flags)
72{
73 struct trace_seq *s = &iter->seq;
74 struct trace_entry *ent = iter->ent;
75 struct syscall_trace_exit *trace;
76 int syscall;
77 struct syscall_metadata *entry;
78 int ret;
79
80 trace_assign_type(trace, ent);
81
82 syscall = trace->nr;
83
84 entry = syscall_nr_to_meta(syscall);
85 if (!entry) {
86 trace_seq_printf(s, "\n");
87 return TRACE_TYPE_HANDLED;
88 }
89
90 ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
91 trace->ret);
92 if (!ret)
93 return TRACE_TYPE_PARTIAL_LINE;
94
95 return TRACE_TYPE_HANDLED;
96}
97
ee08c6ec
FW
98void start_ftrace_syscalls(void)
99{
100 unsigned long flags;
101 struct task_struct *g, *t;
102
5be71b61
FW
103 mutex_lock(&syscall_trace_lock);
104
ac99c58c 105 /* Don't enable the flag on the tasks twice */
5be71b61
FW
106 if (++refcount != 1)
107 goto unlock;
ee08c6ec
FW
108
109 read_lock_irqsave(&tasklist_lock, flags);
110
111 do_each_thread(g, t) {
112 set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
113 } while_each_thread(g, t);
114
115 read_unlock_irqrestore(&tasklist_lock, flags);
5be71b61
FW
116
117unlock:
118 mutex_unlock(&syscall_trace_lock);
ee08c6ec
FW
119}
120
121void stop_ftrace_syscalls(void)
122{
123 unsigned long flags;
124 struct task_struct *g, *t;
125
5be71b61
FW
126 mutex_lock(&syscall_trace_lock);
127
ac99c58c 128 /* There are perhaps still some users */
5be71b61
FW
129 if (--refcount)
130 goto unlock;
ee08c6ec
FW
131
132 read_lock_irqsave(&tasklist_lock, flags);
133
134 do_each_thread(g, t) {
135 clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
136 } while_each_thread(g, t);
137
138 read_unlock_irqrestore(&tasklist_lock, flags);
5be71b61
FW
139
140unlock:
141 mutex_unlock(&syscall_trace_lock);
ee08c6ec
FW
142}
143
144void ftrace_syscall_enter(struct pt_regs *regs)
145{
bed1ffca
FW
146 struct syscall_trace_enter *entry;
147 struct syscall_metadata *sys_data;
148 struct ring_buffer_event *event;
149 int size;
ee08c6ec
FW
150 int syscall_nr;
151
152 syscall_nr = syscall_get_nr(current, regs);
153
bed1ffca
FW
154 sys_data = syscall_nr_to_meta(syscall_nr);
155 if (!sys_data)
156 return;
157
158 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
159
160 event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER, size,
161 0, 0);
162 if (!event)
163 return;
164
165 entry = ring_buffer_event_data(event);
166 entry->nr = syscall_nr;
167 syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args);
168
169 trace_current_buffer_unlock_commit(event, 0, 0);
170 trace_wake_up();
ee08c6ec
FW
171}
172
173void ftrace_syscall_exit(struct pt_regs *regs)
174{
bed1ffca
FW
175 struct syscall_trace_exit *entry;
176 struct syscall_metadata *sys_data;
177 struct ring_buffer_event *event;
ee08c6ec
FW
178 int syscall_nr;
179
180 syscall_nr = syscall_get_nr(current, regs);
181
bed1ffca
FW
182 sys_data = syscall_nr_to_meta(syscall_nr);
183 if (!sys_data)
184 return;
185
186 event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT,
187 sizeof(*entry), 0, 0);
188 if (!event)
189 return;
190
191 entry = ring_buffer_event_data(event);
192 entry->nr = syscall_nr;
193 entry->ret = syscall_get_return_value(current, regs);
194
195 trace_current_buffer_unlock_commit(event, 0, 0);
196 trace_wake_up();
ee08c6ec
FW
197}
198
199static int init_syscall_tracer(struct trace_array *tr)
200{
201 start_ftrace_syscalls();
202
203 return 0;
204}
205
206static void reset_syscall_tracer(struct trace_array *tr)
207{
208 stop_ftrace_syscalls();
ac99c58c 209 tracing_reset_online_cpus(tr);
ee08c6ec
FW
210}
211
212static struct trace_event syscall_enter_event = {
bed1ffca
FW
213 .type = TRACE_SYSCALL_ENTER,
214 .trace = print_syscall_enter,
ee08c6ec
FW
215};
216
217static struct trace_event syscall_exit_event = {
bed1ffca
FW
218 .type = TRACE_SYSCALL_EXIT,
219 .trace = print_syscall_exit,
ee08c6ec
FW
220};
221
222static struct tracer syscall_tracer __read_mostly = {
bed1ffca 223 .name = "syscall",
ee08c6ec 224 .init = init_syscall_tracer,
bed1ffca
FW
225 .reset = reset_syscall_tracer,
226 .flags = &syscalls_flags,
ee08c6ec
FW
227};
228
229__init int register_ftrace_syscalls(void)
230{
231 int ret;
232
233 ret = register_ftrace_event(&syscall_enter_event);
234 if (!ret) {
235 printk(KERN_WARNING "event %d failed to register\n",
236 syscall_enter_event.type);
237 WARN_ON_ONCE(1);
238 }
239
240 ret = register_ftrace_event(&syscall_exit_event);
241 if (!ret) {
242 printk(KERN_WARNING "event %d failed to register\n",
243 syscall_exit_event.type);
244 WARN_ON_ONCE(1);
245 }
246
247 return register_tracer(&syscall_tracer);
248}
249device_initcall(register_ftrace_syscalls);