From: Mathieu Desnoyers Date: Thu, 12 Jul 2012 17:01:14 +0000 (-0400) Subject: Implement filter bytecode support in lttng-session, and parse filter string X-Git-Tag: v2.1.0-rc1~94 X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=53a80697a772bc2e260e3dff006f910be6709f04 Implement filter bytecode support in lttng-session, and parse filter string Signed-off-by: Mathieu Desnoyers --- diff --git a/configure.ac b/configure.ac index cba96c1af..7934a5b27 100644 --- a/configure.ac +++ b/configure.ac @@ -140,6 +140,20 @@ AC_CHECK_LIB([dl], [dlopen], AM_CONDITIONAL([LTTNG_TOOLS_BUILD_WITH_LIBDL], [test "x$have_libdl" = "xyes"]) AM_CONDITIONAL([LTTNG_TOOLS_BUILD_WITH_LIBC_DL], [test "x$have_libc_dl" = "xyes"]) +# Check for fmemopen +AC_CHECK_LIB([c], [fmemopen], +[ + AC_DEFINE_UNQUOTED([LTTNG_HAVE_FMEMOPEN], 1, [Has fmemopen support.]) +] +) + +# Check for open_memstream +AC_CHECK_LIB([c], [open_memstream], +[ + AC_DEFINE_UNQUOTED([LTTNG_HAVE_OPEN_MEMSTREAM], 1, [Has open_memstream support.]) +] +) + # Option to only build the consumer daemon and its libraries AC_ARG_WITH([consumerd-only], AS_HELP_STRING([--with-consumerd-only],[Only build the consumer daemon [default=no]]), diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 4741b6877..598abe077 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -548,6 +548,17 @@ extern int lttng_add_context(struct lttng_handle *handle, extern int lttng_enable_event(struct lttng_handle *handle, struct lttng_event *ev, const char *channel_name); +/* + * Apply a filter expression to an event. + * + * If event_name is NULL, the filter is applied to all events of the channel. + * If channel_name is NULL, a lookup of the event's channel is done. + * If both are NULL, the filter is applied to all events of all channels. + */ +extern int lttng_set_event_filter(struct lttng_handle *handle, + const char *event_name, + const char *channel_name, + const char *filter_expression); /* * Create or enable a channel. * The channel name cannot be NULL. diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index c9201f5da..0cbf0c11a 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -19,7 +19,7 @@ lttng_sessiond_SOURCES = utils.c utils.h \ fd-limit.c fd-limit.h \ consumer.c consumer.h \ kernel-consumer.c kernel-consumer.h \ - consumer.h + consumer.h filter.c filter.h if HAVE_LIBLTTNG_UST_CTL lttng_sessiond_SOURCES += trace-ust.c ust-app.c ust-consumer.c ust-consumer.h diff --git a/src/bin/lttng-sessiond/filter.c b/src/bin/lttng-sessiond/filter.c new file mode 100644 index 000000000..e012cb8a1 --- /dev/null +++ b/src/bin/lttng-sessiond/filter.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2011 - David Goulet + * Copyright (C) 2012 - Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include +#include + +#include "filter.h" +#include "kernel.h" +#include "ust-app.h" +#include "trace-ust.h" + +/* + * Add UST context to event. + */ +static int add_ufilter_to_event(struct ltt_ust_session *usess, int domain, + struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent, + struct lttng_filter_bytecode *bytecode) +{ + int ret; + + if (uevent->filter) { + ret = -EEXIST; + goto error; + } + /* Same layout. */ + uevent->filter = (struct lttng_ust_filter_bytecode *) bytecode; + + switch (domain) { + case LTTNG_DOMAIN_UST: + ret = ust_app_set_filter_event_glb(usess, uchan, uevent, + bytecode); + if (ret < 0) { + goto error; + } + break; + default: + ret = -ENOSYS; + goto error; + } + + DBG("Filter UST added to event %s",uevent->attr.name); + + return 0; + +error: + free(bytecode); + return ret; +} + +/* + * Add UST context to tracer. + */ +int filter_ust_set(struct ltt_ust_session *usess, int domain, + struct lttng_filter_bytecode *bytecode, char *event_name, + char *channel_name) +{ + int ret = LTTCOMM_OK, have_event = 0; + struct lttng_ht_iter iter; + struct lttng_ht *chan_ht; + struct ltt_ust_channel *uchan = NULL; + struct ltt_ust_event *uevent = NULL; + + /* + * Define which channel's hashtable to use from the domain or quit if + * unknown domain. + */ + switch (domain) { + case LTTNG_DOMAIN_UST: + chan_ht = usess->domain_global.channels; + break; +#if 0 + case LTTNG_DOMAIN_UST_EXEC_NAME: + case LTTNG_DOMAIN_UST_PID: + case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: +#endif + default: + ret = LTTCOMM_UND; + goto error; + } + + /* Do we have an event name */ + if (strlen(event_name) != 0) { + have_event = 1; + } + + /* Get UST channel if defined */ + if (strlen(channel_name) != 0) { + uchan = trace_ust_find_channel_by_name(chan_ht, channel_name); + if (uchan == NULL) { + ret = LTTCOMM_UST_CHAN_NOT_FOUND; + goto error; + } + } + + /* If UST channel specified and event name, get UST event ref */ + if (uchan && have_event) { + uevent = trace_ust_find_event_by_name(uchan->events, event_name); + if (uevent == NULL) { + ret = LTTCOMM_UST_EVENT_NOT_FOUND; + goto error; + } + } + + /* At this point, we have 4 possibilities */ + + if (uchan && uevent) { /* Add filter to event in channel */ + ret = add_ufilter_to_event(usess, domain, uchan, uevent, + bytecode); + } else if (uchan && !have_event) { /* Add filter to channel */ + ERR("Cannot add filter to channel"); + ret = LTTCOMM_FATAL; /* not supported. */ + goto error; + } else if (!uchan && have_event) { /* Add filter to event */ + /* Add context to event without having the channel name */ + cds_lfht_for_each_entry(chan_ht->ht, &iter.iter, uchan, node.node) { + uevent = trace_ust_find_event_by_name(uchan->events, event_name); + if (uevent != NULL) { + ret = add_ufilter_to_event(usess, domain, uchan, uevent, bytecode); + /* + * LTTng UST does not allowed the same event to be registered + * multiple time in different or the same channel. So, if we + * found our event, we stop. + */ + goto end; + } + } + ret = LTTCOMM_UST_EVENT_NOT_FOUND; + goto error; + } else if (!uchan && !have_event) { /* Add filter all events, all channels */ + ERR("Cannot add filter to channel"); + ret = LTTCOMM_FATAL; /* not supported. */ + goto error; + } + +end: + switch (ret) { + case -EEXIST: + ret = LTTCOMM_FILTER_EXIST; + break; + case -ENOMEM: + ret = LTTCOMM_FATAL; + break; + case -EINVAL: + ret = LTTCOMM_FILTER_INVAL; + break; + case -ENOSYS: + ret = LTTCOMM_UNKNOWN_DOMAIN; + break; + default: + ret = LTTCOMM_OK; + break; + } + +error: + return ret; +} diff --git a/src/bin/lttng-sessiond/filter.h b/src/bin/lttng-sessiond/filter.h new file mode 100644 index 000000000..d70682433 --- /dev/null +++ b/src/bin/lttng-sessiond/filter.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 - David Goulet + * Copyright (C) 2012 - Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LTT_FILTER_H +#define _LTT_FILTER_H + +#include + +#include "trace-kernel.h" +#include "trace-ust.h" +#include "ust-ctl.h" + +struct lttng_filter_bytecode; + +int filter_ust_set(struct ltt_ust_session *usess, int domain, + struct lttng_filter_bytecode *bytecode, char *event_name, + char *channel_name); + +#endif /* _LTT_FILTER_H */ diff --git a/src/bin/lttng-sessiond/lttng-ust-abi.h b/src/bin/lttng-sessiond/lttng-ust-abi.h index dc6ad7ab6..d8b10c257 100644 --- a/src/bin/lttng-sessiond/lttng-ust-abi.h +++ b/src/bin/lttng-sessiond/lttng-ust-abi.h @@ -168,6 +168,13 @@ struct lttng_ust_calibrate { } u; }; +#define FILTER_BYTECODE_MAX_LEN 65535 +struct lttng_ust_filter_bytecode { + uint16_t len; + uint16_t reloc_offset; + char data[0]; +}; + #define _UST_CMD(minor) (minor) #define _UST_CMDR(minor, type) (minor) #define _UST_CMDW(minor, type) (minor) diff --git a/src/bin/lttng-sessiond/lttng-ust-ctl.h b/src/bin/lttng-sessiond/lttng-ust-ctl.h index c3479c97b..9baf443f3 100644 --- a/src/bin/lttng-sessiond/lttng-ust-ctl.h +++ b/src/bin/lttng-sessiond/lttng-ust-ctl.h @@ -37,6 +37,8 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, int ustctl_add_context(int sock, struct lttng_ust_context *ctx, struct lttng_ust_object_data *obj_data, struct lttng_ust_object_data **context_data); +int ustctl_set_filter(int sock, struct lttng_ust_filter_bytecode *bytecode, + struct lttng_ust_object_data *obj_data); int ustctl_enable(int sock, struct lttng_ust_object_data *object); int ustctl_disable(int sock, struct lttng_ust_object_data *object); diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index a15721d76..e2ca01eb5 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -58,6 +58,7 @@ #include "ust-consumer.h" #include "utils.h" #include "fd-limit.h" +#include "filter.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -2731,6 +2732,46 @@ error: return ret; } +/* + * Command LTTNG_SET_FILTER processed by the client thread. + */ +static int cmd_set_filter(struct ltt_session *session, int domain, + char *channel_name, char *event_name, + struct lttng_filter_bytecode *bytecode) +{ + int ret; + + switch (domain) { + case LTTNG_DOMAIN_KERNEL: + ret = LTTCOMM_FATAL; + break; + case LTTNG_DOMAIN_UST: + { + struct ltt_ust_session *usess = session->ust_session; + + ret = filter_ust_set(usess, domain, bytecode, event_name, channel_name); + if (ret != LTTCOMM_OK) { + goto error; + } + break; + } +#if 0 + case LTTNG_DOMAIN_UST_EXEC_NAME: + case LTTNG_DOMAIN_UST_PID: + case LTTNG_DOMAIN_UST_PID_FOLLOW_CHILDREN: +#endif + default: + ret = LTTCOMM_UND; + goto error; + } + + ret = LTTCOMM_OK; + +error: + return ret; + +} + /* * Command LTTNG_ENABLE_EVENT processed by the client thread. */ @@ -3928,8 +3969,11 @@ error: * is set and ready for transmission before returning. * * Return any error encountered or 0 for success. + * + * "sock" is only used for special-case var. len data. */ -static int process_client_msg(struct command_ctx *cmd_ctx) +static int process_client_msg(struct command_ctx *cmd_ctx, int sock, + int *sock_error) { int ret = LTTCOMM_OK; int need_tracing_session = 1; @@ -3937,6 +3981,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx) DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); + *sock_error = 0; + switch (cmd_ctx->lsm->cmd_type) { case LTTNG_CREATE_SESSION: case LTTNG_CREATE_SESSION_URI: @@ -4447,6 +4493,43 @@ skip_domain: cmd_ctx->lsm->u.reg.path); break; } + case LTTNG_SET_FILTER: + { + struct lttng_filter_bytecode *bytecode; + + if (cmd_ctx->lsm->u.filter.bytecode_len > 65336) { + ret = LTTCOMM_FILTER_INVAL; + goto error; + } + bytecode = zmalloc(cmd_ctx->lsm->u.filter.bytecode_len); + if (!bytecode) { + ret = LTTCOMM_FILTER_NOMEM; + goto error; + } + /* Receive var. len. data */ + DBG("Receiving var len data from client ..."); + ret = lttcomm_recv_unix_sock(sock, bytecode, + cmd_ctx->lsm->u.filter.bytecode_len); + if (ret <= 0) { + DBG("Nothing recv() from client var len data... continuing"); + *sock_error = 1; + ret = LTTCOMM_FILTER_INVAL; + goto error; + } + + if (bytecode->len + sizeof(*bytecode) + != cmd_ctx->lsm->u.filter.bytecode_len) { + free(bytecode); + ret = LTTCOMM_FILTER_INVAL; + goto error; + } + + ret = cmd_set_filter(cmd_ctx->session, cmd_ctx->lsm->domain.type, + cmd_ctx->lsm->u.filter.channel_name, + cmd_ctx->lsm->u.filter.event_name, + bytecode); + break; + } default: ret = LTTCOMM_UND; break; @@ -4479,6 +4562,7 @@ init_setup_error: static void *thread_manage_clients(void *data) { int sock = -1, ret, i, pollfd; + int sock_error; uint32_t revents, nb_fd; struct command_ctx *cmd_ctx = NULL; struct lttng_poll_event events; @@ -4611,13 +4695,22 @@ static void *thread_manage_clients(void *data) * informations for the client. The command context struct contains * everything this function may needs. */ - ret = process_client_msg(cmd_ctx); + ret = process_client_msg(cmd_ctx, sock, &sock_error); rcu_thread_offline(); if (ret < 0) { + if (sock_error) { + ret = close(sock); + if (ret) { + PERROR("close"); + } + sock = -1; + } /* * TODO: Inform client somehow of the fatal error. At * this point, ret < 0 means that a zmalloc failed - * (ENOMEM). Error detected but still accept command. + * (ENOMEM). Error detected but still accept + * command, unless a socket error has been + * detected. */ clean_command_ctx(&cmd_ctx); continue; diff --git a/src/bin/lttng-sessiond/trace-ust.c b/src/bin/lttng-sessiond/trace-ust.c index cd1660d59..4001ec87b 100644 --- a/src/bin/lttng-sessiond/trace-ust.c +++ b/src/bin/lttng-sessiond/trace-ust.c @@ -410,7 +410,7 @@ void trace_ust_destroy_event(struct ltt_ust_event *event) { DBG2("Trace destroy UST event %s", event->attr.name); destroy_contexts(event->ctx); - + free(event->filter); free(event); } diff --git a/src/bin/lttng-sessiond/trace-ust.h b/src/bin/lttng-sessiond/trace-ust.h index f8bcb3356..845bcd6c9 100644 --- a/src/bin/lttng-sessiond/trace-ust.h +++ b/src/bin/lttng-sessiond/trace-ust.h @@ -46,6 +46,7 @@ struct ltt_ust_event { struct lttng_ust_event attr; struct lttng_ht *ctx; struct lttng_ht_node_str node; + struct lttng_ust_filter_bytecode *filter; }; /* UST stream */ diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index c8c653134..6fb328eb9 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -32,6 +32,7 @@ #include "ust-consumer.h" #include "ust-ctl.h" #include "fd-limit.h" +#include "../../common/sessiond-comm/sessiond-comm.h" /* * Delete ust context safely. RCU read lock must be held before calling @@ -65,6 +66,7 @@ void delete_ust_app_event(int sock, struct ust_app_event *ua_event) assert(!ret); delete_ust_app_ctx(sock, ua_ctx); } + free(ua_event->filter); lttng_ht_destroy(ua_event->ctx); if (ua_event->obj != NULL) { @@ -430,6 +432,31 @@ error: return ret; } +/* + * Set the filter on the tracer. + */ +static +int set_ust_event_filter(struct ust_app_event *ua_event, + struct ust_app *app) +{ + int ret; + + if (!ua_event->filter) { + return 0; + } + + ret = ustctl_set_filter(app->sock, ua_event->filter, + ua_event->obj); + if (ret < 0) { + goto error; + } + + DBG2("UST filter set successfully for event %s", ua_event->name); + +error: + return ret; +} + /* * Disable the specified event on to UST tracer for the UST session. */ @@ -705,6 +732,16 @@ static void shadow_copy_event(struct ust_app_event *ua_event, /* Copy event attributes */ memcpy(&ua_event->attr, &uevent->attr, sizeof(ua_event->attr)); + /* Copy filter bytecode */ + if (uevent->filter) { + ua_event->filter = zmalloc(sizeof(*ua_event->filter) + + uevent->filter->len); + if (!ua_event->filter) { + return; + } + memcpy(ua_event->filter, uevent->filter, + sizeof(*ua_event->filter) + uevent->filter->len); + } cds_lfht_for_each_entry(uevent->ctx->ht, &iter.iter, uctx, node.node) { ua_ctx = alloc_ust_app_ctx(&uctx->ctx); if (ua_ctx == NULL) { @@ -997,6 +1034,35 @@ error: return ret; } +/* + * Set UST filter for the event on the tracer. + */ +static +int set_ust_app_event_filter(struct ust_app_session *ua_sess, + struct ust_app_event *ua_event, + struct lttng_filter_bytecode *bytecode, + struct ust_app *app) +{ + int ret = 0; + + DBG2("UST app adding context to event %s", ua_event->name); + + /* Copy filter bytecode */ + ua_event->filter = zmalloc(sizeof(*ua_event->filter) + bytecode->len); + if (!ua_event->filter) { + return -ENOMEM; + } + memcpy(ua_event->filter, bytecode, + sizeof(*ua_event->filter) + bytecode->len); + ret = set_ust_event_filter(ua_event, app); + if (ret < 0) { + goto error; + } + +error: + return ret; +} + /* * Enable on the tracer side a ust app event for the session and channel. */ @@ -2419,6 +2485,11 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock) continue; } } + ret = set_ust_event_filter(ua_event, app); + if (ret < 0) { + /* FIXME: Should we quit here or continue... */ + continue; + } } } @@ -2540,6 +2611,63 @@ int ust_app_add_ctx_event_glb(struct ltt_ust_session *usess, return ret; } +/* + * Add context to a specific event in a channel for global UST domain. + */ +int ust_app_set_filter_event_glb(struct ltt_ust_session *usess, + struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent, + struct lttng_filter_bytecode *bytecode) +{ + int ret = 0; + struct lttng_ht_node_str *ua_chan_node, *ua_event_node; + struct lttng_ht_iter iter, uiter; + struct ust_app_session *ua_sess; + struct ust_app_event *ua_event; + struct ust_app_channel *ua_chan = NULL; + struct ust_app *app; + + rcu_read_lock(); + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + if (!app->compatible) { + /* + * TODO: In time, we should notice the caller of this error by + * telling him that this is a version error. + */ + continue; + } + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + continue; + } + + /* Lookup channel in the ust app session */ + lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &uiter); + ua_chan_node = lttng_ht_iter_get_node_str(&uiter); + if (ua_chan_node == NULL) { + continue; + } + ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, + node); + + lttng_ht_lookup(ua_chan->events, (void *)uevent->attr.name, &uiter); + ua_event_node = lttng_ht_iter_get_node_str(&uiter); + if (ua_event_node == NULL) { + continue; + } + ua_event = caa_container_of(ua_event_node, struct ust_app_event, + node); + + ret = set_ust_app_event_filter(ua_sess, ua_event, bytecode, app); + if (ret < 0) { + continue; + } + } + + rcu_read_unlock(); + return ret; +} + /* * Enable event for a channel from a UST session for a specific PID. */ diff --git a/src/bin/lttng-sessiond/ust-app.h b/src/bin/lttng-sessiond/ust-app.h index 29eaea7ec..77205692f 100644 --- a/src/bin/lttng-sessiond/ust-app.h +++ b/src/bin/lttng-sessiond/ust-app.h @@ -28,6 +28,9 @@ #define UST_APP_EVENT_LIST_SIZE 32 +struct lttng_filter_bytecode; +struct lttng_ust_filter_bytecode; + extern int ust_consumerd64_fd, ust_consumerd32_fd; /* @@ -71,6 +74,7 @@ struct ust_app_event { char name[LTTNG_UST_SYM_NAME_LEN]; struct lttng_ht *ctx; struct lttng_ht_node_str node; + struct lttng_ust_filter_bytecode *filter; }; struct ust_app_channel { @@ -168,6 +172,9 @@ int ust_app_add_ctx_event_glb(struct ltt_ust_session *usess, struct ltt_ust_context *uctx); int ust_app_add_ctx_channel_glb(struct ltt_ust_session *usess, struct ltt_ust_channel *uchan, struct ltt_ust_context *uctx); +int ust_app_set_filter_event_glb(struct ltt_ust_session *usess, + struct ltt_ust_channel *uchan, struct ltt_ust_event *uevent, + struct lttng_filter_bytecode *bytecode); void ust_app_global_update(struct ltt_ust_session *usess, int sock); void ust_app_clean_list(void); diff --git a/src/bin/lttng/commands/enable_events.c b/src/bin/lttng/commands/enable_events.c index 5dda8bf8c..3f304a090 100644 --- a/src/bin/lttng/commands/enable_events.c +++ b/src/bin/lttng/commands/enable_events.c @@ -41,6 +41,7 @@ static char *opt_probe; static char *opt_function; static char *opt_function_entry_symbol; static char *opt_channel_name; +static char *opt_filter; #if 0 /* Not implemented yet */ static char *opt_cmd_name; @@ -58,6 +59,7 @@ enum { OPT_LOGLEVEL, OPT_LOGLEVEL_ONLY, OPT_LIST_OPTIONS, + OPT_FILTER, }; static struct lttng_handle *handle; @@ -90,6 +92,7 @@ static struct poptOption long_options[] = { {"loglevel", 0, POPT_ARG_STRING, 0, OPT_LOGLEVEL, 0, 0}, {"loglevel-only", 0, POPT_ARG_STRING, 0, OPT_LOGLEVEL_ONLY, 0, 0}, {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, + {"filter", 'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; @@ -162,6 +165,9 @@ static void usage(FILE *ofp) fprintf(ofp, " TRACE_DEBUG_LINE = 13\n"); fprintf(ofp, " TRACE_DEBUG = 14\n"); fprintf(ofp, " (shortcuts such as \"system\" are allowed)\n"); + fprintf(ofp, " --filter \'expression\'\n"); + fprintf(ofp, " Filter expression on event fields,\n"); + fprintf(ofp, " event recording depends on evaluation.\n"); fprintf(ofp, "\n"); } @@ -294,6 +300,14 @@ static int enable_events(char *session_name) memset(&ev, 0, sizeof(ev)); memset(&dom, 0, sizeof(dom)); + if (opt_kernel) { + if (opt_filter) { + ERR("Filter not implement for kernel tracing yet"); + ret = CMD_ERROR; + goto error; + } + } + /* Create lttng domain */ if (opt_kernel) { dom.type = LTTNG_DOMAIN_KERNEL; @@ -358,6 +372,15 @@ static int enable_events(char *session_name) } goto end; } + if (opt_filter) { + ret = lttng_set_event_filter(handle, ev.name, channel_name, + opt_filter); + if (ret < 0) { + ERR("Error setting filter"); + ret = -1; + goto error; + } + } switch (opt_event_type) { case LTTNG_EVENT_TRACEPOINT: @@ -519,6 +542,15 @@ static int enable_events(char *session_name) MSG("%s event %s created in channel %s", opt_kernel ? "kernel": "UST", event_name, channel_name); } + if (opt_filter) { + ret = lttng_set_event_filter(handle, ev.name, + channel_name, opt_filter); + if (ret < 0) { + ERR("Error setting filter"); + ret = -1; + goto error; + } + } /* Next event */ event_name = strtok(NULL, ","); @@ -586,6 +618,8 @@ int cmd_enable_events(int argc, const char **argv) case OPT_LIST_OPTIONS: list_cmd_options(stdout, long_options); goto end; + case OPT_FILTER: + break; default: usage(stderr); ret = CMD_UNDEFINED; diff --git a/src/common/sessiond-comm/sessiond-comm.c b/src/common/sessiond-comm/sessiond-comm.c index 6cbd014b8..432cf4cff 100644 --- a/src/common/sessiond-comm/sessiond-comm.c +++ b/src/common/sessiond-comm/sessiond-comm.c @@ -143,6 +143,9 @@ static const char *lttcomm_readable_code[] = { [ LTTCOMM_ERR_INDEX(LTTCOMM_ENABLE_CONSUMER_FAIL) ] = "Enabling consumer failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_RELAYD_SESSION_FAIL) ] = "Unable to create session on lttng-relayd", [ LTTCOMM_ERR_INDEX(LTTCOMM_RELAYD_VERSION_FAIL) ] = "Relay daemon not compatible", + [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_INVAL) ] = "Invalid filter bytecode", + [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_NOMEM) ] = "Not enough memory for filter bytecode", + [ LTTCOMM_ERR_INDEX(LTTCOMM_FILTER_EXIST) ] = "Filter already exist", }; /* diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index 580beec32..f48ba2218 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -72,6 +72,7 @@ enum lttcomm_sessiond_command { LTTNG_START_TRACE, LTTNG_STOP_TRACE, LTTNG_LIST_TRACEPOINT_FIELDS, + /* Consumer */ LTTNG_DISABLE_CONSUMER, LTTNG_ENABLE_CONSUMER, @@ -83,6 +84,9 @@ enum lttcomm_sessiond_command { RELAYD_UPDATE_SYNC_INFO, RELAYD_VERSION, RELAYD_SEND_METADATA, + + /* Other tracer commands */ + LTTNG_SET_FILTER, }; /* @@ -186,6 +190,9 @@ enum lttcomm_return_code { LTTCOMM_ENABLE_CONSUMER_FAIL, /* Enabling consumer failed */ LTTCOMM_RELAYD_SESSION_FAIL, /* lttng-relayd create session failed */ LTTCOMM_RELAYD_VERSION_FAIL, /* lttng-relayd not compatible */ + LTTCOMM_FILTER_INVAL, /* Invalid filter bytecode */ + LTTCOMM_FILTER_NOMEM, /* Lack of memory for filter bytecode */ + LTTCOMM_FILTER_EXIST, /* Filter already exist */ /* MUST be last element */ LTTCOMM_NR, /* Last element */ @@ -280,9 +287,28 @@ struct lttcomm_session_msg { struct lttng_uri ctrl_uri; struct lttng_uri data_uri; } create_uri; + struct { + char channel_name[NAME_MAX]; + char event_name[NAME_MAX]; + /* Length of following bytecode */ + uint32_t bytecode_len; + } filter; } u; }; +#define LTTNG_FILTER_MAX_LEN 65336 + +/* + * Filter bytecode data. The reloc table is located at the end of the + * bytecode. It is made of tuples: (uint16_t, var. len. string). It + * starts at reloc_table_offset. + */ +struct lttng_filter_bytecode { + uint16_t len; /* len of data */ + uint16_t reloc_table_offset; + char data[0]; +}; + /* * Data structure for the response from sessiond to the lttng client. */ diff --git a/src/lib/lttng-ctl/Makefile.am b/src/lib/lttng-ctl/Makefile.am index 4f61d5b01..bb5561e79 100644 --- a/src/lib/lttng-ctl/Makefile.am +++ b/src/lib/lttng-ctl/Makefile.am @@ -15,7 +15,8 @@ liblttng_ctl_la_SOURCES = lttng-ctl.c \ align.h \ filter-ast.h \ filter-bytecode.h \ - filter-ir.h + filter-ir.h \ + memstream.h filter_grammar_test_SOURCES = filter-grammar-test.c filter_grammar_test_LDADD = liblttng-ctl.la diff --git a/src/lib/lttng-ctl/filter-ast.h b/src/lib/lttng-ctl/filter-ast.h index 816562e23..97a3ae410 100644 --- a/src/lib/lttng-ctl/filter-ast.h +++ b/src/lib/lttng-ctl/filter-ast.h @@ -152,15 +152,14 @@ struct filter_ast { const char *node_type(struct filter_node *node); struct ir_op; -struct filter_bytecode; struct filter_parser_ctx { yyscan_t scanner; struct filter_ast *ast; struct cds_list_head allocated_strings; struct ir_op *ir_root; - struct filter_bytecode_alloc *bytecode; - struct filter_bytecode_alloc *bytecode_reloc; + struct lttng_filter_bytecode_alloc *bytecode; + struct lttng_filter_bytecode_alloc *bytecode_reloc; }; struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input); diff --git a/src/lib/lttng-ctl/filter-bytecode.h b/src/lib/lttng-ctl/filter-bytecode.h index fc2d6c8d4..af0733076 100644 --- a/src/lib/lttng-ctl/filter-bytecode.h +++ b/src/lib/lttng-ctl/filter-bytecode.h @@ -23,6 +23,7 @@ */ #include "filter-ast.h" +#include "../../common/sessiond-comm/sessiond-comm.h" /* * offsets are absolute from start of bytecode. @@ -123,24 +124,13 @@ struct return_op { filter_opcode_t op; } __attribute__((packed)); -/* - * The reloc table is located at the end of the bytecode. It is made of - * tuples: (uint16_t, var. len. string). It starts at - * reloc_table_offset. - */ -struct filter_bytecode { - uint16_t len; - uint16_t reloc_table_offset; - char data[0]; -}; - -struct filter_bytecode_alloc { +struct lttng_filter_bytecode_alloc { uint16_t alloc_len; - struct filter_bytecode b; + struct lttng_filter_bytecode b; }; static inline -unsigned int bytecode_get_len(struct filter_bytecode *bytecode) +unsigned int bytecode_get_len(struct lttng_filter_bytecode *bytecode) { return bytecode->len; } diff --git a/src/lib/lttng-ctl/filter-visitor-generate-bytecode.c b/src/lib/lttng-ctl/filter-visitor-generate-bytecode.c index e940e2c81..25128b6a2 100644 --- a/src/lib/lttng-ctl/filter-visitor-generate-bytecode.c +++ b/src/lib/lttng-ctl/filter-visitor-generate-bytecode.c @@ -39,9 +39,9 @@ int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx, struct ir_op *node); static -int bytecode_init(struct filter_bytecode_alloc **fb) +int bytecode_init(struct lttng_filter_bytecode_alloc **fb) { - *fb = calloc(sizeof(struct filter_bytecode_alloc) + INIT_ALLOC_SIZE, 1); + *fb = calloc(sizeof(struct lttng_filter_bytecode_alloc) + INIT_ALLOC_SIZE, 1); if (!*fb) { return -ENOMEM; } else { @@ -51,7 +51,7 @@ int bytecode_init(struct filter_bytecode_alloc **fb) } static -int32_t bytecode_reserve(struct filter_bytecode_alloc **fb, uint32_t align, uint32_t len) +int32_t bytecode_reserve(struct lttng_filter_bytecode_alloc **fb, uint32_t align, uint32_t len) { int32_t ret; uint32_t padding = offset_align((*fb)->b.len, align); @@ -64,7 +64,7 @@ int32_t bytecode_reserve(struct filter_bytecode_alloc **fb, uint32_t align, uint if (new_len > 0xFFFF) return -EINVAL; - *fb = realloc(*fb, sizeof(struct filter_bytecode_alloc) + new_len); + *fb = realloc(*fb, sizeof(struct lttng_filter_bytecode_alloc) + new_len); if (!*fb) return -ENOMEM; memset(&(*fb)->b.data[old_len], 0, new_len - old_len); @@ -77,7 +77,7 @@ int32_t bytecode_reserve(struct filter_bytecode_alloc **fb, uint32_t align, uint } static -int bytecode_push(struct filter_bytecode_alloc **fb, const void *data, +int bytecode_push(struct lttng_filter_bytecode_alloc **fb, const void *data, uint32_t align, uint32_t len) { int32_t offset; @@ -90,7 +90,7 @@ int bytecode_push(struct filter_bytecode_alloc **fb, const void *data, } static -int bytecode_push_logical(struct filter_bytecode_alloc **fb, +int bytecode_push_logical(struct lttng_filter_bytecode_alloc **fb, struct logical_op *data, uint32_t align, uint32_t len, uint16_t *skip_offset) @@ -108,7 +108,7 @@ int bytecode_push_logical(struct filter_bytecode_alloc **fb, } static -int bytecode_patch(struct filter_bytecode_alloc **fb, +int bytecode_patch(struct lttng_filter_bytecode_alloc **fb, const void *data, uint16_t offset, uint32_t len) diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index a05a8049e..780b44dd7 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -32,6 +32,26 @@ #include #include +#include "filter-parser.h" +#include "filter-ast.h" +#include "filter-bytecode.h" +#include "memstream.h" + +#ifdef DEBUG +const int print_xml = 1; +#define dbg_printf(fmt, args...) \ + printf("[debug liblttng-ctl] " fmt, ## args) +#else +const int print_xml = 0; +#define dbg_printf(fmt, args...) \ +do { \ + /* do nothing but check printf format */ \ + if (0) \ + printf("[debug liblttnctl] " fmt, ## args); \ +} while (0) +#endif + + /* Socket to session daemon for communication */ static int sessiond_socket; static char sessiond_sock_path[PATH_MAX]; @@ -114,6 +134,31 @@ end: return ret; } +/* + * Send var len data to the session daemon. + * + * On success, returns the number of bytes sent (>=0) + * On error, returns -1 + */ +static int send_session_varlen(void *data, size_t len) +{ + int ret; + + if (!connected) { + ret = -ENOTCONN; + goto end; + } + if (!data || !len) { + ret = 0; + goto end; + } + + ret = lttcomm_send_unix_sock(sessiond_socket, data, len); + +end: + return ret; +} + /* * Receive data from the sessiond socket. * @@ -311,10 +356,14 @@ static int disconnect_sessiond(void) /* * Ask the session daemon a specific command and put the data into buf. + * Takes extra var. len. data as input to send to the session daemon. * * Return size of data (only payload, not header) or a negative error code. */ -static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf) +static int ask_sessiond_varlen(struct lttcomm_session_msg *lsm, + void *vardata, + size_t varlen, + void **buf) { int ret; size_t size; @@ -331,6 +380,11 @@ static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf) if (ret < 0) { goto end; } + /* Send var len data */ + ret = send_session_varlen(vardata, varlen); + if (ret < 0) { + goto end; + } /* Get header from data transmission */ ret = recv_data_sessiond(&llm, sizeof(llm)); @@ -381,6 +435,16 @@ end: return ret; } +/* + * Ask the session daemon a specific command and put the data into buf. + * + * Return size of data (only payload, not header) or a negative error code. + */ +static int ask_sessiond(struct lttcomm_session_msg *lsm, void **buf) +{ + return ask_sessiond_varlen(lsm, NULL, 0, buf); +} + /* * Create lttng handle and return pointer. * The returned pointer will be NULL in case of malloc() error. @@ -555,6 +619,139 @@ int lttng_enable_event(struct lttng_handle *handle, return ask_sessiond(&lsm, NULL); } +/* + * set filter for an event + * Return negative error value on error. + * Return size of returned session payload data if OK. + */ + +int lttng_set_event_filter(struct lttng_handle *handle, + const char *event_name, const char *channel_name, + const char *filter_expression) +{ + struct lttcomm_session_msg lsm; + struct filter_parser_ctx *ctx; + FILE *fmem; + int ret = 0; + + /* Safety check. */ + if (handle == NULL) { + return -1; + } + + if (!filter_expression) { + return 0; + } + + /* + * casting const to non-const, as the underlying function will + * use it in read-only mode. + */ + fmem = lttng_fmemopen((void *) filter_expression, + strlen(filter_expression), "r"); + if (!fmem) { + fprintf(stderr, "Error opening memory as stream\n"); + return -ENOMEM; + } + ctx = filter_parser_ctx_alloc(fmem); + if (!ctx) { + fprintf(stderr, "Error allocating parser\n"); + ret = -ENOMEM; + goto alloc_error; + } + ret = filter_parser_ctx_append_ast(ctx); + if (ret) { + fprintf(stderr, "Parse error\n"); + ret = -EINVAL; + goto parse_error; + } + ret = filter_visitor_set_parent(ctx); + if (ret) { + fprintf(stderr, "Set parent error\n"); + ret = -EINVAL; + goto parse_error; + } + if (print_xml) { + ret = filter_visitor_print_xml(ctx, stdout, 0); + if (ret) { + fflush(stdout); + fprintf(stderr, "XML print error\n"); + ret = -EINVAL; + goto parse_error; + } + } + + dbg_printf("Generating IR... "); + fflush(stdout); + ret = filter_visitor_ir_generate(ctx); + if (ret) { + fprintf(stderr, "Generate IR error\n"); + ret = -EINVAL; + goto parse_error; + } + dbg_printf("done\n"); + + dbg_printf("Validating IR... "); + fflush(stdout); + ret = filter_visitor_ir_check_binary_op_nesting(ctx); + if (ret) { + ret = -EINVAL; + goto parse_error; + } + dbg_printf("done\n"); + + dbg_printf("Generating bytecode... "); + fflush(stdout); + ret = filter_visitor_bytecode_generate(ctx); + if (ret) { + fprintf(stderr, "Generate bytecode error\n"); + ret = -EINVAL; + goto parse_error; + } + dbg_printf("done\n"); + dbg_printf("Size of bytecode generated: %u bytes.\n", + bytecode_get_len(&ctx->bytecode->b)); + + memset(&lsm, 0, sizeof(lsm)); + + lsm.cmd_type = LTTNG_SET_FILTER; + + /* Copy channel name */ + copy_string(lsm.u.filter.channel_name, channel_name, + sizeof(lsm.u.filter.channel_name)); + /* Copy event name */ + copy_string(lsm.u.filter.event_name, event_name, + sizeof(lsm.u.filter.event_name)); + lsm.u.filter.bytecode_len = sizeof(ctx->bytecode->b) + + bytecode_get_len(&ctx->bytecode->b); + + copy_lttng_domain(&lsm.domain, &handle->domain); + + copy_string(lsm.session.name, handle->session_name, + sizeof(lsm.session.name)); + + ret = ask_sessiond_varlen(&lsm, &ctx->bytecode->b, + lsm.u.filter.bytecode_len, NULL); + + filter_bytecode_free(ctx); + filter_ir_free(ctx); + filter_parser_ctx_free(ctx); + if (fclose(fmem) != 0) { + perror("fclose"); + } + return ret; + +parse_error: + filter_bytecode_free(ctx); + filter_ir_free(ctx); + filter_parser_ctx_free(ctx); +alloc_error: + if (fclose(fmem) != 0) { + perror("fclose"); + } + return ret; +} + /* * Disable event(s) of a channel and domain. * If no event name is specified, all events are disabled. diff --git a/src/lib/lttng-ctl/memstream.h b/src/lib/lttng-ctl/memstream.h new file mode 100644 index 000000000..2cbb03559 --- /dev/null +++ b/src/lib/lttng-ctl/memstream.h @@ -0,0 +1,228 @@ +#ifndef _LTTNG_CTL_MEMSTREAM_H +#define _LTTNG_CTL_MEMSTREAM_H + +/* + * src/lib/lttng-ctl/memstream.h + * + * Copyright 2012 (c) - Mathieu Desnoyers + * + * memstream compatibility layer. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ + +#define _GNU_SOURCE +#include + +#ifdef LTTNG_HAVE_FMEMOPEN +#include + +static inline +FILE *lttng_fmemopen(void *buf, size_t size, const char *mode) +{ + return fmemopen(buf, size, mode); +} + +#else /* LTTNG_HAVE_FMEMOPEN */ + +#include +#include + +/* + * Fallback for systems which don't have fmemopen. Copy buffer to a + * temporary file, and use that file as FILE * input. + */ +static inline +FILE *lttng_fmemopen(void *buf, size_t size, const char *mode) +{ + char tmpname[PATH_MAX]; + size_t len; + FILE *fp; + int ret; + + /* + * Support reading only. + */ + if (strcmp(mode, "rb") != 0) { + return NULL; + } + strncpy(tmpname, "/tmp/lttng-tmp-XXXXXX", PATH_MAX); + ret = mkstemp(tmpname); + if (ret < 0) { + return NULL; + } + /* + * We need to write to the file. + */ + fp = fdopen(ret, "w+"); + if (!fp) { + goto error_unlink; + } + /* Copy the entire buffer to the file */ + len = fwrite(buf, sizeof(char), size, fp); + if (len != size) { + goto error_close; + } + ret = fseek(fp, 0L, SEEK_SET); + if (ret < 0) { + perror("fseek"); + goto error_close; + } + /* We keep the handle open, but can unlink the file on the VFS. */ + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return fp; + +error_close: + ret = fclose(fp); + if (ret < 0) { + perror("close"); + } +error_unlink: + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return NULL; +} + +#endif /* LTTNG_HAVE_FMEMOPEN */ + +#ifdef LTTNG_HAVE_OPEN_MEMSTREAM + +#include + +static inline +FILE *lttng_open_memstream(char **ptr, size_t *sizeloc) +{ + return open_memstream(ptr, sizeloc); +} + +static inline +int lttng_close_memstream(char **buf, size_t *size, FILE *fp) +{ + return fclose(fp); +} + +#else /* LTTNG_HAVE_OPEN_MEMSTREAM */ + +#include +#include + +/* + * Fallback for systems which don't have open_memstream. Create FILE * + * with lttng_open_memstream, but require call to + * lttng_close_memstream to flush all data written to the FILE * + * into the buffer (which we allocate). + */ +static inline +FILE *lttng_open_memstream(char **ptr, size_t *sizeloc) +{ + char tmpname[PATH_MAX]; + int ret; + FILE *fp; + + strncpy(tmpname, "/tmp/lttng-tmp-XXXXXX", PATH_MAX); + ret = mkstemp(tmpname); + if (ret < 0) { + return NULL; + } + fp = fdopen(ret, "w+"); + if (!fp) { + goto error_unlink; + } + /* + * lttng_flush_memstream will update the buffer content + * with read from fp. No need to keep the file around, just the + * handle. + */ + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return fp; + +error_unlink: + ret = unlink(tmpname); + if (ret < 0) { + perror("unlink"); + } + return NULL; +} + +/* Get file size, allocate buffer, copy. */ +static inline +int lttng_close_memstream(char **buf, size_t *size, FILE *fp) +{ + size_t len, n; + long pos; + int ret; + + ret = fflush(fp); + if (ret < 0) { + perror("fflush"); + return ret; + } + ret = fseek(fp, 0L, SEEK_END); + if (ret < 0) { + perror("fseek"); + return ret; + } + pos = ftell(fp); + if (ret < 0) { + perror("ftell"); + return ret; + } + *size = pos; + /* add final \0 */ + *buf = calloc(pos + 1, sizeof(char)); + if (!*buf) { + return -ENOMEM; + } + ret = fseek(fp, 0L, SEEK_SET); + if (ret < 0) { + perror("fseek"); + goto error_free; + } + /* Copy the entire file into the buffer */ + n = 0; + clearerr(fp); + while (!feof(fp) && !ferror(fp) && (*size - n > 0)) { + len = fread(*buf, sizeof(char), *size - n, fp); + n += len; + } + if (n != *size) { + ret = -1; + goto error_close; + } + ret = fclose(fp); + if (ret < 0) { + perror("fclose"); + return ret; + } + return 0; + +error_close: + ret = fclose(fp); + if (ret < 0) { + perror("fclose"); + } +error_free: + free(*buf); + *buf = NULL; + return ret; +} + +#endif /* LTTNG_HAVE_OPEN_MEMSTREAM */ + +#endif /* _LTTNG_CTL_MEMSTREAM_H */ diff --git a/tests/kernel/Makefile.am b/tests/kernel/Makefile.am index 79434cad5..2992afbf5 100644 --- a/tests/kernel/Makefile.am +++ b/tests/kernel/Makefile.am @@ -6,12 +6,17 @@ EXTRA_DIST = runall.sh run-kernel-tests.sh noinst_PROGRAMS = kernel_all_events_basic kernel_event_basic UTILS=../utils.h -LIBLTTNG=$(top_srcdir)/src/lib/lttng-ctl/lttng-ctl.c \ - $(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \ +LIBLTTNG=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la + +SESSIONDSRC=$(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \ $(top_srcdir)/src/common/sessiond-comm/unix.c \ $(top_srcdir)/src/common/sessiond-comm/inet.c \ $(top_srcdir)/src/common/sessiond-comm/inet6.c -kernel_all_events_basic_SOURCES = kernel_all_events_basic.c $(UTILS) $(LIBLTTNG) +kernel_all_events_basic_SOURCES = kernel_all_events_basic.c $(UTILS) \ + $(SESSIONDSRC) +kernel_all_events_basic_LDADD = $(LIBLTTNG) -kernel_event_basic_SOURCES = kernel_event_basic.c $(UTILS) $(LIBLTTNG) +kernel_event_basic_SOURCES = kernel_event_basic.c $(UTILS) \ + $(SESSIONDSRC) +kernel_event_basic_LDADD = $(LIBLTTNG) diff --git a/tests/ust/Makefile.am b/tests/ust/Makefile.am index 1275b9804..146bff250 100644 --- a/tests/ust/Makefile.am +++ b/tests/ust/Makefile.am @@ -9,13 +9,19 @@ EXTRA_DIST = runall.sh run-ust-global-tests.sh noinst_PROGRAMS = ust_global_event_basic ust_global_event_wildcard UTILS=../utils.h -LIBLTTNG=$(top_srcdir)/src/lib/lttng-ctl/lttng-ctl.c \ - $(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \ +LIBLTTNG=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la + +SESSIONDSRC=$(top_srcdir)/src/common/sessiond-comm/sessiond-comm.c \ $(top_srcdir)/src/common/sessiond-comm/unix.c \ $(top_srcdir)/src/common/sessiond-comm/inet.c \ $(top_srcdir)/src/common/sessiond-comm/inet6.c -ust_global_event_wildcard_SOURCES = ust_global_event_wildcard.c $(UTILS) $(LIBLTTNG) +ust_global_event_wildcard_SOURCES = ust_global_event_wildcard.c $(UTILS) \ + $(SESSIONDSRC) +ust_global_event_wildcard_LDADD = $(LIBLTTNG) + +ust_global_event_basic_SOURCES = ust_global_event_basic.c $(UTILS) \ + $(SESSIONDSRC) +ust_global_event_basic_LDADD = $(LIBLTTNG) -ust_global_event_basic_SOURCES = ust_global_event_basic.c $(UTILS) $(LIBLTTNG) endif