diff options
Diffstat (limited to 'kernel/trace/trace_syscalls.c')
-rw-r--r-- | kernel/trace/trace_syscalls.c | 113 |
1 files changed, 59 insertions, 54 deletions
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 75289f372dd2..a1834dda85f4 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -143,70 +143,65 @@ extern char *__bad_type_size(void); | |||
143 | #type, #name, offsetof(typeof(trace), name), \ | 143 | #type, #name, offsetof(typeof(trace), name), \ |
144 | sizeof(trace.name), is_signed_type(type) | 144 | sizeof(trace.name), is_signed_type(type) |
145 | 145 | ||
146 | int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | 146 | static |
147 | int __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len) | ||
147 | { | 148 | { |
148 | int i; | 149 | int i; |
149 | int ret; | 150 | int pos = 0; |
150 | struct syscall_metadata *entry = call->data; | ||
151 | struct syscall_trace_enter trace; | ||
152 | int offset = offsetof(struct syscall_trace_enter, args); | ||
153 | 151 | ||
154 | ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | 152 | /* When len=0, we just calculate the needed length */ |
155 | "\tsigned:%u;\n", | 153 | #define LEN_OR_ZERO (len ? len - pos : 0) |
156 | SYSCALL_FIELD(int, nr)); | ||
157 | if (!ret) | ||
158 | return 0; | ||
159 | 154 | ||
155 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); | ||
160 | for (i = 0; i < entry->nb_args; i++) { | 156 | for (i = 0; i < entry->nb_args; i++) { |
161 | ret = trace_seq_printf(s, "\tfield:%s %s;", entry->types[i], | 157 | pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s", |
162 | entry->args[i]); | 158 | entry->args[i], sizeof(unsigned long), |
163 | if (!ret) | 159 | i == entry->nb_args - 1 ? "" : ", "); |
164 | return 0; | ||
165 | ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;" | ||
166 | "\tsigned:%u;\n", offset, | ||
167 | sizeof(unsigned long), | ||
168 | is_signed_type(unsigned long)); | ||
169 | if (!ret) | ||
170 | return 0; | ||
171 | offset += sizeof(unsigned long); | ||
172 | } | 160 | } |
161 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); | ||
173 | 162 | ||
174 | trace_seq_puts(s, "\nprint fmt: \""); | ||
175 | for (i = 0; i < entry->nb_args; i++) { | 163 | for (i = 0; i < entry->nb_args; i++) { |
176 | ret = trace_seq_printf(s, "%s: 0x%%0%zulx%s", entry->args[i], | 164 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
177 | sizeof(unsigned long), | 165 | ", ((unsigned long)(REC->%s))", entry->args[i]); |
178 | i == entry->nb_args - 1 ? "" : ", "); | ||
179 | if (!ret) | ||
180 | return 0; | ||
181 | } | 166 | } |
182 | trace_seq_putc(s, '"'); | ||
183 | 167 | ||
184 | for (i = 0; i < entry->nb_args; i++) { | 168 | #undef LEN_OR_ZERO |
185 | ret = trace_seq_printf(s, ", ((unsigned long)(REC->%s))", | ||
186 | entry->args[i]); | ||
187 | if (!ret) | ||
188 | return 0; | ||
189 | } | ||
190 | 169 | ||
191 | return trace_seq_putc(s, '\n'); | 170 | /* return the length of print_fmt */ |
171 | return pos; | ||
192 | } | 172 | } |
193 | 173 | ||
194 | int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) | 174 | static int set_syscall_print_fmt(struct ftrace_event_call *call) |
195 | { | 175 | { |
196 | int ret; | 176 | char *print_fmt; |
197 | struct syscall_trace_exit trace; | 177 | int len; |
178 | struct syscall_metadata *entry = call->data; | ||
198 | 179 | ||
199 | ret = trace_seq_printf(s, | 180 | if (entry->enter_event != call) { |
200 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | 181 | call->print_fmt = "\"0x%lx\", REC->ret"; |
201 | "\tsigned:%u;\n" | ||
202 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;" | ||
203 | "\tsigned:%u;\n", | ||
204 | SYSCALL_FIELD(int, nr), | ||
205 | SYSCALL_FIELD(long, ret)); | ||
206 | if (!ret) | ||
207 | return 0; | 182 | return 0; |
183 | } | ||
208 | 184 | ||
209 | return trace_seq_printf(s, "\nprint fmt: \"0x%%lx\", REC->ret\n"); | 185 | /* First: called with 0 length to calculate the needed length */ |
186 | len = __set_enter_print_fmt(entry, NULL, 0); | ||
187 | |||
188 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | ||
189 | if (!print_fmt) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | /* Second: actually write the @print_fmt */ | ||
193 | __set_enter_print_fmt(entry, print_fmt, len + 1); | ||
194 | call->print_fmt = print_fmt; | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static void free_syscall_print_fmt(struct ftrace_event_call *call) | ||
200 | { | ||
201 | struct syscall_metadata *entry = call->data; | ||
202 | |||
203 | if (entry->enter_event == call) | ||
204 | kfree(call->print_fmt); | ||
210 | } | 205 | } |
211 | 206 | ||
212 | int syscall_enter_define_fields(struct ftrace_event_call *call) | 207 | int syscall_enter_define_fields(struct ftrace_event_call *call) |
@@ -386,12 +381,22 @@ int init_syscall_trace(struct ftrace_event_call *call) | |||
386 | { | 381 | { |
387 | int id; | 382 | int id; |
388 | 383 | ||
389 | id = register_ftrace_event(call->event); | 384 | if (set_syscall_print_fmt(call) < 0) |
390 | if (!id) | 385 | return -ENOMEM; |
391 | return -ENODEV; | 386 | |
392 | call->id = id; | 387 | id = trace_event_raw_init(call); |
393 | INIT_LIST_HEAD(&call->fields); | 388 | |
394 | return 0; | 389 | if (id < 0) { |
390 | free_syscall_print_fmt(call); | ||
391 | return id; | ||
392 | } | ||
393 | |||
394 | return id; | ||
395 | } | ||
396 | |||
397 | unsigned long __init arch_syscall_addr(int nr) | ||
398 | { | ||
399 | return (unsigned long)sys_call_table[nr]; | ||
395 | } | 400 | } |
396 | 401 | ||
397 | int __init init_ftrace_syscalls(void) | 402 | int __init init_ftrace_syscalls(void) |
@@ -603,7 +608,7 @@ int prof_sysexit_enable(struct ftrace_event_call *call) | |||
603 | ret = register_trace_sys_exit(prof_syscall_exit); | 608 | ret = register_trace_sys_exit(prof_syscall_exit); |
604 | if (ret) { | 609 | if (ret) { |
605 | pr_info("event trace: Could not activate" | 610 | pr_info("event trace: Could not activate" |
606 | "syscall entry trace point"); | 611 | "syscall exit trace point"); |
607 | } else { | 612 | } else { |
608 | set_bit(num, enabled_prof_exit_syscalls); | 613 | set_bit(num, enabled_prof_exit_syscalls); |
609 | sys_prof_refcount_exit++; | 614 | sys_prof_refcount_exit++; |