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 read_lock_irqsave(&tasklist_lock
, flags
);
111 do_each_thread(g
, t
) {
112 set_tsk_thread_flag(t
, TIF_SYSCALL_FTRACE
);
113 } while_each_thread(g
, t
);
115 read_unlock_irqrestore(&tasklist_lock
, flags
);
118 mutex_unlock(&syscall_trace_lock
);
121 void stop_ftrace_syscalls(void)
124 struct task_struct
*g
, *t
;
126 mutex_lock(&syscall_trace_lock
);
128 /* There are perhaps still some users */
132 read_lock_irqsave(&tasklist_lock
, flags
);
134 do_each_thread(g
, t
) {
135 clear_tsk_thread_flag(t
, TIF_SYSCALL_FTRACE
);
136 } while_each_thread(g
, t
);
138 read_unlock_irqrestore(&tasklist_lock
, flags
);
141 mutex_unlock(&syscall_trace_lock
);
144 void ftrace_syscall_enter(struct pt_regs
*regs
)
146 struct syscall_trace_enter
*entry
;
147 struct syscall_metadata
*sys_data
;
148 struct ring_buffer_event
*event
;
152 syscall_nr
= syscall_get_nr(current
, regs
);
154 sys_data
= syscall_nr_to_meta(syscall_nr
);
158 size
= sizeof(*entry
) + sizeof(unsigned long) * sys_data
->nb_args
;
160 event
= trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER
, size
,
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
);
169 trace_current_buffer_unlock_commit(event
, 0, 0);
173 void ftrace_syscall_exit(struct pt_regs
*regs
)
175 struct syscall_trace_exit
*entry
;
176 struct syscall_metadata
*sys_data
;
177 struct ring_buffer_event
*event
;
180 syscall_nr
= syscall_get_nr(current
, regs
);
182 sys_data
= syscall_nr_to_meta(syscall_nr
);
186 event
= trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT
,
187 sizeof(*entry
), 0, 0);
191 entry
= ring_buffer_event_data(event
);
192 entry
->nr
= syscall_nr
;
193 entry
->ret
= syscall_get_return_value(current
, regs
);
195 trace_current_buffer_unlock_commit(event
, 0, 0);
199 static int init_syscall_tracer(struct trace_array
*tr
)
201 start_ftrace_syscalls();
206 static void reset_syscall_tracer(struct trace_array
*tr
)
208 stop_ftrace_syscalls();
209 tracing_reset_online_cpus(tr
);
212 static struct trace_event syscall_enter_event
= {
213 .type
= TRACE_SYSCALL_ENTER
,
214 .trace
= print_syscall_enter
,
217 static struct trace_event syscall_exit_event
= {
218 .type
= TRACE_SYSCALL_EXIT
,
219 .trace
= print_syscall_exit
,
222 static struct tracer syscall_tracer __read_mostly
= {
224 .init
= init_syscall_tracer
,
225 .reset
= reset_syscall_tracer
,
226 .flags
= &syscalls_flags
,
229 __init
int register_ftrace_syscalls(void)
233 ret
= register_ftrace_event(&syscall_enter_event
);
235 printk(KERN_WARNING
"event %d failed to register\n",
236 syscall_enter_event
.type
);
240 ret
= register_ftrace_event(&syscall_exit_event
);
242 printk(KERN_WARNING
"event %d failed to register\n",
243 syscall_exit_event
.type
);
247 return register_tracer(&syscall_tracer
);
249 device_initcall(register_ftrace_syscalls
);