1 #include <trace/syscall.h>
2 #include <linux/kernel.h>
3 #include <asm/syscall.h>
5 #include "trace_output.h"
8 /* Keep a counter of the syscall tracing users */
11 /* Prevent from races on thread flags toggling */
12 static DEFINE_MUTEX(syscall_trace_lock
);
14 /* Option to display the parameters types */
16 TRACE_SYSCALLS_OPT_TYPES
= 0x1,
19 static struct tracer_opt syscalls_opts
[] = {
20 { TRACER_OPT(syscall_arg_type
, TRACE_SYSCALLS_OPT_TYPES
) },
24 static struct tracer_flags syscalls_flags
= {
25 .val
= 0, /* By default: no parameters types */
30 print_syscall_enter(struct trace_iterator
*iter
, int flags
)
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
;
38 trace_assign_type(trace
, ent
);
42 entry
= syscall_nr_to_meta(syscall
);
46 ret
= trace_seq_printf(s
, "%s(", entry
->name
);
48 return TRACE_TYPE_PARTIAL_LINE
;
50 for (i
= 0; i
< entry
->nb_args
; i
++) {
52 if (syscalls_flags
.val
& TRACE_SYSCALLS_OPT_TYPES
) {
53 ret
= trace_seq_printf(s
, "%s ", entry
->types
[i
]);
55 return TRACE_TYPE_PARTIAL_LINE
;
57 /* parameter values */
58 ret
= trace_seq_printf(s
, "%s: %lx%s ", entry
->args
[i
],
60 i
== entry
->nb_args
- 1 ? ")" : ",");
62 return TRACE_TYPE_PARTIAL_LINE
;
66 trace_seq_printf(s
, "\n");
67 return TRACE_TYPE_HANDLED
;
71 print_syscall_exit(struct trace_iterator
*iter
, int flags
)
73 struct trace_seq
*s
= &iter
->seq
;
74 struct trace_entry
*ent
= iter
->ent
;
75 struct syscall_trace_exit
*trace
;
77 struct syscall_metadata
*entry
;
80 trace_assign_type(trace
, ent
);
84 entry
= syscall_nr_to_meta(syscall
);
86 trace_seq_printf(s
, "\n");
87 return TRACE_TYPE_HANDLED
;
90 ret
= trace_seq_printf(s
, "%s -> 0x%lx\n", entry
->name
,
93 return TRACE_TYPE_PARTIAL_LINE
;
95 return TRACE_TYPE_HANDLED
;
98 void start_ftrace_syscalls(void)
101 struct task_struct
*g
, *t
;
103 mutex_lock(&syscall_trace_lock
);
105 /* Don't enable the flag on the tasks twice */
109 arch_init_ftrace_syscalls();
110 read_lock_irqsave(&tasklist_lock
, flags
);
112 do_each_thread(g
, t
) {
113 set_tsk_thread_flag(t
, TIF_SYSCALL_FTRACE
);
114 } while_each_thread(g
, t
);
116 read_unlock_irqrestore(&tasklist_lock
, flags
);
119 mutex_unlock(&syscall_trace_lock
);
122 void stop_ftrace_syscalls(void)
125 struct task_struct
*g
, *t
;
127 mutex_lock(&syscall_trace_lock
);
129 /* There are perhaps still some users */
133 read_lock_irqsave(&tasklist_lock
, flags
);
135 do_each_thread(g
, t
) {
136 clear_tsk_thread_flag(t
, TIF_SYSCALL_FTRACE
);
137 } while_each_thread(g
, t
);
139 read_unlock_irqrestore(&tasklist_lock
, flags
);
142 mutex_unlock(&syscall_trace_lock
);
145 void ftrace_syscall_enter(struct pt_regs
*regs
)
147 struct syscall_trace_enter
*entry
;
148 struct syscall_metadata
*sys_data
;
149 struct ring_buffer_event
*event
;
153 syscall_nr
= syscall_get_nr(current
, regs
);
155 sys_data
= syscall_nr_to_meta(syscall_nr
);
159 size
= sizeof(*entry
) + sizeof(unsigned long) * sys_data
->nb_args
;
161 event
= trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER
, size
,
166 entry
= ring_buffer_event_data(event
);
167 entry
->nr
= syscall_nr
;
168 syscall_get_arguments(current
, regs
, 0, sys_data
->nb_args
, entry
->args
);
170 trace_current_buffer_unlock_commit(event
, 0, 0);
174 void ftrace_syscall_exit(struct pt_regs
*regs
)
176 struct syscall_trace_exit
*entry
;
177 struct syscall_metadata
*sys_data
;
178 struct ring_buffer_event
*event
;
181 syscall_nr
= syscall_get_nr(current
, regs
);
183 sys_data
= syscall_nr_to_meta(syscall_nr
);
187 event
= trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT
,
188 sizeof(*entry
), 0, 0);
192 entry
= ring_buffer_event_data(event
);
193 entry
->nr
= syscall_nr
;
194 entry
->ret
= syscall_get_return_value(current
, regs
);
196 trace_current_buffer_unlock_commit(event
, 0, 0);
200 static int init_syscall_tracer(struct trace_array
*tr
)
202 start_ftrace_syscalls();
207 static void reset_syscall_tracer(struct trace_array
*tr
)
209 stop_ftrace_syscalls();
210 tracing_reset_online_cpus(tr
);
213 static struct trace_event syscall_enter_event
= {
214 .type
= TRACE_SYSCALL_ENTER
,
215 .trace
= print_syscall_enter
,
218 static struct trace_event syscall_exit_event
= {
219 .type
= TRACE_SYSCALL_EXIT
,
220 .trace
= print_syscall_exit
,
223 static struct tracer syscall_tracer __read_mostly
= {
225 .init
= init_syscall_tracer
,
226 .reset
= reset_syscall_tracer
,
227 .flags
= &syscalls_flags
,
230 __init
int register_ftrace_syscalls(void)
234 ret
= register_ftrace_event(&syscall_enter_event
);
236 printk(KERN_WARNING
"event %d failed to register\n",
237 syscall_enter_event
.type
);
241 ret
= register_ftrace_event(&syscall_exit_event
);
243 printk(KERN_WARNING
"event %d failed to register\n",
244 syscall_exit_event
.type
);
248 return register_tracer(&syscall_tracer
);
250 device_initcall(register_ftrace_syscalls
);