1 #include <linux/kernel.h>
2 #include <linux/ftrace.h>
3 #include <asm/syscall.h>
5 #include "trace_output.h"
8 static atomic_t refcount;
12 TRACE_SYSCALLS_OPT_TYPES = 0x1,
15 static struct tracer_opt syscalls_opts[] = {
16 { TRACER_OPT(syscall_arg_type, TRACE_SYSCALLS_OPT_TYPES) },
20 static struct tracer_flags syscalls_flags = {
21 .val = 0, /* By default: no args types */
26 print_syscall_enter(struct trace_iterator *iter, int flags)
28 struct trace_seq *s = &iter->seq;
29 struct trace_entry *ent = iter->ent;
30 struct syscall_trace_enter *trace;
31 struct syscall_metadata *entry;
34 trace_assign_type(trace, ent);
38 entry = syscall_nr_to_meta(syscall);
42 ret = trace_seq_printf(s, "%s(", entry->name);
44 return TRACE_TYPE_PARTIAL_LINE;
46 for (i = 0; i < entry->nb_args; i++) {
48 if (syscalls_flags.val & TRACE_SYSCALLS_OPT_TYPES) {
49 ret = trace_seq_printf(s, "%s ", entry->types[i]);
51 return TRACE_TYPE_PARTIAL_LINE;
53 /* parameter values */
54 ret = trace_seq_printf(s, "%s: %lx%s ", entry->args[i],
56 i == entry->nb_args - 1 ? ")" : ",");
58 return TRACE_TYPE_PARTIAL_LINE;
62 trace_seq_printf(s, "\n");
63 return TRACE_TYPE_HANDLED;
67 print_syscall_exit(struct trace_iterator *iter, int flags)
69 struct trace_seq *s = &iter->seq;
70 struct trace_entry *ent = iter->ent;
71 struct syscall_trace_exit *trace;
73 struct syscall_metadata *entry;
76 trace_assign_type(trace, ent);
80 entry = syscall_nr_to_meta(syscall);
82 trace_seq_printf(s, "\n");
83 return TRACE_TYPE_HANDLED;
86 ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
89 return TRACE_TYPE_PARTIAL_LINE;
91 return TRACE_TYPE_HANDLED;
94 void start_ftrace_syscalls(void)
97 struct task_struct *g, *t;
99 if (atomic_inc_return(&refcount) != 1)
102 arch_init_ftrace_syscalls();
103 read_lock_irqsave(&tasklist_lock, flags);
105 do_each_thread(g, t) {
106 set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
107 } while_each_thread(g, t);
109 read_unlock_irqrestore(&tasklist_lock, flags);
111 atomic_dec(&refcount);
114 void stop_ftrace_syscalls(void)
117 struct task_struct *g, *t;
119 if (atomic_dec_return(&refcount))
122 read_lock_irqsave(&tasklist_lock, flags);
124 do_each_thread(g, t) {
125 clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
126 } while_each_thread(g, t);
128 read_unlock_irqrestore(&tasklist_lock, flags);
130 atomic_inc(&refcount);
133 void ftrace_syscall_enter(struct pt_regs *regs)
135 struct syscall_trace_enter *entry;
136 struct syscall_metadata *sys_data;
137 struct ring_buffer_event *event;
142 syscall_nr = syscall_get_nr(current, regs);
144 cpu = raw_smp_processor_id();
146 sys_data = syscall_nr_to_meta(syscall_nr);
150 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
152 event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER, size,
157 entry = ring_buffer_event_data(event);
158 entry->nr = syscall_nr;
159 syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args);
161 trace_current_buffer_unlock_commit(event, 0, 0);
165 void ftrace_syscall_exit(struct pt_regs *regs)
167 struct syscall_trace_exit *entry;
168 struct syscall_metadata *sys_data;
169 struct ring_buffer_event *event;
173 syscall_nr = syscall_get_nr(current, regs);
175 cpu = raw_smp_processor_id();
177 sys_data = syscall_nr_to_meta(syscall_nr);
181 event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT,
182 sizeof(*entry), 0, 0);
186 entry = ring_buffer_event_data(event);
187 entry->nr = syscall_nr;
188 entry->ret = syscall_get_return_value(current, regs);
190 trace_current_buffer_unlock_commit(event, 0, 0);
194 static int init_syscall_tracer(struct trace_array *tr)
196 start_ftrace_syscalls();
201 static void reset_syscall_tracer(struct trace_array *tr)
203 stop_ftrace_syscalls();
206 static struct trace_event syscall_enter_event = {
207 .type = TRACE_SYSCALL_ENTER,
208 .trace = print_syscall_enter,
211 static struct trace_event syscall_exit_event = {
212 .type = TRACE_SYSCALL_EXIT,
213 .trace = print_syscall_exit,
216 static struct tracer syscall_tracer __read_mostly = {
218 .init = init_syscall_tracer,
219 .reset = reset_syscall_tracer,
220 .flags = &syscalls_flags,
223 __init int register_ftrace_syscalls(void)
227 ret = register_ftrace_event(&syscall_enter_event);
229 printk(KERN_WARNING "event %d failed to register\n",
230 syscall_enter_event.type);
234 ret = register_ftrace_event(&syscall_exit_event);
236 printk(KERN_WARNING "event %d failed to register\n",
237 syscall_exit_event.type);
241 return register_tracer(&syscall_tracer);
243 device_initcall(register_ftrace_syscalls);