Port: handle 'size_t' / 'off_t' on Solaris
[babeltrace.git] / plugins / ctf / common / notif-iter / notif-iter.c
index e6b85753b48e7d1c56cba8cd4c4009013de7d656..33ac24953ea56d89b0cd7f45c0e3f96677dd5b41 100644 (file)
@@ -211,6 +211,9 @@ struct bt_ctf_notif_iter {
 
                /* Current position from addr (bits) */
                size_t at;
+
+               /* Position of the last event header from addr (bits) */
+               size_t last_eh_at;
        } buf;
 
        /* Binary type reader */
@@ -477,6 +480,7 @@ enum bt_ctf_notif_iter_status request_medium_bytes(
 
                /* Restart at the beginning of the new medium buffer */
                notit->buf.at = 0;
+               notit->buf.last_eh_at = -1ULL;
 
                /* New medium buffer size */
                notit->buf.sz = buffer_sz;
@@ -490,6 +494,101 @@ enum bt_ctf_notif_iter_status request_medium_bytes(
                        notit->buf.sz, notit->buf.addr);
                BT_LOGV_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:",
                        buffer_addr);
+       } else if (m_status == BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF) {
+               struct bt_ctf_field_type *eh_ft = NULL;
+               struct bt_ctf_field_type *sec_ft = NULL;
+               struct bt_ctf_field_type *ec_ft = NULL;
+
+               /*
+                * User returned end of stream: validate that we're not
+                * in the middle of a packet header, packet context, or
+                * event.
+                */
+               if (notit->state == STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN) {
+                       /* Beginning of packet: always valid */
+                       goto good_state;
+               }
+
+               if (!notit->meta.stream_class) {
+                       goto bad_state;
+               }
+
+               eh_ft = bt_ctf_stream_class_get_event_header_type(
+                       notit->meta.stream_class);
+               sec_ft = bt_ctf_stream_class_get_event_context_type(
+                       notit->meta.stream_class);
+
+               if (notit->state == STATE_DSCOPE_STREAM_EVENT_HEADER_BEGIN) {
+                       /*
+                        * Beginning of event's header is only valid if
+                        * the packet is not supposed to have a specific
+                        * size (whole packet sequence has in fact only
+                        * one packet).
+                        */
+                       if (notit->cur_packet_size == -1) {
+                               goto good_state;
+                       }
+               }
+
+               if (notit->state == STATE_DSCOPE_STREAM_EVENT_CONTEXT_BEGIN) {
+                       /*
+                        * Beginning of event's stream event context is
+                        * only valid if the packet is not supposed to
+                        * have a specific size (whole packet sequence
+                        * has in fact only one packet), and there's no
+                        * event header.
+                        */
+                       if (notit->cur_packet_size == -1 && !eh_ft) {
+                               goto good_state;
+                       }
+               }
+
+               if (!notit->meta.event_class) {
+                       goto bad_state;
+               }
+
+               ec_ft = bt_ctf_event_class_get_context_type(
+                       notit->meta.event_class);
+
+               if (notit->state == STATE_DSCOPE_EVENT_CONTEXT_BEGIN) {
+                       /*
+                        * Beginning of event's context is only valid if
+                        * the packet is not supposed to have a specific
+                        * size (whole packet sequence has in fact only
+                        * one packet), and there's no event header and
+                        * no stream event context.
+                        */
+                       if (notit->cur_packet_size == -1 && !eh_ft && !sec_ft) {
+                               goto good_state;
+                       }
+               }
+
+               if (notit->state == STATE_DSCOPE_EVENT_PAYLOAD_BEGIN) {
+                       /*
+                        * Beginning of event's context is only valid if
+                        * the packet is not supposed to have a specific
+                        * size (whole packet sequence has in fact only
+                        * one packet), and there's no event header, no
+                        * stream event context, and no event context.
+                        */
+                       if (notit->cur_packet_size == -1 && !eh_ft && !sec_ft &&
+                                       !ec_ft) {
+                               goto good_state;
+                       }
+               }
+
+bad_state:
+               /* All other states are invalid */
+               BT_LOGW("User function returned %s, but notification iterator is in an unexpected state: "
+                       "state=%s",
+                       bt_ctf_notif_iter_medium_status_string(m_status),
+                       state_string(notit->state));
+               m_status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR;
+
+good_state:
+               bt_put(eh_ft);
+               bt_put(sec_ft);
+               bt_put(ec_ft);
        } else if (m_status < 0) {
                BT_LOGW("User function failed: status=%s",
                        bt_ctf_notif_iter_medium_status_string(m_status));
@@ -1157,6 +1256,9 @@ enum bt_ctf_notif_iter_status read_event_header_begin_state(
        enum bt_ctf_notif_iter_status status = BT_CTF_NOTIF_ITER_STATUS_OK;
        struct bt_ctf_field_type *event_header_type = NULL;
 
+       /* Reset the position of the last event header */
+       notit->buf.last_eh_at = notit->buf.at;
+
        /* Check if we have some content left */
        if (notit->cur_content_size >= 0) {
                if (packet_at(notit) == notit->cur_content_size) {
@@ -1168,7 +1270,7 @@ enum bt_ctf_notif_iter_status read_event_header_begin_state(
                } else if (packet_at(notit) > notit->cur_content_size) {
                        /* That's not supposed to happen */
                        BT_LOGV("Before decoding event header field: cursor is passed the packet's content: "
-                               "notit-addr=%p, content-size=%zu, "
+                               "notit-addr=%p, content-size=%" PRId64 ", "
                                "cur=%zu", notit, notit->cur_content_size,
                                packet_at(notit));
                        status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
@@ -1687,6 +1789,7 @@ void bt_ctf_notif_iter_reset(struct bt_ctf_notif_iter *notit)
        notit->buf.addr = NULL;
        notit->buf.sz = 0;
        notit->buf.at = 0;
+       notit->buf.last_eh_at = -1ULL;
        notit->buf.packet_offset = 0;
        notit->state = STATE_INIT;
        notit->cur_content_size = -1;
@@ -2667,6 +2770,35 @@ end:
        return event;
 }
 
+static
+uint64_t get_cur_stream_instance_id(struct bt_ctf_notif_iter *notit)
+{
+       struct bt_ctf_field *stream_instance_id_field = NULL;
+       uint64_t stream_instance_id = -1ULL;
+       int ret;
+
+       if (!notit->dscopes.trace_packet_header) {
+               goto end;
+       }
+
+       stream_instance_id_field = bt_ctf_field_structure_get_field_by_name(
+               notit->dscopes.trace_packet_header, "stream_instance_id");
+       if (!stream_instance_id_field) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_unsigned_integer_get_value(stream_instance_id_field,
+               &stream_instance_id);
+       if (ret) {
+               stream_instance_id = -1ULL;
+               goto end;
+       }
+
+end:
+       bt_put(stream_instance_id_field);
+       return stream_instance_id;
+}
+
 static
 int set_stream(struct bt_ctf_notif_iter *notit)
 {
@@ -2680,7 +2812,8 @@ int set_stream(struct bt_ctf_notif_iter *notit)
                bt_ctf_stream_class_get_name(notit->meta.stream_class),
                bt_ctf_stream_class_get_id(notit->meta.stream_class));
        stream = bt_get(notit->medium.medops.get_stream(
-               notit->meta.stream_class, notit->medium.data));
+               notit->meta.stream_class, get_cur_stream_instance_id(notit),
+               notit->medium.data));
        BT_LOGV("User function returned: stream-addr=%p", stream);
        if (!stream) {
                BT_LOGW_STR("User function failed to return a stream object for the given stream class.");
@@ -2837,9 +2970,17 @@ void notify_event(struct bt_ctf_notif_iter *notit,
                struct bt_clock_class_priority_map *cc_prio_map,
                struct bt_notification **notification)
 {
-       struct bt_ctf_event *event;
+       struct bt_ctf_event *event = NULL;
        struct bt_notification *ret = NULL;
 
+       /* Make sure that the event contains at least one bit of data */
+       if (notit->buf.at == notit->buf.last_eh_at) {
+               BT_LOGE("Cannot create empty event with 0 bits of data: "
+                       "notit-addr=%p, packet-cur=%zu",
+                       notit, packet_at(notit));
+               goto end;
+       }
+
        /* Create event */
        event = create_event(notit);
        if (!event) {
This page took 0.025397 seconds and 4 git commands to generate.