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