aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_syscalls.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /kernel/trace/trace_syscalls.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (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.c397
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;
14static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); 15static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
15static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); 16static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
16 17
18extern unsigned long __start_syscalls_metadata[];
19extern unsigned long __stop_syscalls_metadata[];
20
21static struct syscall_metadata **syscalls_metadata;
22
23static 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
47static 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
17enum print_line_t 55enum print_line_t
18print_syscall_enter(struct trace_iterator *iter, int flags) 56print_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
108int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) 147static
148int __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
160int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s) 175static 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
200static 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
176int syscall_enter_define_fields(struct ftrace_event_call *call) 208int 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
288int reg_event_syscall_enter(void *ptr) 313int 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
312void unreg_event_syscall_enter(void *ptr) 332void 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
329int reg_event_syscall_exit(void *ptr) 347int 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
353void unreg_event_syscall_exit(void *ptr) 366void 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
370struct trace_event event_syscall_enter = { 381int 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
374struct 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
380static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls); 395 return id;
381static DECLARE_BITMAP(enabled_prof_exit_syscalls, NR_syscalls); 396}
382static int sys_prof_refcount_enter; 397
383static int sys_prof_refcount_exit; 398unsigned long __init arch_syscall_addr(int nr)
399{
400 return (unsigned long)sys_call_table[nr];
401}
384 402
385static void prof_syscall_enter(struct pt_regs *regs, long id) 403int __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}
428core_initcall(init_ftrace_syscalls);
429
430#ifdef CONFIG_PERF_EVENTS
431
432static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls);
433static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls);
434static int sys_perf_refcount_enter;
435static int sys_perf_refcount_exit;
436
437static 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
438end:
439 local_irq_restore(flags);
440} 472}
441 473
442int reg_prof_syscall_enter(char *name) 474int 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
465void unreg_prof_syscall_enter(char *name) 495void 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
481static void prof_syscall_exit(struct pt_regs *regs, long ret) 509static 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
537end:
538 local_irq_restore(flags);
539} 547}
540 548
541int reg_prof_syscall_exit(char *name) 549int 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
564void unreg_prof_syscall_exit(char *name) 570void 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