case LTTNG_KERNEL_KRETPROBE:
case LTTNG_KERNEL_FUNCTION:
case LTTNG_KERNEL_NOOP:
+ case LTTNG_KERNEL_SYSCALL:
event_name = event_param->name;
break;
default:
name_len = strlen(event_name);
hash = jhash(event_name, name_len, 0);
head = &session->events_ht.table[hash & (LTTNG_EVENT_HT_SIZE - 1)];
- hlist_for_each_entry(event, head, hlist) {
+ lttng_hlist_for_each_entry(event, head, hlist) {
WARN_ON_ONCE(!event->desc);
if (!strncmp(event->desc->name, event_name,
LTTNG_KERNEL_SYM_NAME_LEN - 1)
event->id = chan->free_event_id++;
event->instrumentation = itype;
event->evtype = LTTNG_TYPE_EVENT;
+ INIT_LIST_HEAD(&event->bytecode_runtime_head);
INIT_LIST_HEAD(&event->enablers_ref_head);
switch (itype) {
WARN_ON_ONCE(!ret);
break;
case LTTNG_KERNEL_NOOP:
+ case LTTNG_KERNEL_SYSCALL:
event->enabled = 1;
event->registered = 0;
event->desc = event_desc;
void register_event(struct lttng_event *event)
{
const struct lttng_event_desc *desc;
- int ret;
+ int ret = -EINVAL;
- WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_TRACEPOINT);
if (event->registered)
return;
+
desc = event->desc;
- ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
- desc->probe_callback, event);
+ switch (event->instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
+ desc->probe_callback,
+ event);
+ break;
+ case LTTNG_KERNEL_SYSCALL:
+ ret = lttng_syscall_filter_enable(event->chan,
+ desc->name);
+ break;
+ case LTTNG_KERNEL_KPROBE:
+ case LTTNG_KERNEL_KRETPROBE:
+ case LTTNG_KERNEL_FUNCTION:
+ case LTTNG_KERNEL_NOOP:
+ ret = 0;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
if (!ret)
event->registered = 1;
}
*/
int _lttng_event_unregister(struct lttng_event *event)
{
+ const struct lttng_event_desc *desc;
int ret = -EINVAL;
if (!event->registered)
return 0;
+ desc = event->desc;
switch (event->instrumentation) {
case LTTNG_KERNEL_TRACEPOINT:
ret = lttng_wrapper_tracepoint_probe_unregister(event->desc->kname,
event->desc->probe_callback,
event);
- if (ret)
- return ret;
break;
case LTTNG_KERNEL_KPROBE:
lttng_kprobes_unregister(event);
lttng_ftrace_unregister(event);
ret = 0;
break;
+ case LTTNG_KERNEL_SYSCALL:
+ ret = lttng_syscall_filter_disable(event->chan,
+ desc->name);
+ break;
case LTTNG_KERNEL_NOOP:
ret = 0;
break;
lttng_ftrace_destroy_private(event);
break;
case LTTNG_KERNEL_NOOP:
+ case LTTNG_KERNEL_SYSCALL:
break;
default:
WARN_ON_ONCE(1);
* Enabler management.
*/
static
-int lttng_desc_match_wildcard_enabler(const struct lttng_event_desc *desc,
- struct lttng_enabler *enabler)
+int lttng_match_enabler_wildcard(const char *desc_name,
+ const char *name)
{
- WARN_ON_ONCE(enabler->type != LTTNG_ENABLER_WILDCARD);
/* Compare excluding final '*' */
- if (strncmp(desc->name, enabler->event_param.name,
- strlen(enabler->event_param.name) - 1))
+ if (strncmp(desc_name, name, strlen(name) - 1))
return 0;
return 1;
}
static
-int lttng_desc_match_name_enabler(const struct lttng_event_desc *desc,
- struct lttng_enabler *enabler)
+int lttng_match_enabler_name(const char *desc_name,
+ const char *name)
{
- WARN_ON_ONCE(enabler->type != LTTNG_ENABLER_NAME);
- if (strcmp(desc->name, enabler->event_param.name))
+ if (strcmp(desc_name, name))
return 0;
return 1;
}
int lttng_desc_match_enabler(const struct lttng_event_desc *desc,
struct lttng_enabler *enabler)
{
+ const char *desc_name, *enabler_name;
+
+ enabler_name = enabler->event_param.name;
+ switch (enabler->event_param.instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ desc_name = desc->name;
+ break;
+ case LTTNG_KERNEL_SYSCALL:
+ desc_name = desc->name;
+ if (!strncmp(desc_name, "compat_", strlen("compat_")))
+ desc_name += strlen("compat_");
+ if (!strncmp(desc_name, "syscall_exit_",
+ strlen("syscall_exit_"))) {
+ desc_name += strlen("syscall_exit_");
+ } else if (!strncmp(desc_name, "syscall_entry_",
+ strlen("syscall_entry_"))) {
+ desc_name += strlen("syscall_entry_");
+ } else {
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
switch (enabler->type) {
case LTTNG_ENABLER_WILDCARD:
- return lttng_desc_match_wildcard_enabler(desc, enabler);
+ return lttng_match_enabler_wildcard(desc_name, enabler_name);
case LTTNG_ENABLER_NAME:
- return lttng_desc_match_name_enabler(desc, enabler);
+ return lttng_match_enabler_name(desc_name, enabler_name);
default:
return -EINVAL;
}
int lttng_event_match_enabler(struct lttng_event *event,
struct lttng_enabler *enabler)
{
+ if (enabler->event_param.instrumentation != event->instrumentation)
+ return 0;
if (lttng_desc_match_enabler(event->desc, enabler)
&& event->chan == enabler->chan)
return 1;
return NULL;
}
-/*
- * Create struct lttng_event if it is missing and present in the list of
- * tracepoint probes.
- * Should be called with sessions mutex held.
- */
static
-void lttng_create_event_if_missing(struct lttng_enabler *enabler)
+void lttng_create_tracepoint_if_missing(struct lttng_enabler *enabler)
{
struct lttng_session *session = enabler->chan->session;
struct lttng_probe_desc *probe_desc;
*/
hash = jhash(event_name, name_len, 0);
head = &session->events_ht.table[hash & (LTTNG_EVENT_HT_SIZE - 1)];
- hlist_for_each_entry(event, head, hlist) {
+ lttng_hlist_for_each_entry(event, head, hlist) {
if (event->desc == desc
&& event->chan == enabler->chan)
found = 1;
}
}
+static
+void lttng_create_syscall_if_missing(struct lttng_enabler *enabler)
+{
+ int ret;
+
+ ret = lttng_syscalls_register(enabler->chan, NULL);
+ WARN_ON_ONCE(ret);
+}
+
+/*
+ * Create struct lttng_event if it is missing and present in the list of
+ * tracepoint probes.
+ * Should be called with sessions mutex held.
+ */
+static
+void lttng_create_event_if_missing(struct lttng_enabler *enabler)
+{
+ switch (enabler->event_param.instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ lttng_create_tracepoint_if_missing(enabler);
+ break;
+ case LTTNG_KERNEL_SYSCALL:
+ lttng_create_syscall_if_missing(enabler);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
/*
* Create events associated with an enabler (if not already present),
* and add backward reference from the event to the enabler.
&event->enablers_ref_head);
}
+ /*
+ * Link filter bytecodes if not linked yet.
+ */
+ lttng_enabler_event_link_bytecode(event, enabler);
+
/* TODO: merge event context. */
}
return 0;
if (!enabler)
return NULL;
enabler->type = type;
+ INIT_LIST_HEAD(&enabler->filter_bytecode_head);
memcpy(&enabler->event_param, event_param,
sizeof(enabler->event_param));
enabler->chan = chan;
/* ctx left NULL */
- enabler->enabled = 1;
+ enabler->enabled = 0;
enabler->evtype = LTTNG_TYPE_ENABLER;
mutex_lock(&sessions_mutex);
list_add(&enabler->node, &enabler->chan->session->enablers_head);
return 0;
}
+int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
+ struct lttng_kernel_filter_bytecode __user *bytecode)
+{
+ struct lttng_filter_bytecode_node *bytecode_node;
+ uint32_t bytecode_len;
+ int ret;
+
+ ret = get_user(bytecode_len, &bytecode->len);
+ if (ret)
+ return ret;
+ bytecode_node = kzalloc(sizeof(*bytecode_node) + bytecode_len,
+ GFP_KERNEL);
+ if (!bytecode_node)
+ return -ENOMEM;
+ ret = copy_from_user(&bytecode_node->bc, bytecode,
+ sizeof(*bytecode) + bytecode_len);
+ if (ret)
+ goto error_free;
+ bytecode_node->enabler = enabler;
+ /* Enforce length based on allocated size */
+ bytecode_node->bc.len = bytecode_len;
+ list_add_tail(&bytecode_node->node, &enabler->filter_bytecode_head);
+ lttng_session_lazy_sync_enablers(enabler->chan->session);
+ return 0;
+
+error_free:
+ kfree(bytecode_node);
+ return ret;
+}
+
int lttng_enabler_attach_context(struct lttng_enabler *enabler,
struct lttng_kernel_context *context_param)
{
static
void lttng_enabler_destroy(struct lttng_enabler *enabler)
{
+ struct lttng_filter_bytecode_node *filter_node, *tmp_filter_node;
+
+ /* Destroy filter bytecode */
+ list_for_each_entry_safe(filter_node, tmp_filter_node,
+ &enabler->filter_bytecode_head, node) {
+ kfree(filter_node);
+ }
+
/* Destroy contexts */
lttng_destroy_context(enabler->ctx);
*/
list_for_each_entry(event, &session->events, list) {
struct lttng_enabler_ref *enabler_ref;
- int enabled = 0;
+ struct lttng_bytecode_runtime *runtime;
+ int enabled = 0, has_enablers_without_bytecode = 0;
- if (event->instrumentation == LTTNG_KERNEL_TRACEPOINT) {
+ switch (event->instrumentation) {
+ case LTTNG_KERNEL_TRACEPOINT:
+ case LTTNG_KERNEL_SYSCALL:
/* Enable events */
list_for_each_entry(enabler_ref,
&event->enablers_ref_head, node) {
break;
}
}
- } else {
+ break;
+ default:
/* Not handled with lazy sync. */
continue;
}
} else {
_lttng_event_unregister(event);
}
+
+ /* Check if has enablers without bytecode enabled */
+ list_for_each_entry(enabler_ref,
+ &event->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled
+ && list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+ has_enablers_without_bytecode = 1;
+ break;
+ }
+ }
+ event->has_enablers_without_bytecode =
+ has_enablers_without_bytecode;
+
+ /* Enable filters */
+ list_for_each_entry(runtime,
+ &event->bytecode_runtime_head, node)
+ lttng_filter_sync_state(runtime);
}
}
if (ret)
return ret;
- ret = lttng_tracepoint_init();
+ ret = lttng_context_init();
if (ret)
return ret;
+ ret = lttng_tracepoint_init();
+ if (ret)
+ goto error_tp;
event_cache = KMEM_CACHE(lttng_event, 0);
if (!event_cache) {
ret = -ENOMEM;
kmem_cache_destroy(event_cache);
error_kmem:
lttng_tracepoint_exit();
+error_tp:
+ lttng_context_exit();
return ret;
}
lttng_session_destroy(session);
kmem_cache_destroy(event_cache);
lttng_tracepoint_exit();
+ lttng_context_exit();
}
module_exit(lttng_events_exit);