linux/kernel/trace/trace_syscalls.c
<<
>>
Prefs
   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
  14static DEFINE_MUTEX(syscall_trace_lock);
  15static int sys_refcount_enter;
  16static int sys_refcount_exit;
  17static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
  18static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
  19
  20static int syscall_enter_register(struct ftrace_event_call *event,
  21                                 enum trace_reg type, void *data);
  22static int syscall_exit_register(struct ftrace_event_call *event,
  23                                 enum trace_reg type, void *data);
  24
  25static struct list_head *
  26syscall_get_enter_fields(struct ftrace_event_call *call)
  27{
  28        struct syscall_metadata *entry = call->data;
  29
  30        return &entry->enter_fields;
  31}
  32
  33extern struct syscall_metadata *__start_syscalls_metadata[];
  34extern struct syscall_metadata *__stop_syscalls_metadata[];
  35
  36static struct syscall_metadata **syscalls_metadata;
  37
  38#ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME
  39static 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 */
  67static int
  68trace_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
  76static inline int
  77trace_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
  83static __init struct syscall_metadata *
  84find_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
 105static 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
 113static enum print_line_t
 114print_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
 158end:
 159        ret =  trace_seq_putc(s, '\n');
 160        if (!ret)
 161                return TRACE_TYPE_PARTIAL_LINE;
 162
 163        return TRACE_TYPE_HANDLED;
 164}
 165
 166static enum print_line_t
 167print_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
 199extern 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
 207static
 208int  __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
 235static 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
 260static 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
 268static 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
 291static 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
 306static 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
 341static 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
 373static 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
 392static 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
 407static 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
 426static 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
 441static 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
 466struct trace_event_functions enter_syscall_print_funcs = {
 467        .trace          = print_syscall_enter,
 468};
 469
 470struct trace_event_functions exit_syscall_print_funcs = {
 471        .trace          = print_syscall_exit,
 472};
 473
 474struct 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
 482struct 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
 490unsigned long __init __weak arch_syscall_addr(int nr)
 491{
 492        return (unsigned long)sys_call_table[nr];
 493}
 494
 495static 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}
 520early_initcall(init_ftrace_syscalls);
 521
 522#ifdef CONFIG_PERF_EVENTS
 523
 524static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls);
 525static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls);
 526static int sys_perf_refcount_enter;
 527static int sys_perf_refcount_exit;
 528
 529static 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
 570static 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
 591static 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
 605static 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
 648static 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
 669static 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
 685static 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
 711static 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.