aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_syscalls.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2009-03-13 10:42:11 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-13 11:57:42 -0400
commitbed1ffca022cc876fb83161d26670e9b5d3cf36b (patch)
treea896c79e9ea1af11f992826f1de7e2ece52fbe33 /kernel/trace/trace_syscalls.c
parentf58ba100678f421bdcb000a3c71793f432dfab93 (diff)
tracing/syscalls: core infrastructure for syscalls tracing, enhancements
Impact: new feature This adds the generic support for syscalls tracing. This is currently exploited through a devoted tracer but other tracing engines can use it. (They just have to play with {start,stop}_ftrace_syscalls() and use the display callbacks unless they want to override them.) The syscalls prototypes definitions are abused here to steal some metadata informations: - syscall name, param types, param names, number of params The syscall addr is not directly saved during this definition because we don't know if its prototype is available in the namespace. But we don't really need it. The arch has just to build a function able to resolve the syscall number to its metadata struct. The current tracer prints the syscall names, parameters names and values (and their types optionally). Currently the value is a raw hex but higher level values diplaying is on my TODO list. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <1236955332-10133-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace_syscalls.c')
-rw-r--r--kernel/trace/trace_syscalls.c146
1 files changed, 138 insertions, 8 deletions
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 66cf97449af3..c72e599230ff 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)