Fix: missing dereference when computing extended info position
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 800859b8e55437919af0eba63d3278652eba1bed..f35043fa46d52a8d6709ece90028c67b72fdb1b9 100644 (file)
@@ -139,13 +139,97 @@ error:
        return ret;
 }
 
+/*
+ * Get run-time attributes if the session has been started (discarded events,
+ * lost packets).
+ */
+static int get_kernel_runtime_stats(struct ltt_session *session,
+               struct ltt_kernel_channel *kchan, uint64_t *discarded_events,
+               uint64_t *lost_packets)
+{
+       int ret;
+
+       if (!session->has_been_started) {
+               ret = 0;
+               *discarded_events = 0;
+               *lost_packets = 0;
+               goto end;
+       }
+
+       ret = consumer_get_discarded_events(session->id, kchan->fd,
+                       session->kernel_session->consumer,
+                       discarded_events);
+       if (ret < 0) {
+               goto end;
+       }
+
+       ret = consumer_get_lost_packets(session->id, kchan->fd,
+                       session->kernel_session->consumer,
+                       lost_packets);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Get run-time attributes if the session has been started (discarded events,
+ * lost packets).
+ */
+static int get_ust_runtime_stats(struct ltt_session *session,
+               struct ltt_ust_channel *uchan, uint64_t *discarded_events,
+               uint64_t *lost_packets)
+{
+       int ret;
+       struct ltt_ust_session *usess;
+
+       usess = session->ust_session;
+
+       if (!usess || !session->has_been_started) {
+               *discarded_events = 0;
+               *lost_packets = 0;
+               ret = 0;
+               goto end;
+       }
+
+       if (usess->buffer_type == LTTNG_BUFFER_PER_UID) {
+               ret = ust_app_uid_get_channel_runtime_stats(usess->id,
+                               &usess->buffer_reg_uid_list,
+                               usess->consumer, uchan->id,
+                               uchan->attr.overwrite,
+                               discarded_events,
+                               lost_packets);
+       } else if (usess->buffer_type == LTTNG_BUFFER_PER_PID) {
+               ret = ust_app_pid_get_channel_runtime_stats(usess,
+                               uchan, usess->consumer,
+                               uchan->attr.overwrite,
+                               discarded_events,
+                               lost_packets);
+               if (ret < 0) {
+                       goto end;
+               }
+               *discarded_events += uchan->per_pid_closed_app_discarded;
+               *lost_packets += uchan->per_pid_closed_app_lost;
+       } else {
+               ERR("Unsupported buffer type");
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
 /*
  * Fill lttng_channel array of all channels.
  */
 static void list_lttng_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel *channels)
+               struct ltt_session *session, struct lttng_channel *channels,
+               struct lttcomm_channel_extended *chan_exts)
 {
-       int i = 0;
+       int i = 0, ret;
        struct ltt_kernel_channel *kchan;
 
        DBG("Listing channels for session %s", session->name);
@@ -156,9 +240,19 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                if (session->kernel_session != NULL) {
                        cds_list_for_each_entry(kchan,
                                        &session->kernel_session->channel_list.head, list) {
+                               uint64_t discarded_events, lost_packets;
+
+                               ret = get_kernel_runtime_stats(session, kchan,
+                                               &discarded_events, &lost_packets);
+                               if (ret < 0) {
+                                       goto end;
+                               }
                                /* Copy lttng_channel struct to array */
                                memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel));
                                channels[i].enabled = kchan->enabled;
+                               chan_exts[i].discarded_events =
+                                               discarded_events;
+                               chan_exts[i].lost_packets = lost_packets;
                                i++;
                        }
                }
