diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /kernel/trace/trace_syscalls.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'kernel/trace/trace_syscalls.c')
-rw-r--r-- | kernel/trace/trace_syscalls.c | 397 |
1 files changed, 200 insertions, 197 deletions
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 527e17eae575..4d6d711717f2 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <trace/syscall.h> | 1 | #include <trace/syscall.h> |
2 | #include <trace/events/syscalls.h> | 2 | #include <trace/events/syscalls.h> |
3 | #include <linux/slab.h> | ||
3 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
4 | #include <linux/ftrace.h> | 5 | #include <linux/ftrace.h> |
5 | #include <linux/perf_event.h> | 6 | #include <linux/perf_event.h> |
@@ -14,6 +15,43 @@ static int sys_refcount_exit; | |||
14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); | 15 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); |
15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); | 16 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
16 | 17 | ||
18 | extern unsigned long __start_syscalls_metadata[]; | ||
19 | extern unsigned long __stop_syscalls_metadata[]; | ||
20 | |||
21 | static struct syscall_metadata **syscalls_metadata; | ||
22 | |||
23 | static struct syscall_metadata *find_syscall_meta(unsigned long syscall) | ||
24 | { | ||
25 | struct syscall_metadata *start; | ||
26 | struct syscall_metadata *stop; | ||
27 | char str[KSYM_SYMBOL_LEN]; | ||
28 | |||
29 | |||
30 | start = (struct syscall_metadata *)__start_syscalls_metadata; | ||
31 | stop = (struct syscall_metadata *)__stop_syscalls_metadata; | ||
32 | kallsyms_lookup(syscall, NULL, NULL, NULL, str); | ||
33 | |||
34 | for ( ; start < stop; start++) { | ||
35 | /* | ||
36 | * Only compare after the "sys" prefix. Archs that use | ||
37 | * syscall wrappers may have syscalls symbols aliases prefixed | ||
38 | * with "SyS" instead of "sys", leading to an unwanted | ||
39 | * mismatch. | ||
40 | */ | ||
41 | if (start->name && !strcmp(start->name + 3, str + 3)) | ||
42 | return start; | ||
43 | } | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static struct syscall_metadata *syscall_nr_to_meta(int nr) | ||
48 | { | ||
49 | if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) | ||
50 | return NULL; | ||
51 | |||
52 | return syscalls_metadata[nr]; | ||
53 | } | ||
54 | |||
17 | enum print_line_t | 55 | enum print_line_t |
18 | print_syscall_enter(struct trace_iterator *iter, int flags) | 56 | print_syscall_enter(struct trace_iterator *iter, int flags) |
19 | { | 57 | { |
@@ -30,7 +68,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags) | |||
30 | if (!entry) | 68 | if (!entry) |
31 | goto end; | 69 | goto end; |
32 | 70 | ||
33 | if (entry->enter_id != ent->type) { | 71 | if (entry->enter_event->id != ent->type) { |
34 | WARN_ON_ONCE(1); | 72 | WARN_ON_ONCE(1); |
35 | goto end; | 73 | goto end; |
36 | } | 74 | } |
@@ -85,7 +123,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags) | |||
85 | return TRACE_TYPE_HANDLED; | 123 | return TRACE_TYPE_HANDLED; |
86 | } | 124 | } |
87 | 125 | ||
88 | if (entry->exit_id != ent->type) { | 126 | if (entry->exit_event->id != ent->type) { |
89 | WARN_ON_ONCE(1); | 127 | WARN_ON_ONCE(1); |
90 | return TRACE_TYPE_UNHANDLED; | 128 | return TRACE_TYPE_UNHANDLED; |
91 | } | 129 | } |
@@ -103,92 +141,79 @@ extern char *__bad_type_size(void); | |||
103 | #define SYSCALL_FIELD(type, name) \ | 141 | #define SYSCALL_FIELD(type, name) \ |
104 | sizeof(type) != sizeof(trace.name) ? \ | 142 | sizeof(type) != sizeof(trace.name) ? \ |
105 | __bad_type_size() : \ | 143 | __bad_type_size() : \ |
106 | #type, #name, offsetof(typeof(trace), name), sizeof(trace.name) | 144 | #type, #name, offsetof(typeof(trace), name), \ |
145 | sizeof(trace.name), is_signed_type(type) | ||
107 | 146 | ||
108 | int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | 147 | static |
148 | int __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len) | ||
109 | { | 149 | { |
110 | int i; | 150 | int i; |
111 | int nr; | 151 | int pos = 0; |
112 | int ret; | ||
113 | struct syscall_metadata *entry; | ||
114 | struct syscall_trace_enter trace; | ||
115 | int offset = offsetof(struct syscall_trace_enter, args); | ||
116 | 152 | ||
117 | nr = syscall_name_to_nr(call->data); | 153 | /* When len=0, we just calculate the needed length */ |
118 | entry = syscall_nr_to_meta(nr); | 154 | #define LEN_OR_ZERO (len ? len - pos : 0) |
119 | |||
120 | if (!entry) | ||
121 | return 0; | ||
122 | |||
123 | ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", | ||
124 | SYSCALL_FIELD(int, nr)); | ||
125 | if (!ret) | ||
126 | return 0; | ||
127 | 155 | ||
156 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); | ||
128 | for (i = 0; i < entry->nb_args; i++) { | 157 | for (i = 0; i < entry->nb_args; i++) { |
129 | ret = trace_seq_printf(s, "\tfield:%s %s;", entry->types[i], | 158 | pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s", |
130 | entry->args[i]); | 159 | entry->args[i], sizeof(unsigned long), |
131 | if (!ret) | 160 | i == entry->nb_args - 1 ? "" : ", "); |
132 | return 0; | ||
133 | ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, | ||
134 | sizeof(unsigned long)); | ||
135 | if (!ret) | ||
136 | return 0; | ||
137 | offset += sizeof(unsigned long); | ||
138 | } | 161 | } |
162 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); | ||
139 | 163 | ||
140 | trace_seq_puts(s, "\nprint fmt: \""); | ||
141 | for (i = 0; i < entry->nb_args; i++) { | 164 | for (i = 0; i < entry->nb_args; i++) { |
142 | ret = trace_seq_printf(s, "%s: 0x%%0%zulx%s", entry->args[i], | 165 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
143 | sizeof(unsigned long), | 166 | ", ((unsigned long)(REC->%s))", entry->args[i]); |
144 | i == entry->nb_args - 1 ? "" : ", "); | ||
145 | if (!ret) | ||
146 | return 0; | ||
147 | } | 167 | } |
148 | trace_seq_putc(s, '"'); | ||
149 | 168 | ||
150 | for (i = 0; i < entry->nb_args; i++) { | 169 | #undef LEN_OR_ZERO |
151 | ret = trace_seq_printf(s, ", ((unsigned long)(REC->%s))", | ||
152 | entry->args[i]); | ||
153 | if (!ret) | ||
154 | return 0; | ||
155 | } | ||
156 | 170 | ||
157 | return trace_seq_putc(s, '\n'); | 171 | /* return the length of print_fmt */ |
172 | return pos; | ||
158 | } | 173 | } |
159 | 174 | ||
160 | int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) | 175 | static int set_syscall_print_fmt(struct ftrace_event_call *call) |
161 | { | 176 | { |
162 | int ret; | 177 | char *print_fmt; |
163 | struct syscall_trace_exit trace; | 178 | int len; |
179 | struct syscall_metadata *entry = call->data; | ||
164 | 180 | ||
165 | ret = trace_seq_printf(s, | 181 | if (entry->enter_event != call) { |
166 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" | 182 | call->print_fmt = "\"0x%lx\", REC->ret"; |
167 | "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", | ||
168 | SYSCALL_FIELD(int, nr), | ||
169 | SYSCALL_FIELD(long, ret)); | ||
170 | if (!ret) | ||
171 | return 0; | 183 | return 0; |
184 | } | ||
185 | |||
186 | /* First: called with 0 length to calculate the needed length */ | ||
187 | len = __set_enter_print_fmt(entry, NULL, 0); | ||
188 | |||
189 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | ||
190 | if (!print_fmt) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | /* Second: actually write the @print_fmt */ | ||
194 | __set_enter_print_fmt(entry, print_fmt, len + 1); | ||
195 | call->print_fmt = print_fmt; | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static void free_syscall_print_fmt(struct ftrace_event_call *call) | ||
201 | { | ||
202 | struct syscall_metadata *entry = call->data; | ||
172 | 203 | ||
173 | return trace_seq_printf(s, "\nprint fmt: \"0x%%lx\", REC->ret\n"); | 204 | if (entry->enter_event == call) |
205 | kfree(call->print_fmt); | ||
174 | } | 206 | } |
175 | 207 | ||
176 | int syscall_enter_define_fields(struct ftrace_event_call *call) | 208 | int syscall_enter_define_fields(struct ftrace_event_call *call) |
177 | { | 209 | { |
178 | struct syscall_trace_enter trace; | 210 | struct syscall_trace_enter trace; |
179 | struct syscall_metadata *meta; | 211 | struct syscall_metadata *meta = call->data; |
180 | int ret; | 212 | int ret; |
181 | int nr; | ||
182 | int i; | 213 | int i; |
183 | int offset = offsetof(typeof(trace), args); | 214 | int offset = offsetof(typeof(trace), args); |
184 | 215 | ||
185 | nr = syscall_name_to_nr(call->data); | 216 | ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER); |
186 | meta = syscall_nr_to_meta(nr); | ||
187 | |||
188 | if (!meta) | ||
189 | return 0; | ||
190 | |||
191 | ret = trace_define_common_fields(call); | ||
192 | if (ret) | 217 | if (ret) |
193 | return ret; | 218 | return ret; |
194 | 219 | ||
@@ -208,11 +233,11 @@ int syscall_exit_define_fields(struct ftrace_event_call *call) | |||
208 | struct syscall_trace_exit trace; | 233 | struct syscall_trace_exit trace; |
209 | int ret; | 234 | int ret; |
210 | 235 | ||
211 | ret = trace_define_common_fields(call); | 236 | ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER); |
212 | if (ret) | 237 | if (ret) |
213 | return ret; | 238 | return ret; |
214 | 239 | ||
215 | ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0, | 240 | ret = trace_define_field(call, SYSCALL_FIELD(long, ret), |
216 | FILTER_OTHER); | 241 | FILTER_OTHER); |
217 | 242 | ||
218 | return ret; | 243 | return ret; |
@@ -239,8 +264,8 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) | |||
239 | 264 | ||
240 | size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; | 265 | size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; |
241 | 266 | ||
242 | event = trace_current_buffer_lock_reserve(&buffer, sys_data->enter_id, | 267 | event = trace_current_buffer_lock_reserve(&buffer, |
243 | size, 0, 0); | 268 | sys_data->enter_event->id, size, 0, 0); |
244 | if (!event) | 269 | if (!event) |
245 | return; | 270 | return; |
246 | 271 | ||
@@ -271,8 +296,8 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) | |||
271 | if (!sys_data) | 296 | if (!sys_data) |
272 | return; | 297 | return; |
273 | 298 | ||
274 | event = trace_current_buffer_lock_reserve(&buffer, sys_data->exit_id, | 299 | event = trace_current_buffer_lock_reserve(&buffer, |
275 | sizeof(*entry), 0, 0); | 300 | sys_data->exit_event->id, sizeof(*entry), 0, 0); |
276 | if (!event) | 301 | if (!event) |
277 | return; | 302 | return; |
278 | 303 | ||
@@ -285,23 +310,18 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) | |||
285 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); | 310 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); |
286 | } | 311 | } |
287 | 312 | ||
288 | int reg_event_syscall_enter(void *ptr) | 313 | int reg_event_syscall_enter(struct ftrace_event_call *call) |
289 | { | 314 | { |
290 | int ret = 0; | 315 | int ret = 0; |
291 | int num; | 316 | int num; |
292 | char *name; | ||
293 | 317 | ||
294 | name = (char *)ptr; | 318 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
295 | num = syscall_name_to_nr(name); | ||
296 | if (num < 0 || num >= NR_syscalls) | 319 | if (num < 0 || num >= NR_syscalls) |
297 | return -ENOSYS; | 320 | return -ENOSYS; |
298 | mutex_lock(&syscall_trace_lock); | 321 | mutex_lock(&syscall_trace_lock); |
299 | if (!sys_refcount_enter) | 322 | if (!sys_refcount_enter) |
300 | ret = register_trace_sys_enter(ftrace_syscall_enter); | 323 | ret = register_trace_sys_enter(ftrace_syscall_enter); |
301 | if (ret) { | 324 | if (!ret) { |
302 | pr_info("event trace: Could not activate" | ||
303 | "syscall entry trace point"); | ||
304 | } else { | ||
305 | set_bit(num, enabled_enter_syscalls); | 325 | set_bit(num, enabled_enter_syscalls); |
306 | sys_refcount_enter++; | 326 | sys_refcount_enter++; |
307 | } | 327 | } |
@@ -309,13 +329,11 @@ int reg_event_syscall_enter(void *ptr) | |||
309 | return ret; | 329 | return ret; |
310 | } | 330 | } |
311 | 331 | ||
312 | void unreg_event_syscall_enter(void *ptr) | 332 | void unreg_event_syscall_enter(struct ftrace_event_call *call) |
313 | { | 333 | { |
314 | int num; | 334 | int num; |
315 | char *name; | ||
316 | 335 | ||
317 | name = (char *)ptr; | 336 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
318 | num = syscall_name_to_nr(name); | ||
319 | if (num < 0 || num >= NR_syscalls) | 337 | if (num < 0 || num >= NR_syscalls) |
320 | return; | 338 | return; |
321 | mutex_lock(&syscall_trace_lock); | 339 | mutex_lock(&syscall_trace_lock); |
@@ -326,23 +344,18 @@ void unreg_event_syscall_enter(void *ptr) | |||
326 | mutex_unlock(&syscall_trace_lock); | 344 | mutex_unlock(&syscall_trace_lock); |
327 | } | 345 | } |
328 | 346 | ||
329 | int reg_event_syscall_exit(void *ptr) | 347 | int reg_event_syscall_exit(struct ftrace_event_call *call) |
330 | { | 348 | { |
331 | int ret = 0; | 349 | int ret = 0; |
332 | int num; | 350 | int num; |
333 | char *name; | ||
334 | 351 | ||
335 | name = (char *)ptr; | 352 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
336 | num = syscall_name_to_nr(name); | ||
337 | if (num < 0 || num >= NR_syscalls) | 353 | if (num < 0 || num >= NR_syscalls) |
338 | return -ENOSYS; | 354 | return -ENOSYS; |
339 | mutex_lock(&syscall_trace_lock); | 355 | mutex_lock(&syscall_trace_lock); |
340 | if (!sys_refcount_exit) | 356 | if (!sys_refcount_exit) |
341 | ret = register_trace_sys_exit(ftrace_syscall_exit); | 357 | ret = register_trace_sys_exit(ftrace_syscall_exit); |
342 | if (ret) { | 358 | if (!ret) { |
343 | pr_info("event trace: Could not activate" | ||
344 | "syscall exit trace point"); | ||
345 | } else { | ||
346 | set_bit(num, enabled_exit_syscalls); | 359 | set_bit(num, enabled_exit_syscalls); |
347 | sys_refcount_exit++; | 360 | sys_refcount_exit++; |
348 | } | 361 | } |
@@ -350,13 +363,11 @@ int reg_event_syscall_exit(void *ptr) | |||
350 | return ret; | 363 | return ret; |
351 | } | 364 | } |
352 | 365 | ||
353 | void unreg_event_syscall_exit(void *ptr) | 366 | void unreg_event_syscall_exit(struct ftrace_event_call *call) |
354 | { | 367 | { |
355 | int num; | 368 | int num; |
356 | char *name; | ||
357 | 369 | ||
358 | name = (char *)ptr; | 370 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
359 | num = syscall_name_to_nr(name); | ||
360 | if (num < 0 || num >= NR_syscalls) | 371 | if (num < 0 || num >= NR_syscalls) |
361 | return; | 372 | return; |
362 | mutex_lock(&syscall_trace_lock); | 373 | mutex_lock(&syscall_trace_lock); |
@@ -367,33 +378,73 @@ void unreg_event_syscall_exit(void *ptr) | |||
367 | mutex_unlock(&syscall_trace_lock); | 378 | mutex_unlock(&syscall_trace_lock); |
368 | } | 379 | } |
369 | 380 | ||
370 | struct trace_event event_syscall_enter = { | 381 | int init_syscall_trace(struct ftrace_event_call *call) |
371 | .trace = print_syscall_enter, | 382 | { |
372 | }; | 383 | int id; |
384 | |||
385 | if (set_syscall_print_fmt(call) < 0) | ||
386 | return -ENOMEM; | ||
373 | 387 | ||
374 | struct trace_event event_syscall_exit = { | 388 | id = trace_event_raw_init(call); |
375 | .trace = print_syscall_exit, | ||
376 | }; | ||
377 | 389 | ||
378 | #ifdef CONFIG_EVENT_PROFILE | 390 | if (id < 0) { |
391 | free_syscall_print_fmt(call); | ||
392 | return id; | ||
393 | } | ||
379 | 394 | ||
380 | static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); | 395 | return id; |
381 | static DECLARE_BITMAP(enabled_prof_exit_syscalls, NR_syscalls); | 396 | } |
382 | static int sys_prof_refcount_enter; | 397 | |
383 | static int sys_prof_refcount_exit; | 398 | unsigned long __init arch_syscall_addr(int nr) |
399 | { | ||
400 | return (unsigned long)sys_call_table[nr]; | ||
401 | } | ||
384 | 402 | ||
385 | static void prof_syscall_enter(struct pt_regs *regs, long id) | 403 | int __init init_ftrace_syscalls(void) |
404 | { | ||
405 | struct syscall_metadata *meta; | ||
406 | unsigned long addr; | ||
407 | int i; | ||
408 | |||
409 | syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | ||
410 | NR_syscalls, GFP_KERNEL); | ||
411 | if (!syscalls_metadata) { | ||
412 | WARN_ON(1); | ||
413 | return -ENOMEM; | ||
414 | } | ||
415 | |||
416 | for (i = 0; i < NR_syscalls; i++) { | ||
417 | addr = arch_syscall_addr(i); | ||
418 | meta = find_syscall_meta(addr); | ||
419 | if (!meta) | ||
420 | continue; | ||
421 | |||
422 | meta->syscall_nr = i; | ||
423 | syscalls_metadata[i] = meta; | ||
424 | } | ||
425 | |||
426 | return 0; | ||
427 | } | ||
428 | core_initcall(init_ftrace_syscalls); | ||
429 | |||
430 | #ifdef CONFIG_PERF_EVENTS | ||
431 | |||
432 | static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls); | ||
433 | static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls); | ||
434 | static int sys_perf_refcount_enter; | ||
435 | static int sys_perf_refcount_exit; | ||
436 | |||
437 | static void perf_syscall_enter(struct pt_regs *regs, long id) | ||
386 | { | 438 | { |
387 | struct syscall_metadata *sys_data; | 439 | struct syscall_metadata *sys_data; |
388 | struct syscall_trace_enter *rec; | 440 | struct syscall_trace_enter *rec; |
389 | unsigned long flags; | 441 | unsigned long flags; |
390 | char *raw_data; | ||
391 | int syscall_nr; | 442 | int syscall_nr; |
443 | int rctx; | ||
392 | int size; | 444 | int size; |
393 | int cpu; | ||
394 | 445 | ||
395 | syscall_nr = syscall_get_nr(current, regs); | 446 | syscall_nr = syscall_get_nr(current, regs); |
396 | if (!test_bit(syscall_nr, enabled_prof_enter_syscalls)) | 447 | if (!test_bit(syscall_nr, enabled_perf_enter_syscalls)) |
397 | return; | 448 | return; |
398 | 449 | ||
399 | sys_data = syscall_nr_to_meta(syscall_nr); | 450 | sys_data = syscall_nr_to_meta(syscall_nr); |
@@ -405,91 +456,67 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) | |||
405 | size = ALIGN(size + sizeof(u32), sizeof(u64)); | 456 | size = ALIGN(size + sizeof(u32), sizeof(u64)); |
406 | size -= sizeof(u32); | 457 | size -= sizeof(u32); |
407 | 458 | ||
408 | if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE, | 459 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, |
409 | "profile buffer not large enough")) | 460 | "perf buffer not large enough")) |
410 | return; | 461 | return; |
411 | 462 | ||
412 | /* Protect the per cpu buffer, begin the rcu read side */ | 463 | rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size, |
413 | local_irq_save(flags); | 464 | sys_data->enter_event->id, &rctx, &flags); |
414 | 465 | if (!rec) | |
415 | cpu = smp_processor_id(); | 466 | return; |
416 | |||
417 | if (in_nmi()) | ||
418 | raw_data = rcu_dereference(trace_profile_buf_nmi); | ||
419 | else | ||
420 | raw_data = rcu_dereference(trace_profile_buf); | ||
421 | |||
422 | if (!raw_data) | ||
423 | goto end; | ||
424 | |||
425 | raw_data = per_cpu_ptr(raw_data, cpu); | ||
426 | |||
427 | /* zero the dead bytes from align to not leak stack to user */ | ||
428 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
429 | 467 | ||
430 | rec = (struct syscall_trace_enter *) raw_data; | ||
431 | tracing_generic_entry_update(&rec->ent, 0, 0); | ||
432 | rec->ent.type = sys_data->enter_id; | ||
433 | rec->nr = syscall_nr; | 468 | rec->nr = syscall_nr; |
434 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, | 469 | syscall_get_arguments(current, regs, 0, sys_data->nb_args, |
435 | (unsigned long *)&rec->args); | 470 | (unsigned long *)&rec->args); |
436 | perf_tp_event(sys_data->enter_id, 0, 1, rec, size); | 471 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); |
437 | |||
438 | end: | ||
439 | local_irq_restore(flags); | ||
440 | } | 472 | } |
441 | 473 | ||
442 | int reg_prof_syscall_enter(char *name) | 474 | int perf_sysenter_enable(struct ftrace_event_call *call) |
443 | { | 475 | { |
444 | int ret = 0; | 476 | int ret = 0; |
445 | int num; | 477 | int num; |
446 | 478 | ||
447 | num = syscall_name_to_nr(name); | 479 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
448 | if (num < 0 || num >= NR_syscalls) | ||
449 | return -ENOSYS; | ||
450 | 480 | ||
451 | mutex_lock(&syscall_trace_lock); | 481 | mutex_lock(&syscall_trace_lock); |
452 | if (!sys_prof_refcount_enter) | 482 | if (!sys_perf_refcount_enter) |
453 | ret = register_trace_sys_enter(prof_syscall_enter); | 483 | ret = register_trace_sys_enter(perf_syscall_enter); |
454 | if (ret) { | 484 | if (ret) { |
455 | pr_info("event trace: Could not activate" | 485 | pr_info("event trace: Could not activate" |
456 | "syscall entry trace point"); | 486 | "syscall entry trace point"); |
457 | } else { | 487 | } else { |
458 | set_bit(num, enabled_prof_enter_syscalls); | 488 | set_bit(num, enabled_perf_enter_syscalls); |
459 | sys_prof_refcount_enter++; | 489 | sys_perf_refcount_enter++; |
460 | } | 490 | } |
461 | mutex_unlock(&syscall_trace_lock); | 491 | mutex_unlock(&syscall_trace_lock); |
462 | return ret; | 492 | return ret; |
463 | } | 493 | } |
464 | 494 | ||
465 | void unreg_prof_syscall_enter(char *name) | 495 | void perf_sysenter_disable(struct ftrace_event_call *call) |
466 | { | 496 | { |
467 | int num; | 497 | int num; |
468 | 498 | ||
469 | num = syscall_name_to_nr(name); | 499 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
470 | if (num < 0 || num >= NR_syscalls) | ||
471 | return; | ||
472 | 500 | ||
473 | mutex_lock(&syscall_trace_lock); | 501 | mutex_lock(&syscall_trace_lock); |
474 | sys_prof_refcount_enter--; | 502 | sys_perf_refcount_enter--; |
475 | clear_bit(num, enabled_prof_enter_syscalls); | 503 | clear_bit(num, enabled_perf_enter_syscalls); |
476 | if (!sys_prof_refcount_enter) | 504 | if (!sys_perf_refcount_enter) |
477 | unregister_trace_sys_enter(prof_syscall_enter); | 505 | unregister_trace_sys_enter(perf_syscall_enter); |
478 | mutex_unlock(&syscall_trace_lock); | 506 | mutex_unlock(&syscall_trace_lock); |
479 | } | 507 | } |
480 | 508 | ||
481 | static void prof_syscall_exit(struct pt_regs *regs, long ret) | 509 | static void perf_syscall_exit(struct pt_regs *regs, long ret) |
482 | { | 510 | { |
483 | struct syscall_metadata *sys_data; | 511 | struct syscall_metadata *sys_data; |
484 | struct syscall_trace_exit *rec; | 512 | struct syscall_trace_exit *rec; |
485 | unsigned long flags; | 513 | unsigned long flags; |
486 | int syscall_nr; | 514 | int syscall_nr; |
487 | char *raw_data; | 515 | int rctx; |
488 | int size; | 516 | int size; |
489 | int cpu; | ||
490 | 517 | ||
491 | syscall_nr = syscall_get_nr(current, regs); | 518 | syscall_nr = syscall_get_nr(current, regs); |
492 | if (!test_bit(syscall_nr, enabled_prof_exit_syscalls)) | 519 | if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) |
493 | return; | 520 | return; |
494 | 521 | ||
495 | sys_data = syscall_nr_to_meta(syscall_nr); | 522 | sys_data = syscall_nr_to_meta(syscall_nr); |
@@ -504,79 +531,55 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) | |||
504 | * Impossible, but be paranoid with the future | 531 | * Impossible, but be paranoid with the future |
505 | * How to put this check outside runtime? | 532 | * How to put this check outside runtime? |
506 | */ | 533 | */ |
507 | if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE, | 534 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, |
508 | "exit event has grown above profile buffer size")) | 535 | "exit event has grown above perf buffer size")) |
509 | return; | 536 | return; |
510 | 537 | ||
511 | /* Protect the per cpu buffer, begin the rcu read side */ | 538 | rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size, |
512 | local_irq_save(flags); | 539 | sys_data->exit_event->id, &rctx, &flags); |
513 | cpu = smp_processor_id(); | 540 | if (!rec) |
514 | 541 | return; | |
515 | if (in_nmi()) | ||
516 | raw_data = rcu_dereference(trace_profile_buf_nmi); | ||
517 | else | ||
518 | raw_data = rcu_dereference(trace_profile_buf); | ||
519 | |||
520 | if (!raw_data) | ||
521 | goto end; | ||
522 | |||
523 | raw_data = per_cpu_ptr(raw_data, cpu); | ||
524 | |||
525 | /* zero the dead bytes from align to not leak stack to user */ | ||
526 | *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; | ||
527 | |||
528 | rec = (struct syscall_trace_exit *)raw_data; | ||
529 | 542 | ||
530 | tracing_generic_entry_update(&rec->ent, 0, 0); | ||
531 | rec->ent.type = sys_data->exit_id; | ||
532 | rec->nr = syscall_nr; | 543 | rec->nr = syscall_nr; |
533 | rec->ret = syscall_get_return_value(current, regs); | 544 | rec->ret = syscall_get_return_value(current, regs); |
534 | 545 | ||
535 | perf_tp_event(sys_data->exit_id, 0, 1, rec, size); | 546 | perf_trace_buf_submit(rec, size, rctx, 0, 1, flags, regs); |
536 | |||
537 | end: | ||
538 | local_irq_restore(flags); | ||
539 | } | 547 | } |
540 | 548 | ||
541 | int reg_prof_syscall_exit(char *name) | 549 | int perf_sysexit_enable(struct ftrace_event_call *call) |
542 | { | 550 | { |
543 | int ret = 0; | 551 | int ret = 0; |
544 | int num; | 552 | int num; |
545 | 553 | ||
546 | num = syscall_name_to_nr(name); | 554 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
547 | if (num < 0 || num >= NR_syscalls) | ||
548 | return -ENOSYS; | ||
549 | 555 | ||
550 | mutex_lock(&syscall_trace_lock); | 556 | mutex_lock(&syscall_trace_lock); |
551 | if (!sys_prof_refcount_exit) | 557 | if (!sys_perf_refcount_exit) |
552 | ret = register_trace_sys_exit(prof_syscall_exit); | 558 | ret = register_trace_sys_exit(perf_syscall_exit); |
553 | if (ret) { | 559 | if (ret) { |
554 | pr_info("event trace: Could not activate" | 560 | pr_info("event trace: Could not activate" |
555 | "syscall entry trace point"); | 561 | "syscall exit trace point"); |
556 | } else { | 562 | } else { |
557 | set_bit(num, enabled_prof_exit_syscalls); | 563 | set_bit(num, enabled_perf_exit_syscalls); |
558 | sys_prof_refcount_exit++; | 564 | sys_perf_refcount_exit++; |
559 | } | 565 | } |
560 | mutex_unlock(&syscall_trace_lock); | 566 | mutex_unlock(&syscall_trace_lock); |
561 | return ret; | 567 | return ret; |
562 | } | 568 | } |
563 | 569 | ||
564 | void unreg_prof_syscall_exit(char *name) | 570 | void perf_sysexit_disable(struct ftrace_event_call *call) |
565 | { | 571 | { |
566 | int num; | 572 | int num; |
567 | 573 | ||
568 | num = syscall_name_to_nr(name); | 574 | num = ((struct syscall_metadata *)call->data)->syscall_nr; |
569 | if (num < 0 || num >= NR_syscalls) | ||
570 | return; | ||
571 | 575 | ||
572 | mutex_lock(&syscall_trace_lock); | 576 | mutex_lock(&syscall_trace_lock); |
573 | sys_prof_refcount_exit--; | 577 | sys_perf_refcount_exit--; |
574 | clear_bit(num, enabled_prof_exit_syscalls); | 578 | clear_bit(num, enabled_perf_exit_syscalls); |
575 | if (!sys_prof_refcount_exit) | 579 | if (!sys_perf_refcount_exit) |
576 | unregister_trace_sys_exit(prof_syscall_exit); | 580 | unregister_trace_sys_exit(perf_syscall_exit); |
577 | mutex_unlock(&syscall_trace_lock); | 581 | mutex_unlock(&syscall_trace_lock); |
578 | } | 582 | } |
579 | 583 | ||
580 | #endif | 584 | #endif /* CONFIG_PERF_EVENTS */ |
581 | |||
582 | 585 | ||