+static
+void ctf_update_timestamp(struct ctf_stream *stream,
+ struct definition_integer *integer_definition)
+{
+ struct declaration_integer *integer_declaration =
+ integer_definition->declaration;
+ uint64_t oldval, newval, updateval;
+
+ if (integer_declaration->len == 64) {
+ stream->timestamp = integer_definition->value._unsigned;
+ return;
+ }
+ /* keep low bits */
+ oldval = stream->timestamp;
+ oldval &= (1ULL << integer_declaration->len) - 1;
+ newval = integer_definition->value._unsigned;
+ /* Test for overflow by comparing low bits */
+ if (newval < oldval)
+ newval += 1ULL << integer_declaration->len;
+ /* updateval contains old high bits, and new low bits (sum) */
+ updateval = stream->timestamp;
+ updateval &= ~((1ULL << integer_declaration->len) - 1);
+ updateval += newval;
+ stream->timestamp = updateval;
+}
+
+static
+int ctf_read_event(struct stream_pos *ppos, struct ctf_stream *stream)
+{
+ struct ctf_stream_pos *pos =
+ container_of(ppos, struct ctf_stream_pos, parent);
+ struct ctf_stream_class *stream_class = stream->stream_class;
+ struct ctf_file_event *event;
+ uint64_t id = 0;
+ int ret;
+
+ if (pos->offset == EOF)
+ return EOF;
+
+ /* Read event header */
+ if (stream->stream_event_header) {
+ struct definition_integer *integer_definition;
+ struct definition *variant;
+
+ ret = generic_rw(ppos, &stream->stream_event_header->p);
+ if (ret)
+ goto error;
+ /* lookup event id */
+ integer_definition = lookup_integer(&stream->stream_event_header->p, "id", FALSE);
+ if (integer_definition) {
+ id = integer_definition->value._unsigned;
+ } else {
+ struct definition_enum *enum_definition;
+
+ enum_definition = lookup_enum(&stream->stream_event_header->p, "id", FALSE);
+ if (enum_definition) {
+ id = enum_definition->integer->value._unsigned;
+ }
+ }
+
+ variant = lookup_variant(&stream->stream_event_header->p, "v");
+ if (variant) {
+ integer_definition = lookup_integer(variant, "id", FALSE);
+ if (integer_definition) {
+ id = integer_definition->value._unsigned;
+ }
+ }
+
+ /* lookup timestamp */
+ integer_definition = lookup_integer(&stream->stream_event_header->p, "timestamp", FALSE);
+ if (integer_definition) {
+ ctf_update_timestamp(stream, integer_definition);
+ } else {
+ if (variant) {
+ integer_definition = lookup_integer(variant, "timestamp", FALSE);
+ if (integer_definition) {
+ ctf_update_timestamp(stream, integer_definition);
+ }
+ }
+ }
+ }
+
+ /* Read stream-declared event context */
+ if (stream->stream_event_context) {
+ ret = generic_rw(ppos, &stream->stream_event_context->p);
+ if (ret)
+ goto error;
+ }
+
+ if (id >= stream_class->events_by_id->len) {
+ fprintf(stdout, "[error] Event id %" PRIu64 " is outside range.\n", id);
+ return -EINVAL;
+ }
+ event = g_ptr_array_index(stream->events_by_id, id);
+ if (!event) {
+ fprintf(stdout, "[error] Event id %" PRIu64 " is unknown.\n", id);
+ return -EINVAL;
+ }
+
+ /* Read event-declared event context */
+ if (event->event_context) {
+ ret = generic_rw(ppos, &event->event_context->p);
+ if (ret)
+ goto error;
+ }
+
+ /* Read event payload */
+ if (event->event_fields) {
+ ret = generic_rw(ppos, &event->event_fields->p);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ fprintf(stdout, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
+ return ret;
+}
+
+static
+int ctf_write_event(struct stream_pos *pos, struct ctf_stream *stream)
+{
+ struct ctf_stream_class *stream_class = stream->stream_class;
+ struct ctf_file_event *event;
+ uint64_t id = 0;
+ int ret;
+
+ /* print event header */
+ if (stream->stream_event_header) {
+ struct definition_integer *integer_definition;
+ struct definition *variant;
+
+ /* lookup event id */
+ integer_definition = lookup_integer(&stream->stream_event_header->p, "id", FALSE);
+ if (integer_definition) {
+ id = integer_definition->value._unsigned;
+ } else {
+ struct definition_enum *enum_definition;
+
+ enum_definition = lookup_enum(&stream->stream_event_header->p, "id", FALSE);
+ if (enum_definition) {
+ id = enum_definition->integer->value._unsigned;
+ }
+ }
+
+ variant = lookup_variant(&stream->stream_event_header->p, "v");
+ if (variant) {
+ integer_definition = lookup_integer(variant, "id", FALSE);
+ if (integer_definition) {
+ id = integer_definition->value._unsigned;
+ }
+ }
+
+ ret = generic_rw(pos, &stream->stream_event_header->p);
+ if (ret)
+ goto error;
+ }
+
+ /* print stream-declared event context */
+ if (stream->stream_event_context) {
+ ret = generic_rw(pos, &stream->stream_event_context->p);
+ if (ret)
+ goto error;
+ }
+
+ if (id >= stream_class->events_by_id->len) {
+ fprintf(stdout, "[error] Event id %" PRIu64 " is outside range.\n", id);
+ return -EINVAL;
+ }
+ event = g_ptr_array_index(stream->events_by_id, id);
+ if (!event) {
+ fprintf(stdout, "[error] Event id %" PRIu64 " is unknown.\n", id);
+ return -EINVAL;
+ }
+
+ /* print event-declared event context */
+ if (event->event_context) {
+ ret = generic_rw(pos, &event->event_context->p);
+ if (ret)
+ goto error;
+ }
+
+ /* Read and print event payload */
+ if (event->event_fields) {
+ ret = generic_rw(pos, &event->event_fields->p);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ fprintf(stdout, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
+ return ret;
+}
+