aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-03-13 05:23:39 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-13 05:23:39 -0400
commit62a394eb77a1ddea73273f53ed8c3ccf6e04f2fb (patch)
treeee72d87524b29eb9457b45e02a4587d8fbd9191d
parentd2e82546ae98eee353fae57e389f487586fe380d (diff)
parent1b3fa2ce64363c289b3b14723cca7290bf91cfce (diff)
Merge branches 'tracing/ftrace' and 'tracing/syscalls'; commit 'v2.6.29-rc8' into tracing/core
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/thread_info.h9
-rw-r--r--arch/x86/kernel/ptrace.c7
-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
8 files changed, 161 insertions, 3 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bdcee12c25ab..b0a638b4199a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -35,6 +35,7 @@ config X86
35 select HAVE_FUNCTION_GRAPH_TRACER 35 select HAVE_FUNCTION_GRAPH_TRACER
36 select HAVE_FUNCTION_TRACE_MCOUNT_TEST 36 select HAVE_FUNCTION_TRACE_MCOUNT_TEST
37 select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE 37 select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
38 select HAVE_FTRACE_SYSCALLS
38 select HAVE_KVM 39 select HAVE_KVM
39 select HAVE_ARCH_KGDB 40 select HAVE_ARCH_KGDB
40 select HAVE_ARCH_TRACEHOOK 41 select HAVE_ARCH_TRACEHOOK
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index df9d5f78385e..8820a73ae090 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -94,6 +94,7 @@ struct thread_info {
94#define TIF_FORCED_TF 24 /* true if TF in eflags artificially */ 94#define TIF_FORCED_TF 24 /* true if TF in eflags artificially */
95#define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */ 95#define TIF_DEBUGCTLMSR 25 /* uses thread_struct.debugctlmsr */
96#define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */ 96#define TIF_DS_AREA_MSR 26 /* uses thread_struct.ds_area_msr */
97#define TIF_SYSCALL_FTRACE 27 /* for ftrace syscall instrumentation */
97 98
98#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) 99#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
99#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) 100#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
@@ -115,15 +116,17 @@ struct thread_info {
115#define _TIF_FORCED_TF (1 << TIF_FORCED_TF) 116#define _TIF_FORCED_TF (1 << TIF_FORCED_TF)
116#define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR) 117#define _TIF_DEBUGCTLMSR (1 << TIF_DEBUGCTLMSR)
117#define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR) 118#define _TIF_DS_AREA_MSR (1 << TIF_DS_AREA_MSR)
119#define _TIF_SYSCALL_FTRACE (1 << TIF_SYSCALL_FTRACE)
118 120
119/* work to do in syscall_trace_enter() */ 121/* work to do in syscall_trace_enter() */
120#define _TIF_WORK_SYSCALL_ENTRY \ 122#define _TIF_WORK_SYSCALL_ENTRY \
121 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | \ 123 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_FTRACE | \
122 _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | _TIF_SINGLESTEP) 124 _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | _TIF_SINGLESTEP)
123 125
124/* work to do in syscall_trace_leave() */ 126/* work to do in syscall_trace_leave() */
125#define _TIF_WORK_SYSCALL_EXIT \ 127#define _TIF_WORK_SYSCALL_EXIT \
126 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP) 128 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \
129 _TIF_SYSCALL_FTRACE)
127 130
128/* work to do on interrupt/exception return */ 131/* work to do on interrupt/exception return */
129#define _TIF_WORK_MASK \ 132#define _TIF_WORK_MASK \
@@ -132,7 +135,7 @@ struct thread_info {
132 _TIF_SINGLESTEP|_TIF_SECCOMP|_TIF_SYSCALL_EMU)) 135 _TIF_SINGLESTEP|_TIF_SECCOMP|_TIF_SYSCALL_EMU))
133 136
134/* work to do on any return to user space */ 137/* work to do on any return to user space */
135#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP) 138#define _TIF_ALLWORK_MASK ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_FTRACE)
136 139
137/* Only used for 64 bit */ 140/* Only used for 64 bit */
138#define _TIF_DO_NOTIFY_MASK \ 141#define _TIF_DO_NOTIFY_MASK \
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 3d9672e59c16..99749d6e87a8 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -21,6 +21,7 @@
21#include <linux/audit.h> 21#include <linux/audit.h>
22#include <linux/seccomp.h> 22#include <linux/seccomp.h>
23#include <linux/signal.h> 23#include <linux/signal.h>
24#include <linux/ftrace.h>
24 25
25#include <asm/uaccess.h> 26#include <asm/uaccess.h>
26#include <asm/pgtable.h> 27#include <asm/pgtable.h>
@@ -1416,6 +1417,9 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
1416 tracehook_report_syscall_entry(regs)) 1417 tracehook_report_syscall_entry(regs))
1417 ret = -1L; 1418 ret = -1L;
1418 1419
1420 if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
1421 ftrace_syscall_enter(regs);
1422
1419 if (unlikely(current->audit_context)) { 1423 if (unlikely(current->audit_context)) {
1420 if (IS_IA32) 1424 if (IS_IA32)
1421 audit_syscall_entry(AUDIT_ARCH_I386, 1425 audit_syscall_entry(AUDIT_ARCH_I386,
@@ -1439,6 +1443,9 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
1439 if (unlikely(current->audit_context)) 1443 if (unlikely(current->audit_context))
1440 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax); 1444 audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
1441 1445
1446 if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE)))
1447 ftrace_syscall_exit(regs);
1448
1442 if (test_thread_flag(TIF_SYSCALL_TRACE)) 1449 if (test_thread_flag(TIF_SYSCALL_TRACE))
1443 tracehook_report_syscall_exit(regs, 0); 1450 tracehook_report_syscall_exit(regs, 0);
1444 1451
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 67595b8f0f15..56ce34d90b03 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -31,6 +31,8 @@ enum trace_type {
31 TRACE_GRAPH_ENT, 31 TRACE_GRAPH_ENT,
32 TRACE_USER_STACK, 32 TRACE_USER_STACK,
33 TRACE_HW_BRANCHES, 33 TRACE_HW_BRANCHES,
34 TRACE_SYSCALL_ENTER,
35 TRACE_SYSCALL_EXIT,
34 TRACE_KMEM_ALLOC, 36 TRACE_KMEM_ALLOC,
35 TRACE_KMEM_FREE, 37 TRACE_KMEM_FREE,
36 TRACE_POWER, 38 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);