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