switch (event->type) {
case LTTNG_EVENT_ALL:
{
+ char *filter_expression_a = NULL;
+ struct lttng_filter_bytecode *filter_a = NULL;
+
+ /*
+ * We need to duplicate filter_expression and filter,
+ * because ownership is passed to first enable
+ * event.
+ */
+ if (filter_expression) {
+ filter_expression_a = strdup(filter_expression);
+ if (!filter_expression_a) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+ }
+ if (filter) {
+ filter_a = zmalloc(sizeof(*filter_a) + filter->len);
+ if (!filter_a) {
+ free(filter_expression_a);
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+ memcpy(filter_a, filter, sizeof(*filter_a) + filter->len);
+ }
event->type = LTTNG_EVENT_TRACEPOINT; /* Hack */
- ret = event_kernel_enable_event(kchan, event);
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression, filter);
if (ret != LTTNG_OK) {
if (channel_created) {
/* Let's not leak a useless channel. */
kernel_destroy_channel(kchan);
}
+ free(filter_expression_a);
+ free(filter_a);
goto error;
}
event->type = LTTNG_EVENT_SYSCALL; /* Hack */
- ret = event_kernel_enable_event(kchan, event);
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression_a, filter_a);
if (ret != LTTNG_OK) {
+ free(filter_expression_a);
+ free(filter_a);
goto error;
}
break;
case LTTNG_EVENT_FUNCTION:
case LTTNG_EVENT_FUNCTION_ENTRY:
case LTTNG_EVENT_TRACEPOINT:
- ret = event_kernel_enable_event(kchan, event);
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression, filter);
if (ret != LTTNG_OK) {
if (channel_created) {
/* Let's not leak a useless channel. */
}
break;
case LTTNG_EVENT_SYSCALL:
- ret = event_kernel_enable_event(kchan, event);
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression, filter);
if (ret != LTTNG_OK) {
goto error;
}
* We own filter_expression and filter.
*/
int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
- struct lttng_event *event)
+ struct lttng_event *event, char *filter_expression,
+ struct lttng_filter_bytecode *filter)
{
int ret;
struct ltt_kernel_event *kevent;
assert(kchan);
assert(event);
- kevent = trace_kernel_get_event_by_name(event->name, kchan,
- event->type);
+ kevent = trace_kernel_find_event(event->name, kchan,
+ event->type, filter);
if (kevent == NULL) {
- ret = kernel_create_event(event, kchan);
+ ret = kernel_create_event(event, kchan,
+ filter_expression, filter);
if (ret < 0) {
switch (-ret) {
case EEXIST:
int event_kernel_disable_event_all(struct ltt_kernel_channel *kchan);
int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
- struct lttng_event *event);
+ struct lttng_event *event, char *filter_expression,
+ struct lttng_filter_bytecode *filter);
int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
struct ltt_ust_channel *uchan, struct lttng_event *event,
* We own filter_expression and filter.
*/
int kernel_create_event(struct lttng_event *ev,
- struct ltt_kernel_channel *channel)
+ struct ltt_kernel_channel *channel,
+ char *filter_expression,
+ struct lttng_filter_bytecode *filter)
{
int ret;
struct ltt_kernel_event *event;
assert(ev);
assert(channel);
- event = trace_kernel_create_event(ev);
+ event = trace_kernel_create_event(ev, filter_expression,
+ filter);
if (event == NULL) {
ret = -1;
goto error;
PERROR("fcntl session fd");
}
+ if (filter) {
+ ret = kernctl_filter(event->fd, filter);
+ if (ret) {
+ goto filter_error;
+ }
+ }
+
+ ret = kernctl_enable(event->fd);
+ if (ret < 0) {
+ switch (errno) {
+ case EEXIST:
+ ret = LTTNG_ERR_KERN_EVENT_EXIST;
+ break;
+ default:
+ PERROR("enable kernel event");
+ break;
+ }
+ goto enable_error;
+ }
+
/* Add event to event list */
cds_list_add(&event->list, &channel->events_list.head);
channel->event_count++;
return 0;
+enable_error:
+filter_error:
+ {
+ int closeret;
+
+ closeret = close(event->fd);
+ if (closeret) {
+ PERROR("close event fd");
+ }
+ }
free_event:
free(event);
error:
int kernel_create_session(struct ltt_session *session, int tracer_fd);
int kernel_create_channel(struct ltt_kernel_session *session,
struct lttng_channel *chan);
-int kernel_create_event(struct lttng_event *ev, struct ltt_kernel_channel *channel);
+int kernel_create_event(struct lttng_event *ev, struct ltt_kernel_channel *channel,
+ char *filter_expression, struct lttng_filter_bytecode *filter);
int kernel_disable_channel(struct ltt_kernel_channel *chan);
int kernel_disable_event(struct ltt_kernel_event *event);
int kernel_enable_event(struct ltt_kernel_event *event);
struct ltt_kernel_event *kevent;
/* Create a temporary kevent in order to save it. */
- kevent = trace_kernel_create_event(&events[i]);
+ /*
+ * TODO: struct lttng_event does not really work for a filter,
+ * but unfortunately, it is exposed as external API (and used as
+ * internal representation. Using NULL meanwhile.
+ */
+ kevent = trace_kernel_create_event(&events[i],
+ NULL, NULL);
if (!kevent) {
ret = -ENOMEM;
goto end;
return NULL;
}
+/*
+ * Find the event for the given channel.
+ */
+struct ltt_kernel_event *trace_kernel_find_event(
+ char *name, struct ltt_kernel_channel *channel,
+ enum lttng_event_type type,
+ struct lttng_filter_bytecode *filter)
+{
+ struct ltt_kernel_event *ev;
+ int found = 0;
+
+ assert(name);
+ assert(channel);
+
+ cds_list_for_each_entry(ev, &channel->events_list.head, list) {
+ if (type != LTTNG_EVENT_ALL && ev->type != type) {
+ continue;
+ }
+ if (strcmp(name, ev->event->name)) {
+ continue;
+ }
+ if ((ev->filter && !filter) || (!ev->filter && filter)) {
+ continue;
+ }
+ if (ev->filter && filter) {
+ if (ev->filter->len != filter->len ||
+ memcmp(ev->filter->data, filter->data,
+ filter->len) != 0) {
+ continue;
+ }
+ }
+ found = 1;
+ break;
+ }
+ if (found) {
+ DBG("Found event %s for channel %s", name,
+ channel->channel->name);
+ return ev;
+ } else {
+ return NULL;
+ }
+}
+
/*
* Find the event name for the given channel.
*/
enum lttng_event_type type)
{
struct ltt_kernel_event *ev;
+ int found = 0;
assert(name);
assert(channel);
cds_list_for_each_entry(ev, &channel->events_list.head, list) {
- if (type != LTTNG_EVENT_ALL && ev->type != type)
+ if (type != LTTNG_EVENT_ALL && ev->type != type) {
continue;
- if (strcmp(name, ev->event->name) == 0) {
- DBG("Found event by name %s for channel %s", name,
- channel->channel->name);
- return ev;
}
+ if (strcmp(name, ev->event->name)) {
+ continue;
+ }
+ found = 1;
+ break;
+ }
+ if (found) {
+ DBG("Found event %s for channel %s", name,
+ channel->channel->name);
+ return ev;
+ } else {
+ return NULL;
}
-
- return NULL;
}
/*
*
* Return pointer to structure or NULL.
*/
-struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev)
+struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev,
+ char *filter_expression, struct lttng_filter_bytecode *filter)
{
struct ltt_kernel_event *lke;
struct lttng_kernel_event *attr;
lke->fd = -1;
lke->event = attr;
lke->enabled = 1;
+ lke->filter_expression = filter_expression;
+ lke->filter = filter;
return lke;
/* Remove from event list */
cds_list_del(&event->list);
+ free(event->filter_expression);
+ free(event->filter);
+
free(event->event);
free(event);
}
enum lttng_event_type type;
struct lttng_kernel_event *event;
struct cds_list_head list;
+ char *filter_expression;
+ struct lttng_filter_bytecode *filter;
};
/* Kernel channel */
struct ltt_kernel_event *trace_kernel_get_event_by_name(
char *name, struct ltt_kernel_channel *channel,
enum lttng_event_type type);
+struct ltt_kernel_event *trace_kernel_find_event(
+ char *name, struct ltt_kernel_channel *channel,
+ enum lttng_event_type type,
+ struct lttng_filter_bytecode *filter);
struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
char *name, struct ltt_kernel_session *session);
struct ltt_kernel_session *trace_kernel_create_session(void);
struct ltt_kernel_channel *trace_kernel_create_channel(
struct lttng_channel *chan);
-struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev);
+struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev,
+ char *filter_expression, struct lttng_filter_bytecode *filter);
struct ltt_kernel_metadata *trace_kernel_create_metadata(void);
struct ltt_kernel_stream *trace_kernel_create_stream(const char *name,
unsigned int count);
memset(&dom, 0, sizeof(dom));
if (opt_kernel) {
- if (opt_filter) {
- ERR("Filter not implement for kernel tracing yet");
- ret = CMD_ERROR;
- goto error;
- }
if (opt_loglevel) {
WARN("Kernel loglevels are not supported.");
}
#include <sys/ioctl.h>
#include <string.h>
#include <common/align.h>
+#include <errno.h>
#include "kernel-ctl.h"
#include "kernel-ioctl.h"
LTTNG_KERNEL_SESSION_STOP);
}
+int kernctl_filter(int fd, struct lttng_filter_bytecode *filter)
+{
+ struct lttng_kernel_filter_bytecode *kb;
+ uint32_t len;
+ int ret;
+
+ /* Translate bytecode to kernel bytecode */
+ kb = zmalloc(sizeof(*kb) + filter->len);
+ if (!kb)
+ return -ENOMEM;
+ kb->len = len = filter->len;
+ kb->reloc_offset = filter->reloc_table_offset;
+ kb->seqnum = filter->seqnum;
+ memcpy(kb->data, filter->data, len);
+ ret = ioctl(fd, LTTNG_KERNEL_FILTER, kb);
+ free(kb);
+ return ret;
+}
+
int kernctl_tracepoint_list(int fd)
{
return compat_ioctl_no_arg(fd, LTTNG_KERNEL_OLD_TRACEPOINT_LIST,
#include <lttng/lttng.h>
#include <common/lttng-kernel.h>
#include <common/lttng-kernel-old.h>
+#include <common/sessiond-comm/sessiond-comm.h> /* for struct lttng_filter_bytecode */
int kernctl_create_session(int fd);
int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops);
int kernctl_start_session(int fd);
int kernctl_stop_session(int fd);
+/* Apply on event FD */
+int kernctl_filter(int fd, struct lttng_filter_bytecode *filter);
+
int kernctl_tracepoint_list(int fd);
int kernctl_syscall_list(int fd);
int kernctl_tracer_version(int fd, struct lttng_kernel_tracer_version *v);
#define LTTNG_KERNEL_ENABLE _IO(0xF6, 0x82)
#define LTTNG_KERNEL_DISABLE _IO(0xF6, 0x83)
+/* Event FD ioctl */
+#define LTTNG_KERNEL_FILTER _IO(0xF6, 0x90)
+
#endif /* _LTT_KERNEL_IOCTL_H */
char padding[LTTNG_KERNEL_CHANNEL_PADDING1];
} LTTNG_PACKED;
+#define KERNEL_FILTER_BYTECODE_MAX_LEN 65536
+struct lttng_kernel_filter_bytecode {
+ uint32_t len;
+ uint32_t reloc_offset;
+ uint64_t seqnum;
+ char data[0];
+} LTTNG_PACKED;
+
#endif /* _LTTNG_KERNEL_H */
FILTER_OP_GET_CONTEXT_REF_S64 = 72,
FILTER_OP_GET_CONTEXT_REF_DOUBLE = 73,
+ /* load userspace field ref */
+ FILTER_OP_LOAD_FIELD_REF_USER_STRING = 74,
+ FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE = 75,
+
NR_FILTER_OPS,
};
ev.type = LTTNG_EVENT_TRACEPOINT;
ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
- event = trace_kernel_create_event(&ev);
+ event = trace_kernel_create_event(&ev, NULL, NULL);
ok(event != NULL, "Create kernel event");
ok(event->fd == -1 &&