aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace.h21
-rw-r--r--kernel/trace/Kconfig10
-rw-r--r--kernel/trace/Makefile1
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_syscalls.c113
5 files changed, 147 insertions, 0 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index e1583f2639b0..c146c1021a29 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -503,4 +503,25 @@ static inline void trace_hw_branch_oops(void) {}
503 503
504#endif /* CONFIG_HW_BRANCH_TRACER */ 504#endif /* CONFIG_HW_BRANCH_TRACER */
505 505
506/*
507 * A syscall entry in the ftrace syscalls array.
508 *
509 * @syscall_nr: syscall number
510 */
511struct syscall_trace_entry {
512 int syscall_nr;
513};
514
515#ifdef CONFIG_FTRACE_SYSCALLS
516extern void start_ftrace_syscalls(void);
517extern void stop_ftrace_syscalls(void);
518extern void ftrace_syscall_enter(struct pt_regs *regs);
519extern void ftrace_syscall_exit(struct pt_regs *regs);
520#else
521static inline void start_ftrace_syscalls(void) { }
522static inline void stop_ftrace_syscalls(void) { }
523static inline void ftrace_syscall_enter(struct pt_regs *regs) { }
524static inline void ftrace_syscall_exit(struct pt_regs *regs) { }
525#endif
526
506#endif /* _LINUX_FTRACE_H */ 527#endif /* _LINUX_FTRACE_H */
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 8e4a2a61cd75..95a0ad191f19 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -34,6 +34,9 @@ config HAVE_FTRACE_MCOUNT_RECORD
34config HAVE_HW_BRANCH_TRACER 34config HAVE_HW_BRANCH_TRACER
35 bool 35 bool
36 36
37config HAVE_FTRACE_SYSCALLS
38 bool
39
37config TRACER_MAX_TRACE 40config TRACER_MAX_TRACE
38 bool 41 bool
39 42
@@ -175,6 +178,13 @@ config EVENT_TRACER
175 allowing the user to pick and choose which trace point they 178 allowing the user to pick and choose which trace point they
176 want to trace. 179 want to trace.
177 180
181config FTRACE_SYSCALLS
182 bool "Trace syscalls"
183 depends on HAVE_FTRACE_SYSCALLS
184 select TRACING
185 help
186 Basic tracer to catch the syscall entry and exit events.
187
178config BOOT_TRACER 188config BOOT_TRACER
179 bool "Trace boot initcalls" 189 bool "Trace boot initcalls"
180 select TRACING 190 select TRACING
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index c7a2943796eb..c3feea01c3e0 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -43,5 +43,6 @@ obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
43obj-$(CONFIG_EVENT_TRACER) += trace_events.o 43obj-$(CONFIG_EVENT_TRACER) += trace_events.o
44obj-$(CONFIG_EVENT_TRACER) += events.o 44obj-$(CONFIG_EVENT_TRACER) += events.o
45obj-$(CONFIG_EVENT_TRACER) += trace_export.o 45obj-$(CONFIG_EVENT_TRACER) += trace_export.o
46obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o
46 47
47libftrace-y := ftrace.o 48libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index c5e1d8865fe4..3d49daae47dc 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -30,6 +30,8 @@ enum trace_type {
30 TRACE_GRAPH_ENT, 30 TRACE_GRAPH_ENT,
31 TRACE_USER_STACK, 31 TRACE_USER_STACK,
32 TRACE_HW_BRANCHES, 32 TRACE_HW_BRANCHES,
33 TRACE_SYSCALL_ENTER,
34 TRACE_SYSCALL_EXIT,
33 TRACE_KMEM_ALLOC, 35 TRACE_KMEM_ALLOC,
34 TRACE_KMEM_FREE, 36 TRACE_KMEM_FREE,
35 TRACE_POWER, 37 TRACE_POWER,
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
new file mode 100644
index 000000000000..66cf97449af3
--- /dev/null
+++ b/kernel/trace/trace_syscalls.c
@@ -0,0 +1,113 @@
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
9static atomic_t refcount;
10
11void 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);
26out:
27 atomic_dec(&refcount);
28}
29
30void 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);
45out:
46 atomic_inc(&refcount);
47}
48
49void 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
58void 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
67static int init_syscall_tracer(struct trace_array *tr)
68{
69 start_ftrace_syscalls();
70
71 return 0;
72}
73
74static void reset_syscall_tracer(struct trace_array *tr)
75{
76 stop_ftrace_syscalls();
77}
78
79static struct trace_event syscall_enter_event = {
80 .type = TRACE_SYSCALL_ENTER,
81};
82
83static struct trace_event syscall_exit_event = {
84 .type = TRACE_SYSCALL_EXIT,
85};
86
87static 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}
113device_initcall(register_ftrace_syscalls);