+ size_t channel_count, i;
+ const size_t channel_size = sizeof(struct lttng_channel) +
+ sizeof(struct lttcomm_channel_extended);
+ struct lttcomm_session_msg lsm;
+ void *extended_at;
+
+ if (handle == NULL) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_CHANNELS;
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+
+ lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain);
+
+ ret = lttng_ctl_ask_sessiond(&lsm, (void**) channels);
+ if (ret < 0) {
+ goto end;
+ }
+
+ if (ret % channel_size) {
+ ret = -LTTNG_ERR_UNK;
+ free(*channels);
+ *channels = NULL;
+ goto end;
+ }
+ channel_count = (size_t) ret / channel_size;
+
+ /* Set extended info pointers */
+ extended_at = ((void *) *channels) +
+ channel_count * sizeof(struct lttng_channel);
+ for (i = 0; i < channel_count; i++) {
+ struct lttng_channel *chan = &(*channels)[i];
+
+ chan->attr.extended.ptr = extended_at;
+ extended_at += sizeof(struct lttcomm_channel_extended);
+ }
+
+ ret = (int) channel_count;
+end:
+ return ret;
+}
+
+/*
+ * Ask the session daemon for all available events of a session channel.
+ * Sets the contents of the events array.
+ * Returns the number of lttng_event entries in events;
+ * on error, returns a negative value.
+ */
+int lttng_list_events(struct lttng_handle *handle,
+ const char *channel_name, struct lttng_event **events)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ struct lttcomm_event_command_header *cmd_header = NULL;
+ size_t cmd_header_len;
+ uint32_t nb_events, i;
+ void *extended_at;
+
+ /* Safety check. An handle and channel name are mandatory */
+ if (handle == NULL || channel_name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_EVENTS;
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+ lttng_ctl_copy_string(lsm.u.list.channel_name, channel_name,
+ sizeof(lsm.u.list.channel_name));
+ lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain);
+
+ ret = lttng_ctl_ask_sessiond_varlen(&lsm, NULL, 0, (void **) events,
+ (void **) &cmd_header, &cmd_header_len);
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Set number of events and free command header */
+ nb_events = cmd_header->nb_events;
+ if (nb_events > INT_MAX) {
+ ret = -EOVERFLOW;
+ goto error;
+ }
+ ret = (int) nb_events;
+ free(cmd_header);
+ cmd_header = NULL;
+
+ /* Set extended info pointers */
+ extended_at = ((void*) (*events)) +
+ nb_events * sizeof(struct lttng_event);
+
+ for (i = 0; i < nb_events; i++) {
+ struct lttcomm_event_extended_header *ext_header;
+ struct lttng_event *event = &(*events)[i];
+
+ event->extended.ptr = extended_at;
+ ext_header =
+ (struct lttcomm_event_extended_header *) extended_at;
+ extended_at += sizeof(*ext_header);
+ extended_at += ext_header->filter_len;
+ extended_at +=
+ ext_header->nb_exclusions * LTTNG_SYMBOL_NAME_LEN;
+ }
+
+ return ret;
+error:
+ free(cmd_header);
+ free(*events);
+ return ret;
+}
+
+int lttng_event_get_filter_expression(struct lttng_event *event,
+ const char **filter_expression)
+{
+ int ret = 0;
+ struct lttcomm_event_extended_header *ext_header;
+
+ if (!event || !filter_expression) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ext_header = event->extended.ptr;
+
+ if (!ext_header) {
+ /*
+ * This can happen since the lttng_event structure is
+ * used for other tasks where this pointer is never set.
+ */
+ *filter_expression = NULL;
+ goto end;
+ }
+
+ if (ext_header->filter_len) {
+ *filter_expression = ((const char *) (ext_header)) +
+ sizeof(*ext_header);
+ } else {
+ *filter_expression = NULL;
+ }
+
+end:
+ return ret;
+}
+
+int lttng_event_get_exclusion_name_count(struct lttng_event *event)
+{
+ int ret;
+ struct lttcomm_event_extended_header *ext_header;