@@ -171,6 +265,8 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                rcu_read_lock();
                cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
                                &iter.iter, uchan, node.node) {
+                       uint64_t discarded_events, lost_packets;
+
                        strncpy(channels[i].name, uchan->name, LTTNG_SYMBOL_NAME_LEN);
                        channels[i].attr.overwrite = uchan->attr.overwrite;
                        channels[i].attr.subbuf_size = uchan->attr.subbuf_size;
@@ -182,12 +278,30 @@ static void list_lttng_channels(enum lttng_domain_type domain,
                        channels[i].enabled = uchan->enabled;
                        channels[i].attr.tracefile_size = uchan->tracefile_size;
                        channels[i].attr.tracefile_count = uchan->tracefile_count;
+
+                       /*
+                        * Map enum lttng_ust_output to enum lttng_event_output.
+                        */
                        switch (uchan->attr.output) {
                        case LTTNG_UST_MMAP:
-                       default:
                                channels[i].attr.output = LTTNG_EVENT_MMAP;
                                break;
+                       default:
+                               /*
+                                * LTTNG_UST_MMAP is the only supported UST
+                                * output mode.
+                                */
+                               assert(0);
+                               break;
+                       }
+
+                       ret = get_ust_runtime_stats(session, uchan,
+                                       &discarded_events, &lost_packets);
+                       if (ret < 0) {
+                               break;
                        }
+                       chan_exts[i].discarded_events = discarded_events;
+                       chan_exts[i].lost_packets = lost_packets;
                        i++;
                }
                rcu_read_unlock();
@@ -196,33 +310,61 @@ static void list_lttng_channels(enum lttng_domain_type domain,
        default:
                break;
        }
+
+end:
+       return;
 }
 
 static void increment_extended_len(const char *filter_expression,
-               size_t *extended_len)
+               struct lttng_event_exclusion *exclusion, size_t *extended_len)
 {
        *extended_len += sizeof(struct lttcomm_event_extended_header);
 
        if (filter_expression) {
                *extended_len += strlen(filter_expression) + 1;
        }
+
+       if (exclusion) {
+               *extended_len += exclusion->count * LTTNG_SYMBOL_NAME_LEN;
+       }
 }
 
 static void append_extended_info(const char *filter_expression,
-               void **extended_at)
+               struct lttng_event_exclusion *exclusion, void **extended_at)
 {
        struct lttcomm_event_extended_header extended_header;
        size_t filter_len = 0;
+       size_t nb_exclusions = 0;
 
        if (filter_expression) {
                filter_len = strlen(filter_expression) + 1;
        }
 
+       if (exclusion) {
+               nb_exclusions = exclusion->count;
+       }
+
+       /* Set header fields */
        extended_header.filter_len = filter_len;
+       extended_header.nb_exclusions = nb_exclusions;
+
+       /* Copy header */
        memcpy(*extended_at, &extended_header, sizeof(extended_header));
        *extended_at += sizeof(extended_header);
-       memcpy(*extended_at, filter_expression, filter_len);
-       *extended_at += filter_len;
+
+       /* Copy filter string */
+       if (filter_expression) {
+               memcpy(*extended_at, filter_expression, filter_len);
+               *extended_at += filter_len;
+       }
+
+       /* Copy exclusion names */
+       if (exclusion) {
+               size_t len = nb_exclusions * LTTNG_SYMBOL_NAME_LEN;
+
+               memcpy(*extended_at, &exclusion->names, len);
+               *extended_at += len;
+       }
 }
 
 /*
@@ -264,7 +406,8 @@ static int list_lttng_agent_events(struct agent *agt,
         */
        rcu_read_lock();
        cds_lfht_for_each_entry(agt->events->ht, &iter.iter, event, node.node) {
-               increment_extended_len(event->filter_expression, &extended_len);
+               increment_extended_len(event->filter_expression, NULL,
+                               &extended_len);
        }
        rcu_read_unlock();
 
@@ -289,7 +432,8 @@ static int list_lttng_agent_events(struct agent *agt,
                i++;
 
                /* Append extended info */
-               append_extended_info(event->filter_expression, &extended_at);
+               append_extended_info(event->filter_expression, NULL,
+                               &extended_at);
        }
        rcu_read_unlock();
 
