tracing/ftrace: syscall tracing infrastructure, basics
[linux-2.6] / kernel / trace / trace_syscalls.c
1 #include <linux/ftrace.h>
2 #include <linux/kernel.h>
3
4 #include <asm/syscall.h>
5
6 #include "trace_output.h"
7 #include "trace.h"
8
9 static atomic_t refcount;
10
11 void start_ftrace_syscalls(void)
12 {
13         unsigned long flags;
14         struct task_struct *g, *t;
15
16         if (atomic_inc_return(&refcount) != 1)
17                 goto out;
18
19         read_lock_irqsave(&tasklist_lock, flags);
20
21         do_each_thread(g, t) {
22                 set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
23         } while_each_thread(g, t);
24
25         read_unlock_irqrestore(&tasklist_lock, flags);
26 out:
27         atomic_dec(&refcount);
28 }
29
30 void stop_ftrace_syscalls(void)
31 {
32         unsigned long flags;
33         struct task_struct *g, *t;
34
35         if (atomic_dec_return(&refcount))
36                 goto out;
37
38         read_lock_irqsave(&tasklist_lock, flags);
39
40         do_each_thread(g, t) {
41                 clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
42         } while_each_thread(g, t);
43
44         read_unlock_irqrestore(&tasklist_lock, flags);
45 out:
46         atomic_inc(&refcount);
47 }
48
49 void ftrace_syscall_enter(struct pt_regs *regs)
50 {
51         int syscall_nr;
52
53         syscall_nr = syscall_get_nr(current, regs);
54
55         trace_printk("syscall %d enter\n", syscall_nr);
56 }
57
58 void ftrace_syscall_exit(struct pt_regs *regs)
59 {
60         int syscall_nr;
61
62         syscall_nr = syscall_get_nr(current, regs);
63
64         trace_printk("syscall %d exit\n", syscall_nr);
65 }
66
67 static int init_syscall_tracer(struct trace_array *tr)
68 {
69         start_ftrace_syscalls();
70
71         return 0;
72 }
73
74 static void reset_syscall_tracer(struct trace_array *tr)
75 {
76         stop_ftrace_syscalls();
77 }
78
79 static struct trace_event syscall_enter_event = {
80         .type           = TRACE_SYSCALL_ENTER,
81 };
82
83 static struct trace_event syscall_exit_event = {
84         .type           = TRACE_SYSCALL_EXIT,
85 };
86
87 static struct tracer syscall_tracer __read_mostly = {
88         .name           = "syscall",
89         .init           = init_syscall_tracer,
90         .reset          = reset_syscall_tracer
91 };
92
93 __init int register_ftrace_syscalls(void)
94 {
95         int ret;
96
97         ret = register_ftrace_event(&syscall_enter_event);
98         if (!ret) {
99                 printk(KERN_WARNING "event %d failed to register\n",
100                        syscall_enter_event.type);
101                 WARN_ON_ONCE(1);
102         }
103
104         ret = register_ftrace_event(&syscall_exit_event);
105         if (!ret) {
106                 printk(KERN_WARNING "event %d failed to register\n",
107                        syscall_exit_event.type);
108                 WARN_ON_ONCE(1);
109         }
110
111         return register_tracer(&syscall_tracer);
112 }
113 device_initcall(register_ftrace_syscalls);