aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace.h17
-rw-r--r--kernel/trace/trace_syscalls.c146
2 files changed, 155 insertions, 8 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 3d49daae47d..d80ca0d464d 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -194,6 +194,19 @@ struct kmemtrace_free_entry {
194 const void *ptr; 194 const void *ptr;
195}; 195};
196 196
197struct syscall_trace_enter {
198 struct trace_entry ent;
199 int nr;
200 unsigned long args[];
201};
202
203struct syscall_trace_exit {
204 struct trace_entry ent;
205 int nr;
206 unsigned long ret;
207};
208
209
197/* 210/*
198 * trace_flag_type is an enumeration that holds different 211 * trace_flag_type is an enumeration that holds different
199 * states when a trace occurs. These are: 212 * states when a trace occurs. These are:
@@ -306,6 +319,10 @@ extern void __ftrace_bad_type(void);
306 TRACE_KMEM_ALLOC); \ 319 TRACE_KMEM_ALLOC); \
307 IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \ 320 IF_ASSIGN(var, ent, struct kmemtrace_free_entry, \
308 TRACE_KMEM_FREE); \ 321 TRACE_KMEM_FREE); \
322 IF_ASSIGN(var, ent, struct syscall_trace_enter, \
323 TRACE_SYSCALL_ENTER); \
324 IF_ASSIGN(var, ent, struct syscall_trace_exit, \
325 TRACE_SYSCALL_EXIT); \
309 __ftrace_bad_type(); \ 326 __ftrace_bad_type(); \
310 } while (0) 327 } while (0)
311 328
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 66cf97449af..c72e599230f 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -1,6 +1,5 @@
1#include <linux/ftrace.h>
2#include <linux/kernel.h> 1#include <linux/kernel.h>
3 2#include <linux/ftrace.h>
4#include <asm/syscall.h> 3#include <asm/syscall.h>
5 4
6#include "trace_output.h" 5#include "trace_output.h"
@@ -8,6 +7,90 @@
8 7
9static atomic_t refcount; 8static atomic_t refcount;
10 9
10/* Our two options */
11enum {
12 TRACE_SYSCALLS_OPT_TYPES = 0x1,
13};
14
15static struct tracer_opt syscalls_opts[] = {
16 { TRACER_OPT(syscall_arg_type, TRACE_SYSCALLS_OPT_TYPES) },
17 { }
18};
19
20static struct tracer_flags syscalls_flags = {
21 .val = 0, /* By default: no args types */
22 .opts = syscalls_opts
23};
24
25enum print_line_t
26print_syscall_enter(struct trace_iterator *iter, int flags)
27{
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;
32 int i, ret, syscall;
33
34 trace_assign_type(trace, ent);
35
36 syscall = trace->nr;
37
38 entry = syscall_nr_to_meta(syscall);
39 if (!entry)
40 goto end;
41
42 ret = trace_seq_printf(s, "%s(", entry->name);
43 if (!ret)
44 return TRACE_TYPE_PARTIAL_LINE;
45
46 for (i = 0; i < entry->nb_args; i++) {
47 /* parameter types */
48 if (syscalls_flags.val & TRACE_SYSCALLS_OPT_TYPES) {
49 ret = trace_seq_printf(s, "%s ", entry->types[i]);
50 if (!ret)
51 return TRACE_TYPE_PARTIAL_LINE;
52 }
53 /* parameter values */
54 ret = trace_seq_printf(s, "%s: %lx%s ", entry->args[i],
55 trace->args[i],
56 i == entry->nb_args - 1 ? ")" : ",");
57 if (!ret)
58 return TRACE_TYPE_PARTIAL_LINE;
59 }
60
61end:
62 trace_seq_printf(s, "\n");
63 return TRACE_TYPE_HANDLED;
64}
65
66enum print_line_t
67print_syscall_exit(struct trace_iterator *iter, int flags)
68{
69 struct trace_seq *s = &iter->seq;
70 struct trace_entry *ent = iter->ent;
71 struct syscall_trace_exit *trace;
72 int syscall;
73 struct syscall_metadata *entry;
74 int ret;
75
76 trace_assign_type(trace, ent);
77
78 syscall = trace->nr;
79
80 entry = syscall_nr_to_meta(syscall);
81 if (!entry) {
82 trace_seq_printf(s, "\n");
83 return TRACE_TYPE_HANDLED;
84 }
85
86 ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
87 trace->ret);
88 if (!ret)
89 return TRACE_TYPE_PARTIAL_LINE;
90
91 return TRACE_TYPE_HANDLED;
92}
93
11void start_ftrace_syscalls(void) 94void start_ftrace_syscalls(void)
12{ 95{
13 unsigned long flags; 96 unsigned long flags;
@@ -16,6 +99,7 @@ void start_ftrace_syscalls(void)
16 if (atomic_inc_return(&refcount) != 1) 99 if (atomic_inc_return(&refcount) != 1)
17 goto out; 100 goto out;
18 101
102 arch_init_ftrace_syscalls();
19 read_lock_irqsave(&tasklist_lock, flags); 103 read_lock_irqsave(&tasklist_lock, flags);
20 104
21 do_each_thread(g, t) { 105 do_each_thread(g, t) {
@@ -48,20 +132,63 @@ out:
48 132
49void ftrace_syscall_enter(struct pt_regs *regs) 133void ftrace_syscall_enter(struct pt_regs *regs)
50{ 134{
135 struct syscall_trace_enter *entry;
136 struct syscall_metadata *sys_data;
137 struct ring_buffer_event *event;
138 int size;
51 int syscall_nr; 139 int syscall_nr;
140 int cpu;
52 141
53 syscall_nr = syscall_get_nr(current, regs); 142 syscall_nr = syscall_get_nr(current, regs);
54 143
55 trace_printk("syscall %d enter\n", syscall_nr); 144 cpu = raw_smp_processor_id();
145
146 sys_data = syscall_nr_to_meta(syscall_nr);
147 if (!sys_data)
148 return;
149
150 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
151
152 event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_ENTER, size,
153 0, 0);
154 if (!event)
155 return;
156
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);
160
161 trace_current_buffer_unlock_commit(event, 0, 0);
162 trace_wake_up();
56} 163}
57 164
58void ftrace_syscall_exit(struct pt_regs *regs) 165void ftrace_syscall_exit(struct pt_regs *regs)
59{ 166{
167 struct syscall_trace_exit *entry;
168 struct syscall_metadata *sys_data;
169 struct ring_buffer_event *event;
60 int syscall_nr; 170 int syscall_nr;
171 int cpu;
61 172
62 syscall_nr = syscall_get_nr(current, regs); 173 syscall_nr = syscall_get_nr(current, regs);
63 174
64 trace_printk("syscall %d exit\n", syscall_nr); 175 cpu = raw_smp_processor_id();
176
177 sys_data = syscall_nr_to_meta(syscall_nr);
178 if (!sys_data)
179 return;
180
181 event = trace_current_buffer_lock_reserve(TRACE_SYSCALL_EXIT,
182 sizeof(*entry), 0, 0);
183 if (!event)
184 return;
185
186 entry = ring_buffer_event_data(event);
187 entry->nr = syscall_nr;
188 entry->ret = syscall_get_return_value(current, regs);
189
190 trace_current_buffer_unlock_commit(event, 0, 0);
191 trace_wake_up();
65} 192}
66 193
67static int init_syscall_tracer(struct trace_array *tr) 194static int init_syscall_tracer(struct trace_array *tr)
@@ -77,17 +204,20 @@ static void reset_syscall_tracer(struct trace_array *tr)
77} 204}
78 205
79static struct trace_event syscall_enter_event = { 206static struct trace_event syscall_enter_event = {
80 .type = TRACE_SYSCALL_ENTER, 207 .type = TRACE_SYSCALL_ENTER,
208 .trace = print_syscall_enter,
81}; 209};
82 210
83static struct trace_event syscall_exit_event = { 211static struct trace_event syscall_exit_event = {
84 .type = TRACE_SYSCALL_EXIT, 212 .type = TRACE_SYSCALL_EXIT,
213 .trace = print_syscall_exit,
85}; 214};
86 215
87static struct tracer syscall_tracer __read_mostly = { 216static struct tracer syscall_tracer __read_mostly = {
88 .name = "syscall", 217 .name = "syscall",
89 .init = init_syscall_tracer, 218 .init = init_syscall_tracer,
90 .reset = reset_syscall_tracer 219 .reset = reset_syscall_tracer,
220 .flags = &syscalls_flags,
91}; 221};
92 222
93__init int register_ftrace_syscalls(void) 223__init int register_ftrace_syscalls(void)