1 #include <trace/syscall.h> 2 #include <trace/events/syscalls.h> 3 #include <linux/syscalls.h> 4 #include <linux/slab.h> 5 #include <linux/kernel.h> 6 #include <linux/module.h> /* for MODULE_NAME_LEN via KSYM_SYMBOL_LEN */ 7 #include <linux/ftrace.h> 8 #include <linux/perf_event.h> 9 #include <asm/syscall.h> 10 11 #include "trace_output.h" 12 #include "trace.h" 13 14 static DEFINE_MUTEX(syscall_trace_lock); 15 16 static int syscall_enter_register(struct ftrace_event_call *event, 17 enum trace_reg type, void *data); 18 static int syscall_exit_register(struct ftrace_event_call *event, 19 enum trace_reg type, void *data); 20 21 static struct list_head * 22 syscall_get_enter_fields(struct ftrace_event_call *call) 23 { 24 struct syscall_metadata *entry = call->data; 25 26 return &entry->enter_fields; 27 } 28 29 extern struct syscall_metadata *__start_syscalls_metadata[]; 30 extern struct syscall_metadata *__stop_syscalls_metadata[]; 31 32 static struct syscall_metadata **syscalls_metadata; 33 34 #ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME 35 static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) 36 { 37 /* 38 * Only compare after the "sys" prefix. Archs that use 39 * syscall wrappers may have syscalls symbols aliases prefixed 40 * with ".SyS" or ".sys" instead of "sys", leading to an unwanted 41 * mismatch. 42 */ 43 return !strcmp(sym + 3, name + 3); 44 } 45 #endif 46 47 #ifdef ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 48 /* 49 * Some architectures that allow for 32bit applications 50 * to run on a 64bit kernel, do not map the syscalls for 51 * the 32bit tasks the same as they do for 64bit tasks. 52 * 53 * *cough*x86*cough* 54 * 55 * In such a case, instead of reporting the wrong syscalls, 56 * simply ignore them. 57 * 58 * For an arch to ignore the compat syscalls it needs to 59 * define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS as well as 60 * define the function arch_trace_is_compat_syscall() to let 61 * the tracing system know that it should ignore it. 62 */ 63 static int 64 trace_get_syscall_nr(struct task_struct *task, struct pt_regs *regs) 65 { 66 if (unlikely(arch_trace_is_compat_syscall(regs))) 67 return -1; 68 69 return syscall_get_nr(task, regs); 70 } 71 #else 72 static inline int 73 trace_get_syscall_nr(struct task_struct *task, struct pt_regs *regs) 74 { 75 return syscall_get_nr(task, regs); 76 } 77 #endif /* ARCH_TRACE_IGNORE_COMPAT_SYSCALLS */ 78 79 static __init struct syscall_metadata * 80 find_syscall_meta(unsigned long syscall) 81 { 82 struct syscall_metadata **start; 83 struct syscall_metadata **stop; 84 char str[KSYM_SYMBOL_LEN]; 85 86 87 start = __start_syscalls_metadata; 88 stop = __stop_syscalls_metadata; 89 kallsyms_lookup(syscall, NULL, NULL, NULL, str); 90 91 if (arch_syscall_match_sym_name(str, "sys_ni_syscall")) 92 return NULL; 93 94 for ( ; start < stop; start++) { 95 if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name)) 96 return *start; 97 } 98 return NULL; 99 } 100 101 static struct syscall_metadata *syscall_nr_to_meta(int nr) 102 { 103 if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) 104 return NULL; 105 106 return syscalls_metadata[nr]; 107 } 108 109 static enum print_line_t 110 print_syscall_enter(struct trace_iterator *iter, int flags, 111 struct trace_event *event) 112 { 113 struct trace_seq *s = &iter->seq; 114 struct trace_entry *ent = iter->ent; 115 struct syscall_trace_enter *trace; 116 struct syscall_metadata *entry; 117 int i, ret, syscall; 118 119 trace = (typeof(trace))ent; 120 syscall = trace->nr; 121 entry = syscall_nr_to_meta(syscall); 122 123 if (!entry) 124 goto end; 125 126 if (entry->enter_event->event.type != ent->type) { 127 WARN_ON_ONCE(1); 128 goto end; 129 } 130 131 ret = trace_seq_printf(s, "%s(", entry->name); 132 if (!ret) 133 return TRACE_TYPE_PARTIAL_LINE; 134 135 for (i = 0; i < entry->nb_args; i++) { 136 /* parameter types */ 137 if (trace_flags & TRACE_ITER_VERBOSE) { 138 ret = trace_seq_printf(s, "%s ", entry->types[i]); 139 if (!ret) 140 return TRACE_TYPE_PARTIAL_LINE; 141 } 142 /* parameter values */ 143 ret = trace_seq_printf(s, "%s: %lx%s", entry->args[i], 144 trace->args[i], 145 i == entry->nb_args - 1 ? "" : ", "); 146 if (!ret) 147 return TRACE_TYPE_PARTIAL_LINE; 148 } 149 150 ret = trace_seq_putc(s, ')'); 151 if (!ret) 152 return TRACE_TYPE_PARTIAL_LINE; 153 154 end: 155 ret = trace_seq_putc(s, '\n'); 156 if (!ret) 157 return TRACE_TYPE_PARTIAL_LINE; 158 159 return TRACE_TYPE_HANDLED; 160 } 161 162 static enum print_line_t 163 print_syscall_exit(struct trace_iterator *iter, int flags, 164 struct trace_event *event) 165 { 166 struct trace_seq *s = &iter->seq; 167 struct trace_entry *ent = iter->ent; 168 struct syscall_trace_exit *trace; 169 int syscall; 170 struct syscall_metadata *entry; 171 int ret; 172 173 trace = (typeof(trace))ent; 174 syscall = trace->nr; 175 entry = syscall_nr_to_meta(syscall); 176 177 if (!entry) { 178 trace_seq_putc(s, '\n'); 179 return TRACE_TYPE_HANDLED; 180 } 181 182 if (entry->exit_event->event.type != ent->type) { 183 WARN_ON_ONCE(1); 184 return TRACE_TYPE_UNHANDLED; 185 } 186 187 ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name, 188 trace->ret); 189 if (!ret) 190 return TRACE_TYPE_PARTIAL_LINE; 191 192 return TRACE_TYPE_HANDLED; 193 } 194 195 extern char *__bad_type_size(void); 196 197 #define SYSCALL_FIELD(type, name) \ 198 sizeof(type) != sizeof(trace.name) ? \ 199 __bad_type_size() : \ 200 #type, #name, offsetof(typeof(trace), name), \ 201 sizeof(trace.name), is_signed_type(type) 202 203 static int __init 204 __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len) 205 { 206 int i; 207 int pos = 0; 208 209 /* When len=0, we just calculate the needed length */ 210 #define LEN_OR_ZERO (len ? len - pos : 0) 211 212 pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); 213 for (i = 0; i < entry->nb_args; i++) { 214 pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s", 215 entry->args[i], sizeof(unsigned long), 216 i == entry->nb_args - 1 ? "" : ", "); 217 } 218 pos += snprintf(buf + pos, LEN_OR_ZERO, "\""); 219 220 for (i = 0; i < entry->nb_args; i++) { 221 pos += snprintf(buf + pos, LEN_OR_ZERO, 222 ", ((unsigned long)(REC->%s))", entry->args[i]); 223 } 224 225 #undef LEN_OR_ZERO 226 227 /* return the length of print_fmt */ 228 return pos; 229 } 230 231 static int __init set_syscall_print_fmt(struct ftrace_event_call *call) 232 { 233 char *print_fmt; 234 int len; 235 struct syscall_metadata *entry = call->data; 236 237 if (entry->enter_event != call) { 238 call->print_fmt = "\"0x%lx\", REC->ret"; 239 return 0; 240 } 241 242 /* First: called with 0 length to calculate the needed length */ 243 len = __set_enter_print_fmt(entry, NULL, 0); 244 245 print_fmt = kmalloc(len + 1, GFP_KERNEL); 246 if (!print_fmt) 247 return -ENOMEM; 248 249 /* Second: actually write the @print_fmt */ 250 __set_enter_print_fmt(entry, print_fmt, len + 1); 251 call->print_fmt = print_fmt; 252 253 return 0; 254 } 255 256 static void __init free_syscall_print_fmt(struct ftrace_event_call *call) 257 { 258 struct syscall_metadata *entry = call->data; 259 260 if (entry->enter_event == call) 261 kfree(call->print_fmt); 262 } 263 264 static int __init syscall_enter_define_fields(struct ftrace_event_call *call) 265 { 266 struct syscall_trace_enter trace; 267 struct syscall_metadata *meta = call->data; 268 int ret; 269 int i; 270 int offset = offsetof(typeof(trace), args); 271 272 ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER); 273 if (ret) 274 return ret; 275 276 for (i = 0; i < meta->nb_args; i++) { 277 ret = trace_define_field(call, meta->types[i], 278 meta->args[i], offset, 279 sizeof(unsigned long), 0, 280 FILTER_OTHER); 281 offset += sizeof(unsigned long); 282 } 283 284 return ret; 285 } 286 287 static int __init syscall_exit_define_fields(struct ftrace_event_call *call) 288 { 289 struct syscall_trace_exit trace; 290 int ret; 291 292 ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER); 293 if (ret) 294 return ret; 295 296 ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 297 FILTER_OTHER); 298 299 return ret; 300 } 301 302 static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) 303 { 304 struct trace_array *tr = data; 305 struct ftrace_event_file *ftrace_file; 306 struct syscall_trace_enter *entry; 307 struct syscall_metadata *sys_data; 308 struct ring_buffer_event *event; 309 struct ring_buffer *buffer; 310 unsigned long irq_flags; 311 int pc; 312 int syscall_nr; 313 int size; 314 315 syscall_nr = trace_get_syscall_nr(current, regs); 316 if (syscall_nr < 0) 317 return; 318 319 /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */ 320 ftrace_file = rcu_dereference_sched(tr->enter_syscall_files[syscall_nr]); 321 if (!ftrace_file) 322 return; 323 324 if (test_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &ftrace_file->flags)) 325 event_triggers_call(ftrace_file); 326 if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) 327 return; 328 329 sys_data = syscall_nr_to_meta(syscall_nr); 330 if (!sys_data) 331 return; 332 333 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; 334 335 local_save_flags(irq_flags); 336 pc = preempt_count(); 337 338 buffer = tr->trace_buffer.buffer; 339 event = trace_buffer_lock_reserve(buffer, 340 sys_data->enter_event->event.type, size, irq_flags, pc); 341 if (!event) 342 return; 343 344 entry = ring_buffer_event_data(event); 345 entry->nr = syscall_nr; 346 syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); 347 348 if (!filter_check_discard(ftrace_file, entry, buffer, event)) 349 trace_current_buffer_unlock_commit(buffer, event, 350 irq_flags, pc); 351 } 352 353 static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) 354 { 355 struct trace_array *tr = data; 356 struct ftrace_event_file *ftrace_file; 357 struct syscall_trace_exit *entry; 358 struct syscall_metadata *sys_data; 359 struct ring_buffer_event *event; 360 struct ring_buffer *buffer; 361 unsigned long irq_flags; 362 int pc; 363 int syscall_nr; 364 365 syscall_nr = trace_get_syscall_nr(current, regs); 366 if (syscall_nr < 0) 367 return; 368 369 /* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */ 370 ftrace_file = rcu_dereference_sched(tr->exit_syscall_files[syscall_nr]); 371 if (!ftrace_file) 372 return; 373 374 if (test_bit(FTRACE_EVENT_FL_TRIGGER_MODE_BIT, &ftrace_file->flags)) 375 event_triggers_call(ftrace_file); 376 if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &ftrace_file->flags)) 377 return; 378 379 sys_data = syscall_nr_to_meta(syscall_nr); 380 if (!sys_data) 381 return; 382 383 local_save_flags(irq_flags); 384 pc = preempt_count(); 385 386 buffer = tr->trace_buffer.buffer; 387 event = trace_buffer_lock_reserve(buffer, 388 sys_data->exit_event->event.type, sizeof(*entry), 389 irq_flags, pc); 390 if (!event) 391 return; 392 393 entry = ring_buffer_event_data(event); 394 entry->nr = syscall_nr; 395 entry->ret = syscall_get_return_value(current, regs); 396 397 if (!filter_check_discard(ftrace_file, entry, buffer, event)) 398 trace_current_buffer_unlock_commit(buffer, event, 399 irq_flags, pc); 400 } 401 402 static int reg_event_syscall_enter(struct ftrace_event_file *file, 403 struct ftrace_event_call *call) 404 { 405 struct trace_array *tr = file->tr; 406 int ret = 0; 407 int num; 408 409 num = ((struct syscall_metadata *)call->data)->syscall_nr; 410 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 411 return -ENOSYS; 412 mutex_lock(&syscall_trace_lock); 413 if (!tr->sys_refcount_enter) 414 ret = register_trace_sys_enter(ftrace_syscall_enter, tr); 415 if (!ret) { 416 rcu_assign_pointer(tr->enter_syscall_files[num], file); 417 tr->sys_refcount_enter++; 418 } 419 mutex_unlock(&syscall_trace_lock); 420 return ret; 421 } 422 423 static void unreg_event_syscall_enter(struct ftrace_event_file *file, 424 struct ftrace_event_call *call) 425 { 426 struct trace_array *tr = file->tr; 427 int num; 428 429 num = ((struct syscall_metadata *)call->data)->syscall_nr; 430 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 431 return; 432 mutex_lock(&syscall_trace_lock); 433 tr->sys_refcount_enter--; 434 rcu_assign_pointer(tr->enter_syscall_files[num], NULL); 435 if (!tr->sys_refcount_enter) 436 unregister_trace_sys_enter(ftrace_syscall_enter, tr); 437 mutex_unlock(&syscall_trace_lock); 438 } 439 440 static int reg_event_syscall_exit(struct ftrace_event_file *file, 441 struct ftrace_event_call *call) 442 { 443 struct trace_array *tr = file->tr; 444 int ret = 0; 445 int num; 446 447 num = ((struct syscall_metadata *)call->data)->syscall_nr; 448 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 449 return -ENOSYS; 450 mutex_lock(&syscall_trace_lock); 451 if (!tr->sys_refcount_exit) 452 ret = register_trace_sys_exit(ftrace_syscall_exit, tr); 453 if (!ret) { 454 rcu_assign_pointer(tr->exit_syscall_files[num], file); 455 tr->sys_refcount_exit++; 456 } 457 mutex_unlock(&syscall_trace_lock); 458 return ret; 459 } 460 461 static void unreg_event_syscall_exit(struct ftrace_event_file *file, 462 struct ftrace_event_call *call) 463 { 464 struct trace_array *tr = file->tr; 465 int num; 466 467 num = ((struct syscall_metadata *)call->data)->syscall_nr; 468 if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) 469 return; 470 mutex_lock(&syscall_trace_lock); 471 tr->sys_refcount_exit--; 472 rcu_assign_pointer(tr->exit_syscall_files[num], NULL); 473 if (!tr->sys_refcount_exit) 474 unregister_trace_sys_exit(ftrace_syscall_exit, tr); 475 mutex_unlock(&syscall_trace_lock); 476 } 477 478 static int __init init_syscall_trace(struct ftrace_event_call *call) 479 { 480 int id; 481 int num; 482 483 num = ((struct syscall_metadata *)call->data)->syscall_nr; 484 if (num < 0 || num >= NR_syscalls) { 485 pr_debug("syscall %s metadata not mapped, disabling ftrace event\n", 486 ((struct syscall_metadata *)call->data)->name); 487 return -ENOSYS; 488 } 489 490 if (set_syscall_print_fmt(call) < 0) 491 return -ENOMEM; 492 493 id = trace_event_raw_init(call); 494 495 if (id < 0) { 496 free_syscall_print_fmt(call); 497 return id; 498 } 499 500 return id; 501 } 502 503 struct trace_event_functions enter_syscall_print_funcs = { 504 .trace = print_syscall_enter, 505 }; 506 507 struct trace_event_functions exit_syscall_print_funcs = { 508 .trace = print_syscall_exit, 509 }; 510 511 struct ftrace_event_class __refdata event_class_syscall_enter = { 512 .system = "syscalls", 513 .reg = syscall_enter_register, 514 .define_fields = syscall_enter_define_fields, 515 .get_fields = syscall_get_enter_fields, 516 .raw_init = init_syscall_trace, 517 }; 518 519 struct ftrace_event_class __refdata event_class_syscall_exit = { 520 .system = "syscalls", 521 .reg = syscall_exit_register, 522 .define_fields = syscall_exit_define_fields, 523 .fields = LIST_HEAD_INIT(event_class_syscall_exit.fields), 524 .raw_init = init_syscall_trace, 525 }; 526 527 unsigned long __init __weak arch_syscall_addr(int nr) 528 { 529 return (unsigned long)sys_call_table[nr]; 530 } 531 532 static int __init init_ftrace_syscalls(void) 533 { 534 struct syscall_metadata *meta; 535 unsigned long addr; 536 int i; 537 538 syscalls_metadata = kcalloc(NR_syscalls, sizeof(*syscalls_metadata), 539 GFP_KERNEL); 540 if (!syscalls_metadata) { 541 WARN_ON(1); 542 return -ENOMEM; 543 } 544 545 for (i = 0; i < NR_syscalls; i++) { 546 addr = arch_syscall_addr(i); 547 meta = find_syscall_meta(addr); 548 if (!meta) 549 continue; 550 551 meta->syscall_nr = i; 552 syscalls_metadata[i] = meta; 553 } 554 555 return 0; 556 } 557 early_initcall(init_ftrace_syscalls); 558 559 #ifdef CONFIG_PERF_EVENTS 560 561 static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls); 562 static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls); 563 static int sys_perf_refcount_enter; 564 static int sys_perf_refcount_exit; 565 566 static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) 567 { 568 struct syscall_metadata *sys_data; 569 struct syscall_trace_enter *rec; 570 struct hlist_head *head; 571 int syscall_nr; 572 int rctx; 573 int size; 574 575 syscall_nr = trace_get_syscall_nr(current, regs); 576 if (syscall_nr < 0) 577 return; 578 if (!test_bit(syscall_nr, enabled_perf_enter_syscalls)) 579 return; 580 581 sys_data = syscall_nr_to_meta(syscall_nr); 582 if (!sys_data) 583 return; 584 585 head = this_cpu_ptr(sys_data->enter_event->perf_events); 586 if (hlist_empty(head)) 587 return; 588 589 /* get the size after alignment with the u32 buffer size field */ 590 size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec); 591 size = ALIGN(size + sizeof(u32), sizeof(u64)); 592 size -= sizeof(u32); 593 594 rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size, 595 sys_data->enter_event->event.type, regs, &rctx); 596 if (!rec) 597 return; 598 599 rec->nr = syscall_nr; 600 syscall_get_arguments(current, regs, 0, sys_data->nb_args, 601 (unsigned long *)&rec->args); 602 perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); 603 } 604 605 static int perf_sysenter_enable(struct ftrace_event_call *call) 606 { 607 int ret = 0; 608 int num; 609 610 num = ((struct syscall_metadata *)call->data)->syscall_nr; 611 612 mutex_lock(&syscall_trace_lock); 613 if (!sys_perf_refcount_enter) 614 ret = register_trace_sys_enter(perf_syscall_enter, NULL); 615 if (ret) { 616 pr_info("event trace: Could not activate" 617 "syscall entry trace point"); 618 } else { 619 set_bit(num, enabled_perf_enter_syscalls); 620 sys_perf_refcount_enter++; 621 } 622 mutex_unlock(&syscall_trace_lock); 623 return ret; 624 } 625 626 static void perf_sysenter_disable(struct ftrace_event_call *call) 627 { 628 int num; 629 630 num = ((struct syscall_metadata *)call->data)->syscall_nr; 631 632 mutex_lock(&syscall_trace_lock); 633 sys_perf_refcount_enter--; 634 clear_bit(num, enabled_perf_enter_syscalls); 635 if (!sys_perf_refcount_enter) 636 unregister_trace_sys_enter(perf_syscall_enter, NULL); 637 mutex_unlock(&syscall_trace_lock); 638 } 639 640 static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) 641 { 642 struct syscall_metadata *sys_data; 643 struct syscall_trace_exit *rec; 644 struct hlist_head *head; 645 int syscall_nr; 646 int rctx; 647 int size; 648 649 syscall_nr = trace_get_syscall_nr(current, regs); 650 if (syscall_nr < 0) 651 return; 652 if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) 653 return; 654 655 sys_data = syscall_nr_to_meta(syscall_nr); 656 if (!sys_data) 657 return; 658 659 head = this_cpu_ptr(sys_data->exit_event->perf_events); 660 if (hlist_empty(head)) 661 return; 662 663 /* We can probably do that at build time */ 664 size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64)); 665 size -= sizeof(u32); 666 667 rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size, 668 sys_data->exit_event->event.type, regs, &rctx); 669 if (!rec) 670 return; 671 672 rec->nr = syscall_nr; 673 rec->ret = syscall_get_return_value(current, regs); 674 perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL); 675 } 676 677 static int perf_sysexit_enable(struct ftrace_event_call *call) 678 { 679 int ret = 0; 680 int num; 681 682 num = ((struct syscall_metadata *)call->data)->syscall_nr; 683 684 mutex_lock(&syscall_trace_lock); 685 if (!sys_perf_refcount_exit) 686 ret = register_trace_sys_exit(perf_syscall_exit, NULL); 687 if (ret) { 688 pr_info("event trace: Could not activate" 689 "syscall exit trace point"); 690 } else { 691 set_bit(num, enabled_perf_exit_syscalls); 692 sys_perf_refcount_exit++; 693 } 694 mutex_unlock(&syscall_trace_lock); 695 return ret; 696 } 697 698 static void perf_sysexit_disable(struct ftrace_event_call *call) 699 { 700 int num; 701 702 num = ((struct syscall_metadata *)call->data)->syscall_nr; 703 704 mutex_lock(&syscall_trace_lock); 705 sys_perf_refcount_exit--; 706 clear_bit(num, enabled_perf_exit_syscalls); 707 if (!sys_perf_refcount_exit) 708 unregister_trace_sys_exit(perf_syscall_exit, NULL); 709 mutex_unlock(&syscall_trace_lock); 710 } 711 712 #endif /* CONFIG_PERF_EVENTS */ 713 714 static int syscall_enter_register(struct ftrace_event_call *event, 715 enum trace_reg type, void *data) 716 { 717 struct ftrace_event_file *file = data; 718 719 switch (type) { 720 case TRACE_REG_REGISTER: 721 return reg_event_syscall_enter(file, event); 722 case TRACE_REG_UNREGISTER: 723 unreg_event_syscall_enter(file, event); 724 return 0; 725 726 #ifdef CONFIG_PERF_EVENTS 727 case TRACE_REG_PERF_REGISTER: 728 return perf_sysenter_enable(event); 729 case TRACE_REG_PERF_UNREGISTER: 730 perf_sysenter_disable(event); 731 return 0; 732 case TRACE_REG_PERF_OPEN: 733 case TRACE_REG_PERF_CLOSE: 734 case TRACE_REG_PERF_ADD: 735 case TRACE_REG_PERF_DEL: 736 return 0; 737 #endif 738 } 739 return 0; 740 } 741 742 static int syscall_exit_register(struct ftrace_event_call *event, 743 enum trace_reg type, void *data) 744 { 745 struct ftrace_event_file *file = data; 746 747 switch (type) { 748 case TRACE_REG_REGISTER: 749 return reg_event_syscall_exit(file, event); 750 case TRACE_REG_UNREGISTER: 751 unreg_event_syscall_exit(file, event); 752 return 0; 753 754 #ifdef CONFIG_PERF_EVENTS 755 case TRACE_REG_PERF_REGISTER: 756 return perf_sysexit_enable(event); 757 case TRACE_REG_PERF_UNREGISTER: 758 perf_sysexit_disable(event); 759 return 0; 760 case TRACE_REG_PERF_OPEN: 761 case TRACE_REG_PERF_CLOSE: 762 case TRACE_REG_PERF_ADD: 763 case TRACE_REG_PERF_DEL: 764 return 0; 765 #endif 766 } 767 return 0; 768 } 769