-static
-void syscall_exit_event_notifier_probe(void *__data, struct pt_regs *regs,
- long ret)
-{
- struct lttng_event_notifier_group *group = __data;
- const struct trace_syscall_entry *table, *entry;
- struct hlist_head *dispatch_list, *unknown_dispatch_list;
- size_t table_len;
- long id;
-
- id = syscall_get_nr(current, regs);
-
- if (unlikely(in_compat_syscall())) {
- struct lttng_syscall_filter *filter = group->sc_filter;
-
- if (id < 0 || id >= NR_compat_syscalls
- || (!READ_ONCE(group->syscall_all_exit) &&
- !test_bit(id, filter->sc_compat_exit))) {
- /* System call filtered out. */
- return;
- }
- table = compat_sc_exit_table;
- table_len = ARRAY_SIZE(compat_sc_exit_table);
- unknown_dispatch_list = &group->event_notifier_exit_compat_unknown_syscall_dispatch;
- } else {
- struct lttng_syscall_filter *filter = group->sc_filter;
-
- if (id < 0 || id >= NR_syscalls
- || (!READ_ONCE(group->syscall_all_exit) &&
- !test_bit(id, filter->sc_exit))) {
- /* System call filtered out. */
- return;
- }
- table = sc_exit_table;
- table_len = ARRAY_SIZE(sc_exit_table);
- unknown_dispatch_list = &group->event_notifier_exit_unknown_syscall_dispatch;
- }
- /* Check if the syscall id is out of bound. */
- if (unlikely(id < 0 || id >= table_len)) {
- syscall_exit_event_notifier_unknown(unknown_dispatch_list,
- regs, id, ret);
- return;
- }
-
- entry = &table[id];
- if (!entry->event_notifier_func) {
- syscall_entry_event_notifier_unknown(unknown_dispatch_list,
- regs, id);
- return;
- }
-
- if (unlikely(in_compat_syscall())) {
- dispatch_list = &group->event_notifier_exit_compat_syscall_dispatch[id];
- } else {
- dispatch_list = &group->event_notifier_exit_syscall_dispatch[id];
- }
- if (unlikely(hlist_empty(dispatch_list)))
- return;
-
- syscall_exit_event_notifier_call_func(dispatch_list,
- entry->event_notifier_func, entry->nrargs, regs, ret);
-}
-/*
- * noinline to diminish caller stack size.
- * Should be called with sessions lock held.
- */
-static
-int fill_event_table(const struct trace_syscall_entry *table, size_t table_len,
- struct lttng_event **chan_table, struct lttng_channel *chan,
- void *filter, enum sc_type type)
-{
- const struct lttng_event_desc *desc;
- unsigned int i;
-
- /* Allocate events for each syscall, insert into table */
- for (i = 0; i < table_len; i++) {
- struct lttng_kernel_event ev;
- desc = table[i].desc;
-
- if (!desc) {
- /* Unknown syscall */
- continue;
- }
- /*
- * Skip those already populated by previous failed
- * register for this channel.
- */
- if (chan_table[i])
- continue;
- memset(&ev, 0, sizeof(ev));
- switch (type) {
- case SC_TYPE_ENTRY:
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
- break;
- case SC_TYPE_EXIT:
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
- break;
- case SC_TYPE_COMPAT_ENTRY:
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
- break;
- case SC_TYPE_COMPAT_EXIT:
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
- break;
- }
- strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN - 1);
- ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
- ev.instrumentation = LTTNG_KERNEL_SYSCALL;
- chan_table[i] = _lttng_event_create(chan, &ev, filter,
- desc, ev.instrumentation);
- WARN_ON_ONCE(!chan_table[i]);
- if (IS_ERR(chan_table[i])) {
- /*
- * If something goes wrong in event registration
- * after the first one, we have no choice but to
- * leave the previous events in there, until
- * deleted by session teardown.
- */
- return PTR_ERR(chan_table[i]);
- }
- }
- return 0;
-}
-
-/*
- * Should be called with sessions lock held.
- */
-int lttng_syscalls_register_event(struct lttng_channel *chan, void *filter)
-{
- struct lttng_kernel_event ev;
- int ret;
-
- wrapper_vmalloc_sync_mappings();
-
- if (!chan->sc_table) {
- /* create syscall table mapping syscall to events */
- chan->sc_table = kzalloc(sizeof(struct lttng_event *)
- * ARRAY_SIZE(sc_table), GFP_KERNEL);
- if (!chan->sc_table)
- return -ENOMEM;
- }
- if (!chan->sc_exit_table) {
- /* create syscall table mapping syscall to events */
- chan->sc_exit_table = kzalloc(sizeof(struct lttng_event *)
- * ARRAY_SIZE(sc_exit_table), GFP_KERNEL);
- if (!chan->sc_exit_table)
- return -ENOMEM;
- }
-
-
-#ifdef CONFIG_COMPAT
- if (!chan->compat_sc_table) {
- /* create syscall table mapping compat syscall to events */
- chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
- * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
- if (!chan->compat_sc_table)
- return -ENOMEM;
- }
-
- if (!chan->compat_sc_exit_table) {
- /* create syscall table mapping compat syscall to events */
- chan->compat_sc_exit_table = kzalloc(sizeof(struct lttng_event *)
- * ARRAY_SIZE(compat_sc_exit_table), GFP_KERNEL);
- if (!chan->compat_sc_exit_table)
- return -ENOMEM;
- }
-#endif
- if (!chan->sc_unknown) {
- const struct lttng_event_desc *desc =
- &__event_desc___syscall_entry_unknown;
-
- memset(&ev, 0, sizeof(ev));
- strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
- ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
- ev.instrumentation = LTTNG_KERNEL_SYSCALL;
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
- chan->sc_unknown = _lttng_event_create(chan, &ev, filter,
- desc,
- ev.instrumentation);
- WARN_ON_ONCE(!chan->sc_unknown);
- if (IS_ERR(chan->sc_unknown)) {
- return PTR_ERR(chan->sc_unknown);
- }
- }
-
- if (!chan->sc_compat_unknown) {
- const struct lttng_event_desc *desc =
- &__event_desc___compat_syscall_entry_unknown;
-
- memset(&ev, 0, sizeof(ev));
- strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
- ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
- ev.instrumentation = LTTNG_KERNEL_SYSCALL;
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
- chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter,
- desc,
- ev.instrumentation);
- WARN_ON_ONCE(!chan->sc_unknown);
- if (IS_ERR(chan->sc_compat_unknown)) {
- return PTR_ERR(chan->sc_compat_unknown);
- }
- }
-
- if (!chan->compat_sc_exit_unknown) {
- const struct lttng_event_desc *desc =
- &__event_desc___compat_syscall_exit_unknown;
-
- memset(&ev, 0, sizeof(ev));
- strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
- ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
- ev.instrumentation = LTTNG_KERNEL_SYSCALL;
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
- chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev,
- filter, desc,
- ev.instrumentation);
- WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
- if (IS_ERR(chan->compat_sc_exit_unknown)) {
- return PTR_ERR(chan->compat_sc_exit_unknown);
- }
- }
-
- if (!chan->sc_exit_unknown) {
- const struct lttng_event_desc *desc =
- &__event_desc___syscall_exit_unknown;
-
- memset(&ev, 0, sizeof(ev));
- strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
- ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
- ev.instrumentation = LTTNG_KERNEL_SYSCALL;
- ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
- ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
- chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter,
- desc, ev.instrumentation);
- WARN_ON_ONCE(!chan->sc_exit_unknown);
- if (IS_ERR(chan->sc_exit_unknown)) {
- return PTR_ERR(chan->sc_exit_unknown);
- }
- }
-
- ret = fill_event_table(sc_table, ARRAY_SIZE(sc_table),
- chan->sc_table, chan, filter, SC_TYPE_ENTRY);
- if (ret)
- return ret;
- ret = fill_event_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
- chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
- if (ret)
- return ret;
-
-#ifdef CONFIG_COMPAT
- ret = fill_event_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
- chan->compat_sc_table, chan, filter,
- SC_TYPE_COMPAT_ENTRY);
- if (ret)
- return ret;
- ret = fill_event_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
- chan->compat_sc_exit_table, chan, filter,
- SC_TYPE_COMPAT_EXIT);
- if (ret)
- return ret;
-#endif
-
- if (!chan->sc_filter) {
- chan->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter),
- GFP_KERNEL);
- if (!chan->sc_filter)
- return -ENOMEM;
- }
-
- if (!chan->sys_enter_registered) {
- ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
- (void *) syscall_entry_event_probe, chan);
- if (ret)
- return ret;
- chan->sys_enter_registered = 1;
- }
- /*
- * We change the name of sys_exit tracepoint due to namespace
- * conflict with sys_exit syscall entry.
- */
- if (!chan->sys_exit_registered) {
- ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
- (void *) syscall_exit_event_probe, chan);
- if (ret) {
- WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
- (void *) syscall_entry_event_probe, chan));
- return ret;
- }
- chan->sys_exit_registered = 1;
- }
- return ret;
-}
-
-/*
- * Should be called with sessions lock held.
- */
-int lttng_syscalls_register_event_notifier(
- struct lttng_event_notifier_enabler *event_notifier_enabler,
- void *filter)
-{
- struct lttng_event_notifier_group *group = event_notifier_enabler->group;
- unsigned int i;
- int ret = 0;
-
- wrapper_vmalloc_sync_mappings();
-
- if (!group->event_notifier_syscall_dispatch) {
- group->event_notifier_syscall_dispatch =
- kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(sc_table),
- GFP_KERNEL);
- if (!group->event_notifier_syscall_dispatch)
- return -ENOMEM;
-
- /* Initialize all list_head */
- for (i = 0; i < ARRAY_SIZE(sc_table); i++)
- INIT_HLIST_HEAD(&group->event_notifier_syscall_dispatch[i]);
-
- /* Init the unknown syscall notifier list. */
- INIT_HLIST_HEAD(&group->event_notifier_unknown_syscall_dispatch);
- }
-
- if (!group->event_notifier_exit_syscall_dispatch) {
- group->event_notifier_exit_syscall_dispatch =
- kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(sc_table),
- GFP_KERNEL);
- if (!group->event_notifier_exit_syscall_dispatch)
- return -ENOMEM;
-
- /* Initialize all list_head */
- for (i = 0; i < ARRAY_SIZE(sc_table); i++)
- INIT_HLIST_HEAD(&group->event_notifier_exit_syscall_dispatch[i]);
-
- /* Init the unknown exit syscall notifier list. */
- INIT_HLIST_HEAD(&group->event_notifier_exit_unknown_syscall_dispatch);
- }
-
-#ifdef CONFIG_COMPAT
- if (!group->event_notifier_compat_syscall_dispatch) {
- group->event_notifier_compat_syscall_dispatch =
- kzalloc(sizeof(struct hlist_head) * ARRAY_SIZE(compat_sc_table),
- GFP_KERNEL);
- if (!group->event_notifier_syscall_dispatch)
- return -ENOMEM;
-
- /* Initialize all list_head */
- for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++)
- INIT_HLIST_HEAD(&group->event_notifier_compat_syscall_dispatch[i]);