CTF writer: stream: handle automatic fields more securely
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 19 May 2017 23:56:09 +0000 (19:56 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:44 +0000 (12:57 -0400)
The stream.c code for automatically writing the values of selected
fields in the packet context, packet header, and event header fields is
not super secure, in that the user could make the stream object write an
invalid CTF data stream file.

The code is updated to follow those rules:

* Packet header field:
  * `magic` field: always force to 0xc1fc1fc1. Override any current
    value.
  * `uuid` field: always force to trace's UUID. Override any current
    value.
  * `stream_id`: always force to stream's class's ID. Override any
    current value.
* Packet context field:
  * `packet_size`: always force to the size of the packet being flushed.
    Override any current value.
  * `packet_size`: always force to the current packet's offset. Override
    any current value.
  * `timestamp_begin`: if the field's type is mapped to the stream's
    class's clock class, force to the timestamp of the stream's first
    recorded event (if any, and if this timestamp is itself mapped to
    the same clock class), overriding the user's value.
  * `timestamp_end`: if the field's type is mapped to the stream's
    class's clock class, force to the timestamp of the stream's last
    recorded event (if any, and if this timestamp is itself mapped to
    the same clock class), overriding the user's value.
  * `events_discarded`: always force to the stream's current discarded
    events count (now a dedicated member of the stream object to keep
    this value safe). Override any current value.
* Event header field:
  * `timestamp`: if the field's type is an integer field type which is
    mapped to the stream's class's clock class, force to the current
    value of the stream's class's clock, overriding the user's value.
  * `id`: if the field's type is an integer field type, force to the
    event's class's ID, overriding the user's value.
* If the stream's packet context does not exist or does not contain
  a `packet_size` field, the user can only flush the stream one time.
* If the stream's packet context does not exist or does not contain a
  `content_size` field, the content size (current offset) of the packet
  to flush must be equal to its packet size.

Those rules are more strict than before, but they ensure that the
written stream is valid. Writing an invalid CTF stream, or CTF trace at
all, is not a CTF writer use case. This is in line with the project's
first precept: don't trust the user.

I added assertions which check that the packet size is always a multiple
of 8: this is suggested by CTF 1, and required by (eventual) CTF 2. This
is always the case here because the packet's initial size is 8 pages and
then it's incremented by this value each time. If it is a requirement
that the user should be able to control the packet size, then we should
add a function to set the expected packet size before flushing the
stream, not rely on the `packet_size` field's value.

There are still a few cases which remain to be checked. For example, if
the stream class's event header field type's `id` field does not exist,
and there's more than one event class in the stream's class, we write
the event anyway without any warning: this is because LTTng is known to
have a complex system of `id` and `timestamp` fields with extended
structures depending on the ID value, and the ctf.fs sink component
class uses CTF writer as is. That said, in the most common scenarios,
`id` is an integer field type.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
include/babeltrace/ctf-ir/stream-internal.h
include/babeltrace/ctf-writer/serialize-internal.h
include/babeltrace/ctf-writer/stream.h
lib/ctf-ir/fields.c
lib/ctf-ir/stream.c
lib/ctf-writer/serialize.c

index a54cd57b49924b9c77eb54b3b0ff1df7d0652139..0b844b8a23015502896114926e57b7be3c4d36e2 100644 (file)
@@ -80,6 +80,7 @@ struct bt_ctf_stream {
        GPtrArray *events;
        struct bt_ctf_stream_pos pos;
        unsigned int flushed_packet_count;
+       uint64_t discarded_events;
        uint64_t size;
 
        /* Array of struct bt_ctf_stream_destroy_listener */
index 6471993c23a5c739c5e3e1b87c1446fb46c354d3..39cb791361aa47bd818ccf8ea6dbed78023d1b93 100644 (file)
@@ -48,7 +48,6 @@ struct bt_ctf_stream_pos {
        off_t mmap_offset;      /* mmap offset in the file, in bytes */
        off_t mmap_base_offset; /* offset of start of packet in mmap, in bytes */
        uint64_t packet_size;   /* current packet size, in bits */
-       uint64_t content_size;  /* current content size, in bits */
        int64_t offset;         /* offset from base, in bits. EOF for end of file. */
        struct mmap_align *base_mma;/* mmap base address */
 };
@@ -70,12 +69,13 @@ int bt_ctf_stream_pos_access_ok(struct bt_ctf_stream_pos *pos, uint64_t bit_len)
 
        if (unlikely(pos->offset == EOF))
                return 0;
+
        if (pos->prot == PROT_READ) {
                /*
                 * Reads may only reach up to the "content_size",
                 * regardless of the packet_size.
                 */
-               max_len = pos->content_size;
+               max_len = pos->offset;
        } else {
                /* Writes may take place up to the end of the packet. */
                max_len = pos->packet_size;
index 56b6bff8c29edb10bd5e1da77050d4345d6c506f..67422f677e22660109cd95bcd02d84f8528e0bef 100644 (file)
@@ -49,7 +49,7 @@ extern "C" {
  *
  * Returns the number of discarded events, a negative value on error.
  */
-extern int bt_ctf_stream_get_discarded_events_count(
+extern int64_t bt_ctf_stream_get_discarded_events_count(
                struct bt_ctf_stream *stream, uint64_t *count);
 
 /*
index 5929b834fd07c6c43420b2435d5a8fe84e449ace..6caf2e45658524d9bced4df764bae3577a5fcb22 100644 (file)
@@ -2582,25 +2582,33 @@ int bt_ctf_field_structure_serialize(struct bt_ctf_field *field,
        for (i = 0; i < structure->fields->len; i++) {
                struct bt_ctf_field *member = g_ptr_array_index(
                        structure->fields, i);
+               const char *field_name = NULL;
+
+               if (BT_LOG_ON_WARN) {
+                       ret = bt_ctf_field_type_structure_get_field(
+                               field->type, &field_name, NULL, i);
+                       assert(ret == 0);
+               }
 
                BT_LOGV("Serializing structure field's field: pos-offset=%" PRId64 ", "
                        "field-addr=%p, index=%" PRId64,
                        pos->offset, member, i);
+
+               if (!member) {
+                       BT_LOGW("Cannot serialize structure field's field: field is not set: "
+                               "struct-field-addr=%p, "
+                               "field-name=\"%s\", index=%" PRId64,
+                               field, field_name, i);
+                       ret = -1;
+                       goto end;
+               }
+
                ret = bt_ctf_field_serialize(member, pos, native_byte_order);
                if (ret) {
-                       int this_ret;
-                       const char *name;
-                       struct bt_ctf_field_type *structure_type =
-                                       bt_ctf_field_get_type(field);
-
-                       this_ret = bt_ctf_field_type_structure_get_field(
-                               structure_type, &name, NULL, i);
-                       assert(this_ret == 0);
                        BT_LOGW("Cannot serialize structure field's field: "
                                "struct-field-addr=%p, field-addr=%p, "
                                "field-name=\"%s\", index=%" PRId64,
-                               field, member, name, i);
-                       bt_put(structure_type);
+                               field->type, member, field_name, i);
                        break;
                }
        }
@@ -2717,7 +2725,7 @@ int bt_ctf_field_string_serialize(struct bt_ctf_field *field,
 
                ret = bt_ctf_field_unsigned_integer_set_value(character, chr);
                if (ret) {
-                       BT_LOGE("Cannot set character field's value: "
+                       BT_LOGW("Cannot set character field's value: "
                                "pos-offset=%" PRId64 ", field-addr=%p, "
                                "index=%" PRId64 ", char-int=%" PRIu64,
                                pos->offset, character, i, chr);
@@ -2731,7 +2739,7 @@ int bt_ctf_field_string_serialize(struct bt_ctf_field *field,
                ret = bt_ctf_field_integer_serialize(character, pos,
                        native_byte_order);
                if (ret) {
-                       BT_LOGE_STR("Cannot serialize character field.");
+                       BT_LOGW_STR("Cannot serialize character field.");
                        goto end;
                }
        }
@@ -3059,6 +3067,8 @@ int increase_packet_size(struct bt_ctf_stream_pos *pos)
        BT_LOGV("Increased packet size: pos-offset=%" PRId64 ", "
                "new-packet-size=%" PRIu64,
                pos->offset, pos->packet_size);
+       assert(pos->packet_size % 8 == 0);
+
 end:
        return ret;
 }
index a24e16ae343d04c0533330c50b4774b0f01ac629..402597edd3e1e1905e66c910ca8e1a87e76a934b 100644 (file)
@@ -53,8 +53,6 @@ static
 void bt_ctf_stream_destroy(struct bt_object *obj);
 static
 int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
-static
-int set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
 
 static
 int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
@@ -110,7 +108,6 @@ static
 int set_packet_header_magic(struct bt_ctf_stream *stream)
 {
        int ret = 0;
-       struct bt_ctf_field_type *magic_field_type = NULL;
        struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field(
                stream->packet_header, "magic");
        const uint32_t magic_value = 0xc1fc1fc1;
@@ -125,64 +122,22 @@ int set_packet_header_magic(struct bt_ctf_stream *stream)
                goto end;
        }
 
-       if (bt_ctf_field_is_set(magic_field)) {
-               /* Value already set. Not an error, skip. */
-               BT_LOGV("Packet header's `magic` field is already set: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"", stream,
-                       bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       magic_field_type = bt_ctf_field_get_type(magic_field);
-       assert(magic_field_type);
-
-       if (bt_ctf_field_type_get_type_id(magic_field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /* Magic field is not an integer. Not an error, skip. */
-               BT_LOGV("Packet header's `magic` field's type is not an integer field type: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-id=%s",
-                       stream, bt_ctf_stream_get_name(stream), magic_field,
-                       magic_field_type,
-                       bt_ctf_field_type_id_string(magic_field_type->id));
-               goto end;
-       }
-
-       if (bt_ctf_field_type_integer_get_size(magic_field_type) != 32) {
-               /*
-                * Magic field is not of the expected size.
-                * Not an error, skip.
-                */
-               BT_LOGV("Packet header's `magic` field's type is not 32-bit: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\", ft-addr=%p, size=%d",
-                       stream, bt_ctf_stream_get_name(stream), magic_field_type,
-                       bt_ctf_field_type_integer_get_size(magic_field_type));
-               goto end;
-       }
+       ret = bt_ctf_field_unsigned_integer_set_value(magic_field,
+               (uint64_t) magic_value);
 
-       ret = bt_ctf_field_type_integer_get_signed(magic_field_type);
-       assert(ret >= 0);
        if (ret) {
-               ret = bt_ctf_field_signed_integer_set_value(magic_field,
-                       (int64_t) magic_value);
-       } else {
-               ret = bt_ctf_field_unsigned_integer_set_value(magic_field,
-                       (uint64_t) magic_value);
-       }
-
-       if (ret) {
-               BT_LOGW("Cannot set `magic` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64,
+               BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
                        stream, bt_ctf_stream_get_name(stream),
                        magic_field, (uint64_t) magic_value);
        } else {
                BT_LOGV("Set packet header field's `magic` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64,
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
                        stream, bt_ctf_stream_get_name(stream),
                        magic_field, (uint64_t) magic_value);
        }
 end:
        bt_put(magic_field);
-       bt_put(magic_field_type);
        return ret;
 }
 
@@ -192,8 +147,6 @@ int set_packet_header_uuid(struct bt_ctf_stream *stream)
        int ret = 0;
        int64_t i;
        struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_field_type *uuid_field_type = NULL;
-       struct bt_ctf_field_type *element_field_type = NULL;
        struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field(
                stream->packet_header, "uuid");
 
@@ -207,75 +160,18 @@ int set_packet_header_uuid(struct bt_ctf_stream *stream)
                goto end;
        }
 
-       if (bt_ctf_field_is_set(uuid_field)) {
-               /* Value already set. Not an error, skip. */
-               BT_LOGV("Packet header's `uuid` field is already set: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       uuid_field_type = bt_ctf_field_get_type(uuid_field);
-       assert(uuid_field_type);
-       if (bt_ctf_field_type_get_type_id(uuid_field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_ARRAY) {
-               /* UUID field is not an array. Not an error, skip. */
-               BT_LOGV("Packet header's `uuid` field's type is not an array field type: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-id=%s",
-                       stream, bt_ctf_stream_get_name(stream), uuid_field,
-                       uuid_field_type,
-                       bt_ctf_field_type_id_string(uuid_field_type->id));
-               goto end;
-       }
-
-       if (bt_ctf_field_type_array_get_length(uuid_field_type) != 16) {
-               /*
-                * UUID field is not of the expected size.
-                * Not an error, skip.
-                */
-               BT_LOGV("Packet header's `uuid` array field's type's length is not 16: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-length=%u",
-                       stream, bt_ctf_stream_get_name(stream), uuid_field,
-                       uuid_field_type,
-                       (unsigned int) bt_ctf_field_type_array_get_length(uuid_field_type));
-               goto end;
-       }
-
-       element_field_type = bt_ctf_field_type_array_get_element_type(
-               uuid_field_type);
-       assert(element_field_type);
-       if (bt_ctf_field_type_get_type_id(element_field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /* UUID array elements are not integers. Not an error, skip */
-               BT_LOGV("Packet header's `uuid` array field's type's element field type is not an integer field type: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\", uuid-field-addr=%p, "
-                       "element-ft-addr=%p, element-ft-id=%s",
-                       stream, bt_ctf_stream_get_name(stream), uuid_field,
-                       element_field_type,
-                       bt_ctf_field_type_id_string(element_field_type->id));
-               goto end;
-       }
-
        trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
        for (i = 0; i < 16; i++) {
                struct bt_ctf_field *uuid_element =
                        bt_ctf_field_array_get_field(uuid_field, i);
 
-               ret = bt_ctf_field_type_integer_get_signed(element_field_type);
-               assert(ret >= 0);
-
-               if (ret) {
-                       ret = bt_ctf_field_signed_integer_set_value(
-                               uuid_element, (int64_t) trace->uuid[i]);
-               } else {
-                       ret = bt_ctf_field_unsigned_integer_set_value(
-                               uuid_element, (uint64_t) trace->uuid[i]);
-               }
+               ret = bt_ctf_field_unsigned_integer_set_value(
+                       uuid_element, (uint64_t) trace->uuid[i]);
                bt_put(uuid_element);
                if (ret) {
                        BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
                                "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
-                               "value-unsigned=%" PRIu64 ", index=%" PRId64,
+                               "value=%" PRIu64 ", index=%" PRId64,
                                stream, bt_ctf_stream_get_name(stream),
                                uuid_element, (uint64_t) trace->uuid[i], i);
                        goto end;
@@ -288,8 +184,6 @@ int set_packet_header_uuid(struct bt_ctf_stream *stream)
 
 end:
        bt_put(uuid_field);
-       bt_put(uuid_field_type);
-       bt_put(element_field_type);
        BT_PUT(trace);
        return ret;
 }
@@ -298,7 +192,6 @@ int set_packet_header_stream_id(struct bt_ctf_stream *stream)
 {
        int ret = 0;
        uint32_t stream_id;
-       struct bt_ctf_field_type *stream_id_field_type = NULL;
        struct bt_ctf_field *stream_id_field = bt_ctf_field_structure_get_field(
                stream->packet_header, "stream_id");
 
@@ -310,86 +203,409 @@ int set_packet_header_stream_id(struct bt_ctf_stream *stream)
                goto end;
        }
 
-       if (bt_ctf_field_is_set(stream_id_field)) {
-               /* Value already set. Not an error, skip. */
-               BT_LOGV("Packet header's `stream_id` field is already set: skipping: "
+       stream_id = stream->stream_class->id;
+       ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field,
+               (uint64_t) stream_id);
+       if (ret) {
+               BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       stream_id_field, (uint64_t) stream_id);
+       } else {
+               BT_LOGV("Set packet header field's `stream_id` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       stream_id_field, (uint64_t) stream_id);
+       }
+
+end:
+       bt_put(stream_id_field);
+       return ret;
+}
+
+static
+int auto_populate_packet_header(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+
+       if (!stream->packet_header) {
+               goto end;
+       }
+
+       ret = set_packet_header_magic(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's magic number field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_header_uuid(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's UUID field: "
                        "stream-addr=%p, stream-name=\"%s\"",
                        stream, bt_ctf_stream_get_name(stream));
                goto end;
        }
 
-       stream_id_field_type = bt_ctf_field_get_type(stream_id_field);
-       assert(stream_id_field_type);
-       if (bt_ctf_field_type_get_type_id(stream_id_field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /* stream_id field is not an integer. Not an error, skip. */
-               BT_LOGV("Packet header's `stream_id` field's type is not an integer field type: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, ft-addr=%p, ft-id=%s",
-                       stream, bt_ctf_stream_get_name(stream), stream_id_field,
-                       stream_id_field_type,
-                       bt_ctf_field_type_id_string(stream_id_field_type->id));
+       ret = set_packet_header_stream_id(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's stream class ID field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
                goto end;
        }
 
-       stream_id = stream->stream_class->id;
-       ret = bt_ctf_field_type_integer_get_signed(stream_id_field_type);
-       assert(ret >= 0);
+       BT_LOGV("Automatically populated stream's packet header's known fields: "
+               "stream-addr=%p, stream-name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_packet_size(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field(
+               stream->packet_context, "packet_size");
+
+       assert(stream);
+
+       if (!field) {
+               /* No packet size field found. Not an error, skip. */
+               BT_LOGV("No field named `packet_size` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_unsigned_integer_set_value(field,
+               stream->pos.packet_size);
+       if (ret) {
+               BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, stream->pos.packet_size);
+       } else {
+               BT_LOGV("Set packet context field's `packet_size` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, stream->pos.packet_size);
+       }
+
+end:
+       bt_put(field);
+       return ret;
+}
+
+static
+int set_packet_context_content_size(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field(
+               stream->packet_context, "content_size");
+
+       assert(stream);
+
+       if (!field) {
+               /* No content size field found. Not an error, skip. */
+               BT_LOGV("No field named `content_size` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_unsigned_integer_set_value(field,
+               stream->pos.offset);
        if (ret) {
-               ret = bt_ctf_field_signed_integer_set_value(stream_id_field,
-                       (int64_t) stream_id);
+               BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRId64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, stream->pos.offset);
        } else {
-               ret = bt_ctf_field_unsigned_integer_set_value(stream_id_field,
-                       (uint64_t) stream_id);
+               BT_LOGV("Set packet context field's `content_size` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRId64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, stream->pos.offset);
        }
 
+end:
+       bt_put(field);
+       return ret;
+}
+
+static
+int set_packet_context_events_discarded(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field(
+               stream->packet_context, "events_discarded");
+
+       assert(stream);
+
+       if (!field) {
+               /* No discarded events count field found. Not an error, skip. */
+               BT_LOGV("No field named `events_discarded` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_unsigned_integer_set_value(field,
+               stream->discarded_events);
        if (ret) {
-               BT_LOGW("Cannot set `stream_id` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64,
+               BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
                        stream, bt_ctf_stream_get_name(stream),
-                       stream_id_field, (uint64_t) stream_id);
+                       field, stream->discarded_events);
        } else {
-               BT_LOGV("Set packet header field's `stream_id` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value-unsigned=%" PRIu64,
+               BT_LOGV("Set packet context field's `events_discarded` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
                        stream, bt_ctf_stream_get_name(stream),
-                       stream_id_field, (uint64_t) stream_id);
+                       field, stream->discarded_events);
        }
 
 end:
-       bt_put(stream_id_field);
-       bt_put(stream_id_field_type);
+       bt_put(field);
        return ret;
 }
 
 static
-int set_packet_header(struct bt_ctf_stream *stream)
+int get_event_header_timestamp(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *event_header, uint64_t *timestamp)
 {
-       int ret;
+       int ret = 0;
+       struct bt_ctf_field *timestamp_field = NULL;
+       struct bt_ctf_clock_class *ts_field_mapped_clock_class = NULL;
 
-       ret = set_packet_header_magic(stream);
+       *timestamp = 0;
+
+       if (!event_header) {
+               BT_LOGV_STR("Event header does not exist.");
+               goto end;
+       }
+
+       timestamp_field = bt_ctf_field_structure_get_field(event_header,
+               "timestamp");
+       if (!timestamp_field) {
+               BT_LOGV("Cannot get event header's `timestamp` field: "
+                       "event-header-field-addr=%p", event_header);
+               goto end;
+       }
+
+       if (!bt_ctf_field_type_is_integer(timestamp_field->type)) {
+               BT_LOGV("Event header's `timestamp` field's type is not an integer field type: "
+                       "event-header-field-addr=%p", event_header);
+               goto end;
+       }
+
+       ts_field_mapped_clock_class =
+               bt_ctf_field_type_integer_get_mapped_clock_class(
+                       timestamp_field->type);
+       if (!ts_field_mapped_clock_class) {
+               BT_LOGV("Event header's `timestamp` field's type is not mapped to a clock class: "
+                       "event-header-field-addr=%p", event_header);
+               goto end;
+       }
+
+       if (ts_field_mapped_clock_class !=
+                       stream->stream_class->clock->clock_class) {
+               BT_LOGV("Event header's `timestamp` field's type is not mapped to the stream's clock's class: "
+                       "event-header-field-addr=%p", event_header);
+               goto end;
+       }
+
+       ret = bt_ctf_field_unsigned_integer_get_value(timestamp_field,
+               timestamp);
        if (ret) {
-               BT_LOGW("Cannot set packet header's magic number field: "
+               BT_LOGW("Cannot get unsigned integer field's value: "
+                       "event-header-field-addr=%p, "
+                       "timestamp-field-addr=%p",
+                       event_header, timestamp_field);
+               goto end;
+       }
+
+end:
+       bt_put(timestamp_field);
+       bt_put(ts_field_mapped_clock_class);
+       return ret;
+}
+
+static
+int set_packet_context_timestamp_field(struct bt_ctf_stream *stream,
+               const char *field_name, struct bt_ctf_event *event)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field(
+               stream->packet_context, field_name);
+       struct bt_ctf_clock_class *field_mapped_clock_class = NULL;
+       uint64_t ts;
+
+       assert(stream);
+
+       if (!field) {
+               /* No beginning timestamp field found. Not an error, skip. */
+               BT_LOGV("No field named `%s` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"", field_name,
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       if (!stream->stream_class->clock) {
+               BT_LOGV("Stream has no clock: skipping: "
                        "stream-addr=%p, stream-name=\"%s\"",
                        stream, bt_ctf_stream_get_name(stream));
                goto end;
        }
 
-       ret = set_packet_header_uuid(stream);
+       field_mapped_clock_class =
+               bt_ctf_field_type_integer_get_mapped_clock_class(field->type);
+       if (!field_mapped_clock_class) {
+               BT_LOGV("Packet context's `%s` field's type is not mapped to a clock class: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "field-addr=%p, ft-addr=%p", field_name,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, field->type);
+               goto end;
+       }
+
+       if (field_mapped_clock_class !=
+                       stream->stream_class->clock->clock_class) {
+               BT_LOGV("Packet context's `%s` field's type is not mapped to the stream's clock's class: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "field-addr=%p, ft-addr=%p, "
+                       "ft-mapped-clock-class-addr=%p, "
+                       "ft-mapped-clock-class-name=\"%s\", "
+                       "stream-clock-class-addr=%p, "
+                       "stream-clock-class-name=\"%s\"",
+                       field_name,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, field->type,
+                       field_mapped_clock_class,
+                       bt_ctf_clock_class_get_name(field_mapped_clock_class),
+                       stream->stream_class->clock->clock_class,
+                       bt_ctf_clock_class_get_name(
+                               stream->stream_class->clock->clock_class));
+               goto end;
+       }
+
+       if (get_event_header_timestamp(stream, event->event_header, &ts)) {
+               BT_LOGW("Cannot get event's timestamp: "
+                       "event-header-field-addr=%p",
+                       event->event_header);
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_unsigned_integer_set_value(field, ts);
        if (ret) {
-               BT_LOGW("Cannot set packet header's UUID field: "
+               BT_LOGW("Cannot set packet context field's `%s` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       field_name, stream, bt_ctf_stream_get_name(stream),
+                       field, stream->discarded_events);
+       } else {
+               BT_LOGV("Set packet context field's `%s` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       field_name, stream, bt_ctf_stream_get_name(stream),
+                       field, stream->discarded_events);
+       }
+
+end:
+       bt_put(field);
+       bt_put(field_mapped_clock_class);
+       return ret;
+}
+
+static
+int set_packet_context_timestamp_begin(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+
+       if (stream->events->len == 0) {
+               BT_LOGV("Current packet contains no events: skipping: "
                        "stream-addr=%p, stream-name=\"%s\"",
                        stream, bt_ctf_stream_get_name(stream));
                goto end;
        }
 
-       ret = set_packet_header_stream_id(stream);
+       ret = set_packet_context_timestamp_field(stream, "timestamp_begin",
+               g_ptr_array_index(stream->events, 0));
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_timestamp_end(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+
+       if (stream->events->len == 0) {
+               BT_LOGV("Current packet contains no events: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_context_timestamp_field(stream, "timestamp_end",
+               g_ptr_array_index(stream->events, stream->events->len - 1));
+
+end:
+       return ret;
+}
+
+static
+int auto_populate_packet_context(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+
+       if (!stream->packet_context) {
+               goto end;
+       }
+
+       ret = set_packet_context_packet_size(stream);
        if (ret) {
-               BT_LOGW("Cannot set packet header's stream class ID field: "
+               BT_LOGW("Cannot set packet context's packet size field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_context_content_size(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's content size field: "
                        "stream-addr=%p, stream-name=\"%s\"",
                        stream, bt_ctf_stream_get_name(stream));
                goto end;
        }
 
-       BT_LOGV("Set packet header's known fields's values: "
+       ret = set_packet_context_timestamp_begin(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's beginning timestamp field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_context_timestamp_end(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's end timestamp field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_context_events_discarded(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's discarded events count field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       BT_LOGV("Automatically populated stream's packet context's known fields: "
                "stream-addr=%p, stream-name=\"%s\"",
                stream, bt_ctf_stream_get_name(stream));
 
@@ -447,9 +663,10 @@ int create_stream_file(struct bt_ctf_writer *writer,
                O_RDWR | O_CREAT | O_TRUNC,
                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
        if (fd < 0) {
-               BT_LOGW("Failed to open stream file for writing: "
-                       "writer-trace-dir-fd=%d, filename=\"%s\"",
-                       writer->trace_dir_fd, filename->str);
+               BT_LOGW("Failed to open stream file for writing: %s: "
+                       "writer-trace-dir-fd=%d, filename=\"%s\", "
+                       "ret=%d, errno=%d", strerror(errno),
+                       writer->trace_dir_fd, filename->str, fd, errno);
                goto end;
        }
 
@@ -501,7 +718,8 @@ struct bt_ctf_stream *bt_ctf_stream_create(
        trace = bt_ctf_stream_class_get_trace(stream_class);
        if (!trace) {
                BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
-                       "stream-class-name=\"%s\", stream-class-name=\"%s\"",
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-name=\"%s\"",
                        stream_class, bt_ctf_stream_class_get_name(stream_class),
                        name);
                goto error;
@@ -514,10 +732,10 @@ struct bt_ctf_stream *bt_ctf_stream_create(
                 * no more can be added, and each object is also frozen.
                 */
                BT_LOGW("Invalid parameter: cannot create stream from a stream class which is part of a static trace: "
-                       "stream-class-name=\"%s\", stream-class-name=\"%s\", "
-                       "trace-addr=%p",
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-name=\"%s\", trace-addr=%p",
                        stream_class, bt_ctf_stream_class_get_name(stream_class),
-                       name, trace);;
+                       name, trace);
                goto error;
        }
 
@@ -561,8 +779,8 @@ struct bt_ctf_stream *bt_ctf_stream_create(
 
                BT_LOGD("Stream object belongs to a writer's trace: "
                        "writer-addr=%p", writer);
-
                assert(writer);
+
                if (stream_class->packet_context_type) {
                        BT_LOGD("Creating stream's packet context field: "
                                "ft-addr=%p", stream_class->packet_context_type);
@@ -591,15 +809,15 @@ struct bt_ctf_stream *bt_ctf_stream_create(
                        goto error;
                }
 
-               /* A trace is not allowed to have a NULL packet header */
-               assert(trace->packet_header_type);
-               BT_LOGD("Creating stream's packet header field: "
-                       "ft-addr=%p", trace->packet_header_type);
-               stream->packet_header =
-                       bt_ctf_field_create(trace->packet_header_type);
-               if (!stream->packet_header) {
-                       BT_LOGW_STR("Cannot create stream's packet header field.");
-                       goto error;
+               if (trace->packet_header_type) {
+                       BT_LOGD("Creating stream's packet header field: "
+                               "ft-addr=%p", trace->packet_header_type);
+                       stream->packet_header =
+                               bt_ctf_field_create(trace->packet_header_type);
+                       if (!stream->packet_header) {
+                               BT_LOGW_STR("Cannot create stream's packet header field.");
+                               goto error;
+                       }
                }
 
                /*
@@ -610,9 +828,9 @@ struct bt_ctf_stream *bt_ctf_stream_create(
                 * make sure to set the trace packet header fields himself
                 * before flushing.
                 */
-               ret = set_packet_header(stream);
+               ret = auto_populate_packet_header(stream);
                if (ret) {
-                       BT_LOGW_STR("Cannot populate the stream's packet header.");
+                       BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
                        goto error;
                }
 
@@ -669,99 +887,65 @@ end:
        return stream_class;
 }
 
-int bt_ctf_stream_get_discarded_events_count(
+int64_t bt_ctf_stream_get_discarded_events_count(
                struct bt_ctf_stream *stream, uint64_t *count)
 {
        int64_t ret = 0;
-       int field_signed;
-       struct bt_ctf_field *events_discarded_field = NULL;
-       struct bt_ctf_field_type *events_discarded_field_type = NULL;
 
        if (!stream) {
                BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
+               ret = (int64_t) -1;
                goto end;
        }
 
        if (!count) {
                BT_LOGW_STR("Invalid parameter: count is NULL.");
-               ret = -1;
+               ret = (int64_t) -1;
                goto end;
        }
 
-       if (!stream->packet_context) {
-               /* Not an error */
-               BT_LOGV("Stream has no packet context field: "
+       if (stream->pos.fd < 0) {
+               BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
                        "stream-addr=%p, stream-name=\"%s\"",
                        stream, bt_ctf_stream_get_name(stream));
-               ret = -1;
+               ret = (int64_t) -1;
                goto end;
        }
 
-       if (stream->pos.fd < 0) {
-               BT_LOGW("Invalid parameter: stream is not a CTF writer stream: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               ret = -1;
+       *count = (uint64_t) stream->discarded_events;
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream,
+       uint64_t count)
+{
+       int ret = 0;
+       struct bt_ctf_field *events_discarded_field = NULL;
+
+       if (!stream->packet_context) {
                goto end;
        }
 
        events_discarded_field = bt_ctf_field_structure_get_field(
                stream->packet_context, "events_discarded");
        if (!events_discarded_field) {
-               BT_LOGW("Cannot get packet context's `events_discarded` field: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "packet-context-field-addr=%p",
-                       stream, bt_ctf_stream_get_name(stream),
-                       stream->packet_context);
-               ret = -1;
                goto end;
        }
 
-       events_discarded_field_type = bt_ctf_field_get_type(
-               events_discarded_field);
-       assert(events_discarded_field_type);
-       field_signed = bt_ctf_field_type_integer_get_signed(
-               events_discarded_field_type);
-       assert(field_signed >= 0);
-
-       if (field_signed) {
-               int64_t signed_count;
-
-               ret = bt_ctf_field_signed_integer_get_value(
-                       events_discarded_field, &signed_count);
-               if (ret) {
-                       BT_LOGW("Cannot get packet context's `events_discarded` field value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
-                               stream, bt_ctf_stream_get_name(stream),
-                               events_discarded_field);
-                       goto end;
-               }
-               if (signed_count < 0) {
-                       /* Invalid value */
-                       BT_LOGW("Invalid value for packet context's `events_discarded` field: must be zero or positive: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
-                               "value=%" PRId64, stream,
-                               bt_ctf_stream_get_name(stream),
-                               events_discarded_field, signed_count);
-                       ret = -1;
-                       goto end;
-               }
-               *count = (uint64_t) signed_count;
-       } else {
-               ret = bt_ctf_field_unsigned_integer_get_value(
+       ret = bt_ctf_field_unsigned_integer_set_value(
+               events_discarded_field, count);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's `events_discarded` field: "
+                       "field-addr=%p, value=%" PRIu64,
                        events_discarded_field, count);
-               if (ret) {
-                       BT_LOGW("Cannot get packet context's `events_discarded` field value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
-                               stream, bt_ctf_stream_get_name(stream),
-                               events_discarded_field);
-                       goto end;
-               }
+               goto end;
        }
+
 end:
        bt_put(events_discarded_field);
-       bt_put(events_discarded_field_type);
        return ret;
 }
 
@@ -769,11 +953,8 @@ void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
                uint64_t event_count)
 {
        int ret;
-       int field_signed;
-       uint64_t previous_count;
        uint64_t new_count;
        struct bt_ctf_field *events_discarded_field = NULL;
-       struct bt_ctf_field_type *events_discarded_field_type = NULL;
 
        if (!stream) {
                BT_LOGW_STR("Invalid parameter: stream is NULL.");
@@ -794,56 +975,34 @@ void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
                goto end;
        }
 
-       ret = bt_ctf_stream_get_discarded_events_count(stream,
-               &previous_count);
-       if (ret) {
-               BT_LOGW_STR("Cannot get stream's number of discarded events.");
-               goto end;
-       }
-
        events_discarded_field = bt_ctf_field_structure_get_field(
                stream->packet_context, "events_discarded");
        if (!events_discarded_field) {
-               BT_LOGW_STR("No field named `events_discarded` in packet context.");
+               BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
                goto end;
        }
 
-       events_discarded_field_type = bt_ctf_field_get_type(
-               events_discarded_field);
-       assert(events_discarded_field_type);
-       field_signed = bt_ctf_field_type_integer_get_signed(
-               events_discarded_field_type);
-       assert(field_signed >= 0);
-       new_count = previous_count + event_count;
-       assert(new_count >= previous_count);
-       if (field_signed) {
-               ret = bt_ctf_field_signed_integer_set_value(
-                       events_discarded_field, (int64_t) new_count);
-               if (ret) {
-                       BT_LOGW("Cannot set packet context's `events_discarded` field: "
-                               "field-addr=%p, value=%" PRId64,
-                               events_discarded_field, (int64_t) new_count);
-                       goto end;
-               }
-       } else {
-               ret = bt_ctf_field_unsigned_integer_set_value(
-                       events_discarded_field, new_count);
-               if (ret) {
-                       BT_LOGW("Cannot set packet context's `events_discarded` field: "
-                               "field-addr=%p, value=%" PRIu64,
-                               events_discarded_field, new_count);
-                       goto end;
-               }
+       new_count = stream->discarded_events + event_count;
+       if (new_count < stream->discarded_events) {
+               BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
+                       "cur-count=%" PRIu64 ", new-count=%" PRIu64,
+                       stream->discarded_events, new_count);
+               goto end;
+       }
+
+       ret = set_packet_context_events_discarded_field(stream, new_count);
+       if (ret) {
+               /* set_packet_context_events_discarded_field() logs errors */
+               goto end;
        }
 
+       stream->discarded_events = new_count;
        BT_LOGV("Appended discarded events to stream: "
                "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
                stream, bt_ctf_stream_get_name(stream), event_count);
 
-
 end:
        bt_put(events_discarded_field);
-       bt_put(events_discarded_field_type);
 }
 
 static int auto_populate_event_header(struct bt_ctf_stream *stream,
@@ -862,21 +1021,14 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream,
                goto end;
        }
 
-       BT_LOGV("Automatically populating event header field: "
+       BT_LOGV("Automatically populating event's header field: "
                "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
                stream, bt_ctf_stream_get_name(stream), event);
 
-       /*
-        * The condition to automatically set the ID are:
-        *
-        * 1. The event header field "id" exists and is an integer
-        *    field.
-        * 2. The event header field "id" is NOT set.
-        */
        id_field = bt_ctf_field_structure_get_field(event->event_header, "id");
        event_class_id = (uint64_t) bt_ctf_event_class_get_id(event->event_class);
        assert(event_class_id >= 0);
-       if (id_field && !bt_ctf_field_is_set(id_field)) {
+       if (id_field && bt_ctf_field_type_is_integer(id_field->type)) {
                ret = set_integer_field_value(id_field, event_class_id);
                if (ret) {
                        BT_LOGW("Cannot set event header's `id` field's value: "
@@ -896,22 +1048,17 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream,
         * 3. The event header field "timestamp" has its type mapped to
         *    a clock class which is also the clock class of this
         *    stream's class's registered clock.
-        * 4. The event header field "timestamp" is NOT set.
         */
        timestamp_field = bt_ctf_field_structure_get_field(event->event_header,
                        "timestamp");
-       if (timestamp_field && !bt_ctf_field_is_set(timestamp_field) &&
-                       stream->stream_class->clock) {
+       if (timestamp_field && stream->stream_class->clock &&
+                       bt_ctf_field_type_is_integer(timestamp_field->type)) {
                struct bt_ctf_clock_class *stream_class_clock_class =
                        stream->stream_class->clock->clock_class;
-               struct bt_ctf_field_type *timestamp_field_type =
-                       bt_ctf_field_get_type(timestamp_field);
 
-               assert(timestamp_field_type);
                mapped_clock_class =
                        bt_ctf_field_type_integer_get_mapped_clock_class(
-                               timestamp_field_type);
-               BT_PUT(timestamp_field_type);
+                               timestamp_field->type);
                if (mapped_clock_class == stream_class_clock_class) {
                        uint64_t timestamp;
 
@@ -930,7 +1077,7 @@ static int auto_populate_event_header(struct bt_ctf_stream *stream,
                }
        }
 
-       BT_LOGV("Automatically populated event header field: "
+       BT_LOGV("Automatically populated event's header field: "
                "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
                stream, bt_ctf_stream_get_name(stream), event);
 
@@ -1144,7 +1291,25 @@ int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
        }
 
        trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
+
+       if (!field) {
+               if (trace->packet_header_type) {
+                       BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "packet-header-field-addr=%p, "
+                               "expected-ft-addr=%p",
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, trace->packet_header_type);
+                       ret = -1;
+                       goto end;
+               }
+
+               goto skip_validation;
+       }
+
        field_type = bt_ctf_field_get_type(field);
+       assert(field_type);
+
        if (bt_ctf_field_type_compare(field_type, trace->packet_header_type)) {
                BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
                        "stream-addr=%p, stream-name=\"%s\", "
@@ -1156,6 +1321,7 @@ int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
                goto end;
        }
 
+skip_validation:
        bt_put(stream->packet_header);
        stream->packet_header = bt_get(field);
        BT_LOGV("Set stream's packet header field: "
@@ -1168,66 +1334,6 @@ end:
        return ret;
 }
 
-static
-int get_event_header_timestamp(struct bt_ctf_field *event_header, uint64_t *timestamp)
-{
-       int ret = 0;
-       struct bt_ctf_field *timestamp_field = NULL;
-       struct bt_ctf_field_type *timestamp_field_type = NULL;
-
-       timestamp_field = bt_ctf_field_structure_get_field(event_header,
-               "timestamp");
-       if (!timestamp_field) {
-               BT_LOGV("Cannot get event header's `timestamp` field: "
-                       "field-addr=%p", timestamp_field);
-               ret = -1;
-               goto end;
-       }
-
-       timestamp_field_type = bt_ctf_field_get_type(timestamp_field);
-       assert(timestamp_field_type);
-       if (bt_ctf_field_type_get_type_id(timestamp_field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid event header: `timestamp` field's type is not an integer field type: "
-                       "event-header-field-addr=%p, "
-                       "timestamp-field-addr=%p, timestamp-ft-addr=%p, "
-                       "timestamp-ft-id=%s",
-                       event_header, timestamp_field, timestamp_field_type,
-                       bt_ctf_field_type_id_string(timestamp_field_type->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_ctf_field_type_integer_get_signed(timestamp_field_type)) {
-               int64_t val;
-
-               ret = bt_ctf_field_signed_integer_get_value(timestamp_field,
-                       &val);
-               if (ret) {
-                       BT_LOGW("Cannot get signed integer field's value: "
-                               "event-header-field-addr=%p, "
-                               "timestamp-field-addr=%p",
-                               event_header, timestamp_field);
-                       goto end;
-               }
-               *timestamp = (uint64_t) val;
-       } else {
-               ret = bt_ctf_field_unsigned_integer_get_value(timestamp_field,
-                       timestamp);
-               if (ret) {
-                       BT_LOGW("Cannot get unsigned integer field's value: "
-                               "event-header-field-addr=%p, "
-                               "timestamp-field-addr=%p",
-                               event_header, timestamp_field);
-                       goto end;
-               }
-       }
-end:
-       bt_put(timestamp_field);
-       bt_put(timestamp_field_type);
-       return ret;
-}
-
 static
 void reset_structure_field(struct bt_ctf_field *structure, const char *name)
 {
@@ -1243,19 +1349,9 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
 {
        int ret = 0;
        size_t i;
-       uint64_t timestamp_begin, timestamp_end;
-       struct bt_ctf_field *integer = NULL;
        struct bt_ctf_stream_pos packet_context_pos;
        struct bt_ctf_trace *trace;
        enum bt_ctf_byte_order native_byte_order;
-       bt_bool empty_packet;
-       uint64_t packet_size_bits;
-       struct {
-               bt_bool timestamp_begin;
-               bt_bool timestamp_end;
-               bt_bool content_size;
-               bt_bool packet_size;
-       } auto_set_fields = { 0 };
 
        if (!stream) {
                BT_LOGW_STR("Invalid parameter: stream is NULL.");
@@ -1269,15 +1365,23 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                goto end;
        }
 
-       if (!stream->packet_context && stream->flushed_packet_count > 0) {
-               /*
-                * A stream without a packet context, and thus without
-                * content and packet size members, can't have more than
-                * one packet.
-                */
-               BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
-               ret = -1;
-               goto end;
+       if (stream->flushed_packet_count == 1) {
+               struct bt_ctf_field *packet_size_field;
+
+               if (!stream->packet_context) {
+                       BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
+                       ret = -1;
+                       goto end;
+               }
+
+               packet_size_field = bt_ctf_field_structure_get_field(
+                       stream->packet_context, "packet_size");
+               bt_put(packet_size_field);
+               if (!packet_size_field) {
+                       BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
+                       ret = -1;
+                       goto end;
+               }
        }
 
        BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
@@ -1286,74 +1390,39 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
        trace = bt_ctf_stream_class_borrow_trace(stream->stream_class);
        assert(trace);
        native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
-       empty_packet = (stream->events->len == 0);
 
-       /* mmap the next packet */
-       BT_LOGV("Seeking to the next packet: pos-offset=%" PRId64,
-               stream->pos.offset);
-       bt_ctf_stream_pos_packet_seek(&stream->pos, 0, SEEK_CUR);
-       BT_LOGV_STR("Serializing packet header field.");
-       ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos,
-               native_byte_order);
+       ret = auto_populate_packet_header(stream);
        if (ret) {
-               BT_LOGE("Cannot serialize stream's packet header field: "
-                       "field-addr=%p", stream->packet_header);
+               BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
+               ret = -1;
                goto end;
        }
 
-       if (stream->packet_context) {
-               /* Set the default context attributes if present and unset. */
-               if (!empty_packet && !get_event_header_timestamp(
-                       ((struct bt_ctf_event *) g_ptr_array_index(
-                               stream->events, 0))->event_header, &timestamp_begin)) {
-                       ret = try_set_structure_field_integer(
-                               stream->packet_context,
-                               "timestamp_begin", timestamp_begin);
-                       if (ret < 0) {
-                               BT_LOGW("Cannot set `timestamp_begin` field in packet context: "
-                                       "ret=%d, packet-context-field-addr=%p",
-                                       ret, stream->packet_context);
-                               goto end;
-                       }
-                       auto_set_fields.timestamp_begin = ret == 1;
-               }
-
-               if (!empty_packet && !get_event_header_timestamp(
-                       ((struct bt_ctf_event *) g_ptr_array_index(
-                               stream->events, stream->events->len - 1))->event_header,
-                               &timestamp_end)) {
+       ret = auto_populate_packet_context(stream);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
+               ret = -1;
+               goto end;
+       }
 
-                       ret = try_set_structure_field_integer(
-                               stream->packet_context,
-                               "timestamp_end", timestamp_end);
-                       if (ret < 0) {
-                               BT_LOGW("Cannot set `timestamp_end` field in packet context: "
-                                       "ret=%d, packet-context-field-addr=%p",
-                                       ret, stream->packet_context);
-                               goto end;
-                       }
-                       auto_set_fields.timestamp_end = ret == 1;
-               }
-               ret = try_set_structure_field_integer(stream->packet_context,
-                       "content_size", UINT64_MAX);
-               if (ret < 0) {
-                       BT_LOGW("Cannot set `content_size` field in packet context: "
-                               "ret=%d, packet-context-field-addr=%p",
-                               ret, stream->packet_context);
-                       goto end;
-               }
-               auto_set_fields.content_size = ret == 1;
+       /* mmap the next packet */
+       BT_LOGV("Seeking to the next packet: pos-offset=%" PRId64,
+               stream->pos.offset);
+       bt_ctf_stream_pos_packet_seek(&stream->pos, 0, SEEK_CUR);
+       assert(stream->pos.packet_size % 8 == 0);
 
-               ret = try_set_structure_field_integer(stream->packet_context,
-                       "packet_size", UINT64_MAX);
-               if (ret < 0) {
-                       BT_LOGW("Cannot set `packet_size` field in packet context: "
-                               "ret=%d, packet-context-field-addr=%p",
-                               ret, stream->packet_context);
+       if (stream->packet_header) {
+               BT_LOGV_STR("Serializing packet header field.");
+               ret = bt_ctf_field_serialize(stream->packet_header, &stream->pos,
+                       native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet header field: "
+                               "field-addr=%p", stream->packet_header);
                        goto end;
                }
-               auto_set_fields.packet_size = ret == 1;
+       }
 
+       if (stream->packet_context) {
                /* Write packet context */
                memcpy(&packet_context_pos, &stream->pos,
                        sizeof(packet_context_pos));
@@ -1361,7 +1430,7 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                ret = bt_ctf_field_serialize(stream->packet_context,
                        &stream->pos, native_byte_order);
                if (ret) {
-                       BT_LOGE("Cannot serialize stream's packet context field: "
+                       BT_LOGW("Cannot serialize stream's packet context field: "
                                "field-addr=%p", stream->packet_context);
                        goto end;
                }
@@ -1375,7 +1444,7 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                struct bt_ctf_event_class *event_class =
                        bt_ctf_event_borrow_event_class(event);
 
-               BT_LOGV("Serializing event: index=%u, event-addr=%p, "
+               BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
                        "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
                        "pos-offset=%" PRId64 ", packet-size=%" PRIu64,
                        i, event, bt_ctf_event_class_get_name(event_class),
@@ -1387,7 +1456,7 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                ret = bt_ctf_field_serialize(event->event_header,
                        &stream->pos, native_byte_order);
                if (ret) {
-                       BT_LOGE("Cannot serialize event's header field: "
+                       BT_LOGW("Cannot serialize event's header field: "
                                "field-addr=%p", event->event_header);
                        goto end;
                }
@@ -1399,7 +1468,7 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                                event->stream_event_context, &stream->pos,
                                native_byte_order);
                        if (ret) {
-                               BT_LOGE("Cannot serialize event's stream event context field: "
+                               BT_LOGW("Cannot serialize event's stream event context field: "
                                        "field-addr=%p", event->stream_event_context);
                                goto end;
                        }
@@ -1414,47 +1483,52 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
                }
        }
 
-       /* Rounded-up in case content_size is not byte-aligned. */
-       packet_size_bits = (stream->pos.offset + (CHAR_BIT - 1)) &
-               ~(CHAR_BIT - 1);
-       stream->pos.packet_size = packet_size_bits;
+       assert(stream->pos.packet_size % 8 == 0);
 
        if (stream->packet_context) {
                /*
-                * Update the packet total size and content size and overwrite
-                * the packet context.
-                * Copy base_mma as the packet may have been remapped (e.g. when
-                * a packet is resized).
+                * The whole packet is serialized at this point. Make sure that,
+                * if `packet_size` is missing, the current content size is
+                * equal to the current packet size.
                 */
-               packet_context_pos.base_mma = stream->pos.base_mma;
-               if (auto_set_fields.content_size) {
-                       ret = set_structure_field_integer(
-                                       stream->packet_context,
-                                       "content_size", stream->pos.offset);
-                       if (ret < 0) {
-                               BT_LOGW("Cannot set `content_size` field in packet context: "
-                                       "ret=%d, packet-context-field-addr=%p",
-                                       ret, stream->packet_context);
+               struct bt_ctf_field *field = bt_ctf_field_structure_get_field(
+                       stream->packet_context, "content_size");
+
+               bt_put(field);
+               if (!field) {
+                       if (stream->pos.offset != stream->pos.packet_size) {
+                               BT_LOGW("Stream's packet context's `content_size` field is missing, "
+                                       "but current packet's content size is not equal to its packet size: "
+                                       "content-size=%" PRId64 ", "
+                                       "packet-size=%" PRIu64,
+                                       stream->pos.offset,
+                                       stream->pos.packet_size);
+                               ret = -1;
                                goto end;
                        }
                }
 
-               if (auto_set_fields.packet_size) {
-                       ret = set_structure_field_integer(stream->packet_context,
-                                       "packet_size", packet_size_bits);
-                       if (ret < 0) {
-                               BT_LOGW("Cannot set `packet_size` field in packet context: "
-                                       "ret=%d, packet-context-field-addr=%p",
-                                       ret, stream->packet_context);
-                               goto end;
-                       }
+               /*
+                * Overwrite the packet context now that the stream
+                * position's packet and content sizes have the correct
+                * values.
+                *
+                * Copy base_mma as the packet may have been remapped
+                * (e.g. when a packet is resized).
+                */
+               packet_context_pos.base_mma = stream->pos.base_mma;
+               ret = auto_populate_packet_context(stream);
+               if (ret) {
+                       BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
+                       ret = -1;
+                       goto end;
                }
 
                BT_LOGV("Rewriting (serializing) packet context field.");
                ret = bt_ctf_field_serialize(stream->packet_context,
                        &packet_context_pos, native_byte_order);
                if (ret) {
-                       BT_LOGE("Cannot serialize stream's packet context field: "
+                       BT_LOGW("Cannot serialize stream's packet context field: "
                                "field-addr=%p", stream->packet_context);
                        goto end;
                }
@@ -1462,26 +1536,13 @@ int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
 
        g_ptr_array_set_size(stream->events, 0);
        stream->flushed_packet_count++;
-       stream->size += packet_size_bits / CHAR_BIT;
+       stream->size += stream->pos.packet_size / CHAR_BIT;
 end:
        /* Reset automatically-set fields. */
-       if (auto_set_fields.timestamp_begin) {
-               reset_structure_field(stream->packet_context,
-                               "timestamp_begin");
-       }
-       if (auto_set_fields.timestamp_end) {
-               reset_structure_field(stream->packet_context,
-                               "timestamp_end");
-       }
-       if (auto_set_fields.packet_size) {
-               reset_structure_field(stream->packet_context,
-                               "packet_size");
-       }
-       if (auto_set_fields.content_size) {
-               reset_structure_field(stream->packet_context,
-                               "content_size");
-       }
-       bt_put(integer);
+       reset_structure_field(stream->packet_context, "timestamp_begin");
+       reset_structure_field(stream->packet_context, "timestamp_end");
+       reset_structure_field(stream->packet_context, "packet_size");
+       reset_structure_field(stream->packet_context, "content_size");
 
        if (ret < 0) {
                /*
@@ -1492,8 +1553,9 @@ end:
                 */
                stream->pos.packet_size = 0;
        } else {
-               BT_LOGV("Flushed stream's current packet: packet-size=%" PRIu64,
-                       packet_size_bits);
+               BT_LOGV("Flushed stream's current packet: content-size=%" PRId64 ", "
+                       "packet-size=%" PRIu64,
+                       stream->pos.offset, stream->pos.packet_size);
        }
        return ret;
 }
@@ -1655,13 +1717,6 @@ end:
        return ret;
 }
 
-static
-int set_structure_field_integer(struct bt_ctf_field *structure, char *name,
-               uint64_t value)
-{
-       return _set_structure_field_integer(structure, name, value, BT_TRUE);
-}
-
 /*
  * Returns the following codes:
  * 1 if the field was found and set,
index e2fa56d79bb85fb33376656b27bb0794b4881d35..427c2c5a96fd5c8a03c6c46bcd6b33ad26129911 100644 (file)
@@ -282,7 +282,6 @@ void bt_ctf_stream_pos_packet_seek(struct bt_ctf_stream_pos *pos, size_t index,
 
        /* The writer will add padding */
        pos->mmap_offset += pos->packet_size / CHAR_BIT;
-       pos->content_size = -1U;        /* Unknown at this point */
        pos->packet_size = getpagesize() * 8 * CHAR_BIT;
        do {
                ret = bt_posix_fallocate(pos->fd, pos->mmap_offset,
This page took 0.046079 seconds and 4 git commands to generate.