@@ -348,7 +492,7 @@ static int list_lttng_ust_global_events(char *channel_name,
                }
 
                increment_extended_len(uevent->filter_expression,
-                       &extended_len);
+                       uevent->exclusion, &extended_len);
        }
        if (nb_event == 0) {
                /* All events are internal, skip. */
@@ -360,8 +504,8 @@ static int list_lttng_ust_global_events(char *channel_name,
        *total_size = nb_event * sizeof(struct lttng_event) + extended_len;
        tmp = zmalloc(*total_size);
        if (tmp == NULL) {
-               ret = LTTNG_ERR_FATAL;
-               goto error;
+               ret = -LTTNG_ERR_FATAL;
+               goto end;
        }
 
        extended_at = ((uint8_t *) tmp) + nb_event * sizeof(struct lttng_event);
@@ -408,7 +552,8 @@ static int list_lttng_ust_global_events(char *channel_name,
                i++;
 
                /* Append extended info */
-               append_extended_info(uevent->filter_expression, &extended_at);
+               append_extended_info(uevent->filter_expression,
+                       uevent->exclusion, &extended_at);
        }
 
        ret = nb_event;
@@ -445,12 +590,13 @@ static int list_lttng_kernel_events(char *channel_name,
        if (nb_event == 0) {
                *total_size = 0;
                *events = NULL;
-               goto syscall;
+               goto end;
        }
 
        /* Compute required extended infos size */
        cds_list_for_each_entry(event, &kchan->events_list.head, list) {
-               increment_extended_len(event->filter_expression, &extended_len);
+               increment_extended_len(event->filter_expression, NULL,
+                       &extended_len);
        }
 
        *total_size = nb_event * sizeof(struct lttng_event) + extended_len;
@@ -460,7 +606,7 @@ static int list_lttng_kernel_events(char *channel_name,
                goto error;
        }
 
-       extended_at = ((uint8_t *) events) +
+       extended_at = ((void *) *events) +
                nb_event * sizeof(struct lttng_event);
 
        /* Kernel channels */
@@ -503,22 +649,11 @@ static int list_lttng_kernel_events(char *channel_name,
                i++;
 
                /* Append extended info */
-               append_extended_info(event->filter_expression, &extended_at);
-       }
-
-syscall:
-       if (syscall_table) {
-               ssize_t new_size;
-
-               new_size = syscall_list_channel(kchan, events, nb_event);
-               if (new_size < 0) {
-                       free(events);
-                       ret = -new_size;
-                       goto error;
-               }
-               nb_event = new_size;
+               append_extended_info(event->filter_expression, NULL,
+                       &extended_at);
        }
 
+end:
        return nb_event;
 
 error:
@@ -2809,8 +2944,7 @@ error:
 ssize_t cmd_list_channels(enum lttng_domain_type domain,
                struct ltt_session *session, struct lttng_channel **channels)
 {
-       int ret;
-       ssize_t nb_chan = 0;
+       ssize_t nb_chan = 0, payload_size = 0, ret;
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
@@ -2819,7 +2953,8 @@ ssize_t cmd_list_channels(enum lttng_domain_type domain,
                }
                DBG3("Number of kernel channels %zd", nb_chan);
                if (nb_chan <= 0) {
-                       ret = LTTNG_ERR_KERN_CHAN_NOT_FOUND;
+                       ret = -LTTNG_ERR_KERN_CHAN_NOT_FOUND;
+                       goto end;
                }
                break;
        case LTTNG_DOMAIN_UST:
@@ -2831,30 +2966,37 @@ ssize_t cmd_list_channels(enum lttng_domain_type domain,
                }
                DBG3("Number of UST global channels %zd", nb_chan);
                if (nb_chan < 0) {
-                       ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
-                       goto error;
+                       ret = -LTTNG_ERR_UST_CHAN_NOT_FOUND;
+                       goto end;
                }
                break;
        default:
-               ret = LTTNG_ERR_UND;
-               goto error;
+               ret = -LTTNG_ERR_UND;
+               goto end;
        }
 
        if (nb_chan > 0) {
-               *channels = zmalloc(nb_chan * sizeof(struct lttng_channel));
+               const size_t channel_size = sizeof(struct lttng_channel) +
+                       sizeof(struct lttcomm_channel_extended);
+               struct lttcomm_channel_extended *channel_exts;
+
+               payload_size = nb_chan * channel_size;
+               *channels = zmalloc(payload_size);
                if (*channels == NULL) {
-                       ret = LTTNG_ERR_FATAL;
-                       goto error;
+                       ret = -LTTNG_ERR_FATAL;
+                       goto end;
                }
 
-               list_lttng_channels(domain, session, *channels);
+               channel_exts = ((void *) *channels) +
+                               (nb_chan * sizeof(struct lttng_channel));
+               list_lttng_channels(domain, session, *channels, channel_exts);
+       } else {
+               *channels = NULL;
        }
 
-       return nb_chan;
-
-error:
-       /* Return negative value to differentiate return code */
-       return -ret;
+       ret = payload_size;
+end:
+       return ret;
 }
 
 /*
This page took 0.029106 seconds and 4 git commands to generate.