ir: refactor FT validation and resolving
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 8 Feb 2016 07:21:40 +0000 (02:21 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 19 Feb 2016 20:57:34 +0000 (15:57 -0500)
This patch refactors the CTF IR field type validation and the
resolving of variant/sequence field types.

First, validation is completely decoupled from the objects
containing the field types. In other words, validation does not
know the exact event class, stream class, or trace in which the
field types to validate are or are supposed to be. Only field types
are given to the validation function, which is isolated in its
own file.

To make the life of the resolving engine easier, all scopes are
deep-copied before reaching it. This is done during the validation
process. This ensures that no two field types in the whole
hierarchy refer to the same object in memory. This greatly simplifies
the resolving process, while adding insignificant overhead since
this is only done once. The copies do not replace the original types
until we are sure that the object to be validated (event class, stream
class, or trace) is valid and will be frozen. When it is the case, a
valid flag is set, which avoids validating the object again in the
future when calling the same function. If the object is not valid,
then the copies of its field types are discarded, and the function
fails.

Validation is done at three important places:

  * bt_ctf_event_create(): when creating an event, because we don't
    want the user to obtain an event linked to an invalid event
    class. It is possible to create an event from an even class
    which has a parent stream class which has no parent trace. In
    this case, no variant/sequence field type in all the field types
    of the stream class and event class can be resolved to the
    trace packet header field type.
  * bt_ctf_stream_class_add_event_class(): when adding an event class
    to a stream class AND when the stream class has a parent trace,
    because in this case the whole hierarchy exists and everything
    is frozen, so it makes sense that everything in there should be
    valid. If the stream class has no parent trace yet, then the
    validation will be done when adding it to a trace using the
    following function. This is because the added event class could
    contain a variant/sequence field type which resolves to a field
    type of the trace packet header field type, contained in the trace
    object.
  * bt_ctf_trace_add_stream_class(): when adding a stream class to
    a trace, because in this case both the trace and the stream
    class will be frozen, and hence they should be valid because they
    cannot be changed anymore.

The test_ctf_writer test is updated here to follow those changes. Since
the field types can be copied when calling one of the above functions,
we cannot create a field out of an original field type and then compare
its address to a field obtained from the created event or stream: we must
put the original field types and obtain the new ones from the event class
or stream class. The contents of field types are compared using
bt_ctf_field_type_compare() instead.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
19 files changed:
formats/ctf/ir/Makefile.am
formats/ctf/ir/event-fields.c
formats/ctf/ir/event-types.c
formats/ctf/ir/event.c
formats/ctf/ir/resolve.c [new file with mode: 0644]
formats/ctf/ir/stream-class.c
formats/ctf/ir/stream.c
formats/ctf/ir/trace.c
formats/ctf/ir/validation.c [new file with mode: 0644]
formats/ctf/ir/visitor.c [deleted file]
include/Makefile.am
include/babeltrace/ctf-ir/event-internal.h
include/babeltrace/ctf-ir/event-types-internal.h
include/babeltrace/ctf-ir/resolve-internal.h [new file with mode: 0644]
include/babeltrace/ctf-ir/stream-class-internal.h
include/babeltrace/ctf-ir/trace-internal.h
include/babeltrace/ctf-ir/validation-internal.h [new file with mode: 0644]
include/babeltrace/ctf-ir/visitor-internal.h [deleted file]
tests/lib/test_ctf_writer.c

index 31a71ce423f4325a9aa0722b8dac430119b81b13..b08643b11d05ece5de433c6ddfbb685edcb9f4c3 100644 (file)
@@ -12,7 +12,8 @@ libctf_ir_la_SOURCES = \
        stream-class.c \
        trace.c \
        utils.c \
-       visitor.c
+       resolve.c \
+       validation.c
 
 libctf_ir_la_LIBADD = \
        $(top_builddir)/lib/libbabeltrace.la
index 65c9aee863a7511ec4629fb9c9aaecfd1b8d6285..71c4ea173edd02d057cde0d08d226f57bff4c0be 100644 (file)
@@ -535,7 +535,8 @@ int bt_ctf_field_structure_set_field(struct bt_ctf_field *field,
        expected_field_type =
                bt_ctf_field_type_structure_get_field_type_by_name(field->type,
                name);
-       if (expected_field_type != value->type) {
+
+       if (bt_ctf_field_type_compare(expected_field_type, value->type)) {
                ret = -1;
                goto end;
        }
index 1c5e4765c1d0c99a9e3ca507683660e7a906dcd0..1d53c609a95a5c0cc11cb16663c11407bc92ba84 100644 (file)
@@ -3918,8 +3918,6 @@ int bt_ctf_field_type_structure_compare(struct bt_ctf_field_type *type_a,
                if (ret) {
                        goto end;
                }
-
-               ret = 1;
        }
 
        /* Equal */
@@ -3973,8 +3971,6 @@ int bt_ctf_field_type_variant_compare(struct bt_ctf_field_type *type_a,
                if (ret) {
                        goto end;
                }
-
-               ret = 1;
        }
 
        /* Equal */
@@ -4068,3 +4064,85 @@ int bt_ctf_field_type_compare(struct bt_ctf_field_type *type_a,
 end:
        return ret;
 }
+
+BT_HIDDEN
+int bt_ctf_field_type_get_field_count(struct bt_ctf_field_type *field_type)
+{
+       int field_count = -1;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(field_type);
+
+       switch (type_id) {
+       case CTF_TYPE_STRUCT:
+               field_count =
+                       bt_ctf_field_type_structure_get_field_count(field_type);
+               break;
+       case CTF_TYPE_VARIANT:
+               field_count =
+                       bt_ctf_field_type_variant_get_field_count(field_type);
+               break;
+       case CTF_TYPE_ARRAY:
+       case CTF_TYPE_SEQUENCE:
+               /*
+                * Array and sequence types always contain a single member
+                * (the element type).
+                */
+               field_count = 1;
+               break;
+       default:
+               break;
+       }
+
+       return field_count;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type *bt_ctf_field_type_get_field_at_index(
+               struct bt_ctf_field_type *field_type, int index)
+{
+       struct bt_ctf_field_type *field = NULL;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(field_type);
+
+       switch (type_id) {
+       case CTF_TYPE_STRUCT:
+               bt_ctf_field_type_structure_get_field(field_type, NULL, &field,
+                       index);
+               break;
+       case CTF_TYPE_VARIANT:
+               bt_ctf_field_type_variant_get_field(field_type, NULL,
+                       &field, index);
+               break;
+       case CTF_TYPE_ARRAY:
+               field = bt_ctf_field_type_array_get_element_type(field_type);
+               break;
+       case CTF_TYPE_SEQUENCE:
+               field = bt_ctf_field_type_sequence_get_element_type(field_type);
+               break;
+       default:
+               break;
+       }
+
+       return field;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_get_field_index(struct bt_ctf_field_type *field_type,
+               const char *name)
+{
+       int field_index = -1;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(field_type);
+
+       switch (type_id) {
+       case CTF_TYPE_STRUCT:
+               field_index = bt_ctf_field_type_structure_get_field_name_index(
+                       field_type, name);
+               break;
+       case CTF_TYPE_VARIANT:
+               field_index = bt_ctf_field_type_variant_get_field_name_index(
+                       field_type, name);
+               break;
+       default:
+               break;
+       }
+
+       return field_index;
+}
index 14e605f0e64e78c8d3ffaea374e79547cf0fa79e..85edf6942081f7705e81eeded43eb83ac846397b 100644 (file)
@@ -35,6 +35,7 @@
 #include <babeltrace/ctf-ir/stream-class.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
 #include <babeltrace/ctf-ir/trace-internal.h>
+#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ref.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
@@ -531,14 +532,32 @@ end:
 
 struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
 {
+       int ret;
+       enum bt_ctf_validation_flag validation_flags =
+               BT_CTF_VALIDATION_FLAG_STREAM |
+               BT_CTF_VALIDATION_FLAG_EVENT;
        struct bt_ctf_event *event = NULL;
+       struct bt_ctf_trace *trace = NULL;
        struct bt_ctf_stream_class *stream_class = NULL;
+       struct bt_ctf_field_type *packet_header_type = NULL;
+       struct bt_ctf_field_type *packet_context_type = NULL;
+       struct bt_ctf_field_type *event_header_type = NULL;
+       struct bt_ctf_field_type *stream_event_ctx_type = NULL;
+       struct bt_ctf_field_type *event_context_type = NULL;
+       struct bt_ctf_field_type *event_payload_type = NULL;
+       struct bt_ctf_field *event_header = NULL;
+       struct bt_ctf_field *event_context = NULL;
+       struct bt_ctf_field *event_payload = NULL;
+       struct bt_value *environment = NULL;
+       struct bt_ctf_validation_output validation_output = { 0 };
+       int trace_valid = 0;
 
        if (!event_class) {
                goto error;
        }
 
        stream_class = bt_ctf_event_class_get_stream_class(event_class);
+
        /*
         * We disallow the creation of an event if its event class has not been
         * associated to a stream class.
@@ -546,14 +565,69 @@ struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
        if (!stream_class) {
                goto error;
        }
+
+       /* A stream class should always have an existing event header type */
        assert(stream_class->event_header_type);
+
+       /* The event class was frozen when added to its stream class */
+       assert(event_class->frozen);
+
+       /* Validate the trace (if any), the stream class, and the event class */
+       trace = bt_ctf_stream_class_get_trace(stream_class);
+       if (trace) {
+               packet_header_type = bt_ctf_trace_get_packet_header_type(trace);
+               trace_valid = trace->valid;
+               assert(trace_valid);
+               environment = trace->environment;
+       }
+
+       packet_context_type = bt_ctf_stream_class_get_packet_context_type(
+               stream_class);
+       event_header_type = bt_ctf_stream_class_get_event_header_type(
+               stream_class);
+       stream_event_ctx_type = bt_ctf_stream_class_get_event_context_type(
+               stream_class);
+       event_context_type = bt_ctf_event_class_get_context_type(event_class);
+       event_payload_type = bt_ctf_event_class_get_payload_type(event_class);
+       ret = bt_ctf_validate_class_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               event_context_type, event_payload_type, trace_valid,
+               stream_class->valid, event_class->valid,
+               &validation_output, validation_flags);
+       BT_PUT(packet_header_type);
+       BT_PUT(packet_context_type);
+       BT_PUT(event_header_type);
+       BT_PUT(stream_event_ctx_type);
+       BT_PUT(event_context_type);
+       BT_PUT(event_payload_type);
+
+       if (ret) {
+               /*
+                * This means something went wrong during the validation
+                * process, not that the objects are invalid.
+                */
+               goto error;
+       }
+
+       if ((validation_output.valid_flags & validation_flags) !=
+                       validation_flags) {
+               /* Invalid trace/stream class/event class */
+               goto error;
+       }
+
+       /*
+        * At this point we know the trace (if associated to the stream
+        * class), the stream class, and the event class, with their
+        * current types, are valid. We may proceed with creating
+        * the event.
+        */
        event = g_new0(struct bt_ctf_event, 1);
        if (!event) {
                goto error;
        }
 
        bt_object_init(event, bt_ctf_event_destroy);
-       bt_ctf_event_class_freeze(event_class);
+
        /*
         * event does not share a common ancestor with the event class; it has
         * to guarantee its existence by holding a reference. This reference
@@ -562,34 +636,80 @@ struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
         * lifetime.
         */
        event->event_class = bt_get(event_class);
+       event_header =
+               bt_ctf_field_create(validation_output.event_header_type);
 
-       event->event_header = bt_ctf_field_create(
-               stream_class->event_header_type);
-       if (!event->event_header) {
+       if (!event_header) {
                goto error;
        }
-       if (event_class->context) {
-               event->context_payload = bt_ctf_field_create(
-                       event_class->context);
-               if (!event->context_payload) {
+
+       if (validation_output.event_context_type) {
+               event_context = bt_ctf_field_create(
+                       validation_output.event_context_type);
+               if (!event_context) {
                        goto error;
                }
        }
-       event->fields_payload = bt_ctf_field_create(event_class->fields);
-       if (!event->fields_payload) {
-               goto error;
+
+       if (validation_output.event_payload_type) {
+               event_payload = bt_ctf_field_create(
+                       validation_output.event_payload_type);
+               if (!event_payload) {
+                       goto error;
+               }
        }
 
+       /*
+        * At this point all the fields are created, potentially from
+        * validated copies of field types, so that the field types and
+        * fields can be replaced in the trace, stream class,
+        * event class, and created event.
+        */
+       bt_ctf_validation_replace_types(trace, stream_class,
+               event_class, &validation_output, validation_flags);
+       BT_MOVE(event->event_header, event_header);
+       BT_MOVE(event->context_payload, event_context);
+       BT_MOVE(event->fields_payload, event_payload);
+
+       /*
+        * Put what was not moved in bt_ctf_validation_replace_types().
+        */
+       bt_ctf_validation_output_put_types(&validation_output);
+
        /*
         * Freeze the stream class since the event header must not be changed
         * anymore.
         */
        bt_ctf_stream_class_freeze(stream_class);
+
+       /*
+        * Mark stream class, and event class as valid since
+        * they're all frozen now.
+        */
+       stream_class->valid = 1;
+       event_class->valid = 1;
+
+       /* Put stuff we borrowed from the event class */
        BT_PUT(stream_class);
+       BT_PUT(trace);
+
        return event;
+
 error:
+       bt_ctf_validation_output_put_types(&validation_output);
        BT_PUT(event);
        BT_PUT(stream_class);
+       BT_PUT(trace);
+       BT_PUT(event_header);
+       BT_PUT(event_context);
+       BT_PUT(event_payload);
+       assert(!packet_header_type);
+       assert(!packet_context_type);
+       assert(!event_header_type);
+       assert(!stream_event_ctx_type);
+       assert(!event_context_type);
+       assert(!event_payload_type);
+
        return event;
 }
 
@@ -663,7 +783,9 @@ int bt_ctf_event_set_payload(struct bt_ctf_event *event,
                struct bt_ctf_field_type *payload_type;
 
                payload_type = bt_ctf_field_get_type(payload);
-               if (payload_type == event->event_class->fields) {
+
+               if (bt_ctf_field_type_compare(payload_type,
+                               event->event_class->fields) == 0) {
                        bt_put(event->fields_payload);
                        bt_get(payload);
                        event->fields_payload = payload;
@@ -791,7 +913,8 @@ int bt_ctf_event_set_header(struct bt_ctf_event *event,
         * stream class.
         */
        field_type = bt_ctf_field_get_type(header);
-       if (field_type != stream_class->event_header_type) {
+       if (bt_ctf_field_type_compare(field_type,
+                       stream_class->event_header_type)) {
                ret = -1;
                goto end;
        }
@@ -832,7 +955,8 @@ int bt_ctf_event_set_event_context(struct bt_ctf_event *event,
        }
 
        field_type = bt_ctf_field_get_type(context);
-       if (field_type != event->event_class->context) {
+       if (bt_ctf_field_type_compare(field_type,
+                       event->event_class->context)) {
                ret = -1;
                goto end;
        }
diff --git a/formats/ctf/ir/resolve.c b/formats/ctf/ir/resolve.c
new file mode 100644 (file)
index 0000000..fd45401
--- /dev/null
@@ -0,0 +1,1194 @@
+/*
+ * resolve.c
+ *
+ * Babeltrace - CTF IR: Type resolving internal
+ *
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *          Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/event.h>
+#include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/resolve-internal.h>
+#include <babeltrace/ctf-ir/event-types-internal.h>
+#include <babeltrace/ctf-ir/event-internal.h>
+#include <babeltrace/ref.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/values.h>
+#include <limits.h>
+#include <glib.h>
+
+#define _printf_error(fmt, args...) \
+       printf_verbose("[resolving] " fmt, ## args)
+
+typedef GPtrArray type_stack;
+
+/*
+ * A stack frame.
+ *
+ * `type` contains a compound field type (structure, variant, array,
+ * or sequence) and `index` indicates the index of the field type in
+ * the upper frame (-1 for array and sequence field types).
+ *
+ * `type` is owned by the stack frame.
+ */
+struct type_stack_frame {
+       struct bt_ctf_field_type *type;
+       int index;
+};
+
+/*
+ * The current context of the resolving engine.
+ *
+ * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2)
+ * in the following order:
+ *
+ *   * Packet header
+ *   * Packet context
+ *   * Event header
+ *   * Stream event context
+ *   * Event context
+ *   * Event payload
+ */
+struct resolve_context {
+       struct bt_value *environment;
+       struct bt_ctf_field_type *scopes[6];
+
+       /* Root node being visited */
+       enum bt_ctf_node root_node;
+       type_stack *type_stack;
+       struct bt_ctf_field_type *cur_field_type;
+};
+
+/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
+static const char * const absolute_path_prefixes[] = {
+       [CTF_NODE_ENV]                          = "env.",
+       [CTF_NODE_TRACE_PACKET_HEADER]          = "trace.packet.header.",
+       [CTF_NODE_STREAM_PACKET_CONTEXT]        = "stream.packet.context.",
+       [CTF_NODE_STREAM_EVENT_HEADER]          = "stream.event.header.",
+       [CTF_NODE_STREAM_EVENT_CONTEXT]         = "stream.event.context.",
+       [CTF_NODE_EVENT_CONTEXT]                = "event.context.",
+       [CTF_NODE_EVENT_FIELDS]                 = "event.fields.",
+};
+
+/* Number of path tokens used for the absolute prefixes */
+static const int absolute_path_prefix_ptoken_counts[] = {
+       [CTF_NODE_ENV]                          = 1,
+       [CTF_NODE_TRACE_PACKET_HEADER]          = 3,
+       [CTF_NODE_STREAM_PACKET_CONTEXT]        = 3,
+       [CTF_NODE_STREAM_EVENT_HEADER]          = 3,
+       [CTF_NODE_STREAM_EVENT_CONTEXT]         = 3,
+       [CTF_NODE_EVENT_CONTEXT]                = 2,
+       [CTF_NODE_EVENT_FIELDS]                 = 2,
+};
+
+/*
+ * Destroys a type stack frame.
+ */
+static
+void type_stack_destroy_notify(gpointer data)
+{
+       struct type_stack_frame *frame = data;
+
+       BT_PUT(frame->type);
+       g_free(frame);
+}
+
+/*
+ * Creates a type stack.
+ *
+ * Return value is owned by the caller.
+ */
+static
+type_stack *type_stack_create(void)
+{
+       return g_ptr_array_new_with_free_func(type_stack_destroy_notify);
+}
+
+/*
+ * Destroys a type stack.
+ */
+static
+void type_stack_destroy(type_stack *stack)
+{
+       g_ptr_array_free(stack, TRUE);
+}
+
+/*
+ * Pushes a field type onto a type stack.
+ *
+ * `type` is owned by the caller (stack frame gets a new reference).
+ */
+static
+int type_stack_push(type_stack *stack, struct bt_ctf_field_type *type)
+{
+       int ret = 0;
+       struct type_stack_frame *frame = NULL;
+
+       if (!stack || !type) {
+               ret = -1;
+               goto end;
+       }
+
+       frame = g_new0(struct type_stack_frame, 1);
+       if (!frame) {
+               ret = -1;
+               goto end;
+       }
+
+       frame->type = bt_get(type);
+       g_ptr_array_add(stack, frame);
+
+end:
+       return ret;
+}
+
+/*
+ * Checks whether or not `stack` is empty.
+ */
+static
+bool type_stack_empty(type_stack *stack)
+{
+       return stack->len == 0;
+}
+
+/*
+ * Returns the number of frames in `stack`.
+ */
+static
+size_t type_stack_size(type_stack *stack)
+{
+       return stack->len;
+}
+
+/*
+ * Returns the top frame of `stack`.
+ *
+ * Return value is owned by `stack`.
+ */
+static
+struct type_stack_frame *type_stack_peek(type_stack *stack)
+{
+       struct type_stack_frame *entry = NULL;
+
+       if (!stack || type_stack_empty(stack)) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, stack->len - 1);
+end:
+       return entry;
+}
+
+/*
+ * Returns the frame at index `index` in `stack`.
+ *
+ * Return value is owned by `stack`.
+ */
+static
+struct type_stack_frame *type_stack_at(type_stack *stack,
+               size_t index)
+{
+       struct type_stack_frame *entry = NULL;
+
+       if (!stack || index >= stack->len) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, index);
+
+end:
+       return entry;
+}
+
+/*
+ * Removes the top frame of `stack`.
+ */
+static
+void type_stack_pop(type_stack *stack)
+{
+       if (!type_stack_empty(stack)) {
+               /*
+                * This will call the frame's destructor and free it, as
+                * well as put its contained field type.
+                */
+               g_ptr_array_set_size(stack, stack->len - 1);
+       }
+}
+
+/*
+ * Returns the scope field type of `scope` in the context `ctx`.
+ *
+ * Return value is owned by `ctx` on success.
+ */
+static
+struct bt_ctf_field_type *get_type_from_ctx(struct resolve_context *ctx,
+               enum bt_ctf_node node)
+{
+       assert(node >= CTF_NODE_TRACE_PACKET_HEADER &&
+               node <= CTF_NODE_EVENT_FIELDS);
+
+       return ctx->scopes[node - CTF_NODE_TRACE_PACKET_HEADER];
+}
+
+/*
+ * Returns the CTF scope from a path string. May return
+ * CTF_NODE_UNKNOWN if the path is found to be relative.
+ */
+static
+enum bt_ctf_node get_root_node_from_absolute_pathstr(const char *pathstr)
+{
+       enum bt_ctf_node node;
+       enum bt_ctf_node ret = CTF_NODE_UNKNOWN;
+       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
+               sizeof(*absolute_path_prefixes);
+
+       for (node = CTF_NODE_ENV; node < CTF_NODE_ENV + prefixes_count;
+                       node++) {
+               /*
+                * Chech if path string starts with a known absolute
+                * path prefix.
+                *
+                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
+                */
+               if (strncmp(pathstr, absolute_path_prefixes[node],
+                               strlen(absolute_path_prefixes[node]))) {
+                       /* Prefix does not match: try the next one */
+                       continue;
+               }
+
+               /* Found it! */
+               ret = node;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Destroys a path token.
+ */
+static
+void ptokens_destroy_func(gpointer ptoken, gpointer data)
+{
+       g_string_free(ptoken, TRUE);
+}
+
+/*
+ * Destroys a path token list.
+ */
+static
+void ptokens_destroy(GList *ptokens)
+{
+       if (!ptokens) {
+               return;
+       }
+
+       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
+       g_list_free(ptokens);
+}
+
+/*
+ * Returns the string contained in a path token.
+ */
+static
+const char *ptoken_get_string(GList *ptoken)
+{
+       GString *tokenstr = (GString *) ptoken->data;
+
+       return tokenstr->str;
+}
+
+/*
+ * Converts a path string to a path token list, that is, splits the
+ * individual words of a path string into a list of individual
+ * strings.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+GList *pathstr_to_ptokens(const char *pathstr)
+{
+       const char *at = pathstr;
+       const char *last = at;
+       GList *ptokens = NULL;
+
+       for (;;) {
+               if (*at == '.' || *at == '\0') {
+                       GString *tokenstr;
+
+                       if (at == last) {
+                               /* Error: empty token */
+                               _printf_error("Empty token in path string at position %d\n",
+                                       (int) (at - pathstr));
+                               goto error;
+                       }
+
+                       tokenstr = g_string_new(NULL);
+                       g_string_append_len(tokenstr, last, at - last);
+                       ptokens = g_list_append(ptokens, tokenstr);
+                       last = at + 1;
+               }
+
+               if (*at == '\0') {
+                       break;
+               }
+
+               at++;
+       }
+
+       return ptokens;
+
+error:
+       ptokens_destroy(ptokens);
+       return NULL;
+}
+
+/*
+ * Converts a path token list to a field path object. The path token
+ * list is relative from `type`. The index of the source looking for
+ * its target within `type` is indicated by `src_index`. This can be
+ * `INT_MAX` if the source is contained in `type`.
+ *
+ * `ptokens` is owned by the caller. `field_path` is an output parameter
+ * owned by the caller that must be filled here. `type` is owned by the
+ * caller.
+ */
+static
+int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path,
+               struct bt_ctf_field_type *type, int src_index)
+{
+       int ret = 0;
+       GList *cur_ptoken = ptokens;
+       bool first_level_done = false;
+
+       /* Get our own reference */
+       bt_get(type);
+
+       /* Locate target */
+       while (cur_ptoken) {
+               int child_index;
+               struct bt_ctf_field_type *child_type;
+               const char *field_name = ptoken_get_string(cur_ptoken);
+               enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
+
+               /* Find to which index corresponds the current path token */
+               if (type_id == CTF_TYPE_ARRAY || type_id == CTF_TYPE_SEQUENCE) {
+                       child_index = -1;
+               } else {
+                       child_index = bt_ctf_field_type_get_field_index(type,
+                               field_name);
+                       if (child_index < 0) {
+                               /*
+                                * Error: field name does not exist or
+                                * wrong current type.
+                                */
+                               _printf_error("Cannot get index of field type named \"%s\"\n",
+                                       field_name);
+                               ret = -1;
+                               goto end;
+                       } else if (child_index > src_index &&
+                                       !first_level_done) {
+                               _printf_error("Child type is located after source index (%d)\n",
+                                       src_index);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       /* Next path token */
+                       cur_ptoken = g_list_next(cur_ptoken);
+                       first_level_done = true;
+               }
+
+               /* Create new field path entry */
+               g_array_append_val(field_path->path_indexes, child_index);
+
+               /* Get child field type */
+               child_type = bt_ctf_field_type_get_field_at_index(type,
+                       child_index);
+               if (!child_type) {
+                       _printf_error("Cannot get child type at index %d (field \"%s\")\n",
+                               child_index, field_name);
+                       ret = -1;
+                       goto end;
+               }
+
+               /* Move child type to current type */
+               BT_MOVE(type, child_type);
+       }
+
+end:
+       bt_put(type);
+       return ret;
+}
+
+/*
+ * Converts a known absolute path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `ptokens` is owned by the caller. `field_path` is an output parameter
+ * owned by the caller that must be filled here.
+ */
+static
+int absolute_ptokens_to_field_path(GList *ptokens,
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       GList *cur_ptoken;
+       struct bt_ctf_field_type *type;
+
+       /* Skip absolute path tokens */
+       cur_ptoken = g_list_nth(ptokens,
+               absolute_path_prefix_ptoken_counts[field_path->root]);
+
+       /* Start with root type */
+       type = get_type_from_ctx(ctx, field_path->root);
+       if (!type) {
+               /* Error: root type is not available */
+               _printf_error("Root type with node type %d is not available\n",
+                       field_path->root);
+               ret = -1;
+               goto end;
+       }
+
+       /* Locate target */
+       ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX);
+
+end:
+       return ret;
+}
+
+/*
+ * Converts a known relative path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `ptokens` is owned by the caller. `field_path` is an output parameter
+ * owned by the caller that must be filled here.
+ */
+static
+int relative_ptokens_to_field_path(GList *ptokens,
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       int parent_pos_in_stack;
+       struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create();
+
+       if (!tail_field_path) {
+               _printf_error("Cannot create field path\n");
+               ret = -1;
+               goto end;
+       }
+
+       parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1;
+
+       while (parent_pos_in_stack >= 0) {
+               struct bt_ctf_field_type *parent_type =
+                       type_stack_at(ctx->type_stack,
+                               parent_pos_in_stack)->type;
+               int cur_index = type_stack_at(ctx->type_stack,
+                       parent_pos_in_stack)->index;
+
+               /* Locate target from current parent type */
+               ret = ptokens_to_field_path(ptokens, tail_field_path,
+                       parent_type, cur_index);
+               if (ret) {
+                       /* Not found... yet */
+                       bt_ctf_field_path_clear(tail_field_path);
+               } else {
+                       /* Found: stitch tail field path to head field path */
+                       int i = 0;
+                       int tail_field_path_len =
+                               tail_field_path->path_indexes->len;
+
+                       while (true) {
+                               struct bt_ctf_field_type *cur_type =
+                                       type_stack_at(ctx->type_stack, i)->type;
+                               int index = type_stack_at(
+                                       ctx->type_stack, i)->index;
+
+                               if (cur_type == parent_type) {
+                                       break;
+                               }
+
+                               g_array_append_val(field_path->path_indexes,
+                                       index);
+                               i++;
+                       }
+
+                       for (i = 0; i < tail_field_path_len; i++) {
+                               int index = g_array_index(
+                                       tail_field_path->path_indexes,
+                                       int, i);
+
+                               g_array_append_val(field_path->path_indexes,
+                                       index);
+                       }
+                       break;
+               }
+
+               parent_pos_in_stack--;
+       }
+
+       if (parent_pos_in_stack < 0) {
+               /* Not found: look in previous scopes */
+               field_path->root--;
+
+               while (field_path->root >= CTF_NODE_TRACE_PACKET_HEADER) {
+                       struct bt_ctf_field_type *root_type;
+                       bt_ctf_field_path_clear(field_path);
+
+                       root_type = get_type_from_ctx(ctx, field_path->root);
+                       if (!root_type) {
+                               field_path->root--;
+                               continue;
+                       }
+
+                       /* Locate target in previous scope */
+                       ret = ptokens_to_field_path(ptokens, field_path,
+                               root_type, INT_MAX);
+                       if (ret) {
+                               /* Not found yet */
+                               field_path->root--;
+                               continue;
+                       }
+
+                       /* Found */
+                       break;
+               }
+       }
+
+end:
+       bt_ctf_field_path_destroy(tail_field_path);
+       return ret;
+}
+
+/*
+ * Converts a path string to a field path object within the resolving
+ * context `ctx`.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr,
+               struct resolve_context *ctx)
+{
+       int ret;
+       enum bt_ctf_node root_node;
+       GList *ptokens = NULL;
+       struct bt_ctf_field_path *field_path = NULL;
+
+       /* Create field path */
+       field_path = bt_ctf_field_path_create();
+       if (!field_path) {
+               _printf_error("Cannot create field path\n");
+               ret = -1;
+               goto end;
+       }
+
+       /* Convert path string to path tokens */
+       ptokens = pathstr_to_ptokens(pathstr);
+       if (!ptokens) {
+               _printf_error("Cannot convert path string \"%s\" to path tokens\n",
+                       pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       /* Absolute or relative path? */
+       root_node = get_root_node_from_absolute_pathstr(pathstr);
+
+       if (root_node == CTF_NODE_UNKNOWN) {
+               /* Relative path: start with current root node */
+               field_path->root = ctx->root_node;
+               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       _printf_error("Cannot get relative field path of path string \"%s\"\n",
+                               pathstr);
+                       _printf_error("  Starting at root node %d, finished at root node %d\n",
+                               ctx->root_node, field_path->root);
+                       goto end;
+               }
+       } else if (root_node == CTF_NODE_ENV) {
+               _printf_error("Sequence field types referring the trace environment are not supported as of this version\n");
+               ret = -1;
+               goto end;
+       } else {
+               /* Absolute path: use found root node */
+               field_path->root = root_node;
+               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       _printf_error("Cannot get absolute field path of path string \"%s\"\n",
+                               pathstr);
+                       _printf_error("  Looking in root node %d\n", root_node);
+                       goto end;
+               }
+       }
+
+end:
+       if (ret) {
+               bt_ctf_field_path_destroy(field_path);
+               field_path = NULL;
+       }
+
+       ptokens_destroy(ptokens);
+
+       return field_path;
+}
+
+/*
+ * Retrieves a field type by following the field path `field_path` in
+ * the resolving context `ctx`.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+struct bt_ctf_field_type *field_path_to_field_type(
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int i;
+       struct bt_ctf_field_type *type;
+
+       /* Start with root type */
+       type = get_type_from_ctx(ctx, field_path->root);
+       bt_get(type);
+       if (!type) {
+               /* Error: root type is not available */
+               _printf_error("Root type with node type %d is not available\n",
+                       field_path->root);
+               goto error;
+       }
+
+       /* Locate target */
+       for (i = 0; i < field_path->path_indexes->len; i++) {
+               struct bt_ctf_field_type *child_type;
+               int child_index =
+                       g_array_index(field_path->path_indexes, int, i);
+
+               /* Get child field type */
+               child_type = bt_ctf_field_type_get_field_at_index(type,
+                       child_index);
+               if (!child_type) {
+                       _printf_error("Cannot get field type field at index %d\n",
+                               child_index);
+                       goto error;
+               }
+
+               /* Move child type to current type */
+               BT_MOVE(type, child_type);
+       }
+
+       return type;
+
+error:
+       BT_PUT(type);
+       return type;
+}
+
+/*
+ * Returns the equivalent field path object of the context type stack.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
+{
+       int i;
+       struct bt_ctf_field_path *field_path;
+
+       /* Create field path */
+       field_path = bt_ctf_field_path_create();
+       if (!field_path) {
+               _printf_error("Cannot create field path\n");
+               goto error;
+       }
+
+       field_path->root = ctx->root_node;
+
+       for (i = 0; i < type_stack_size(ctx->type_stack); i++) {
+               struct type_stack_frame *frame;
+
+               frame = type_stack_at(ctx->type_stack, i);
+               g_array_append_val(field_path->path_indexes, frame->index);
+       }
+
+       return field_path;
+
+error:
+       bt_ctf_field_path_destroy(field_path);
+       return NULL;
+}
+
+/*
+ * Returns the lowest common ancestor of two field path objects
+ * having the same root scope.
+ *
+ * `field_path1` and `field_path2` are owned by the caller.
+ */
+int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1,
+               struct bt_ctf_field_path *field_path2)
+{
+       int lca_index = 0;
+       int field_path1_len, field_path2_len;
+
+       /*
+        * Start from both roots and find the first mismatch.
+        */
+       assert(field_path1->root == field_path2->root);
+       field_path1_len = field_path1->path_indexes->len;
+       field_path2_len = field_path2->path_indexes->len;
+
+       while (true) {
+               int target_index, ctx_index;
+
+               if (lca_index == field_path2_len ||
+                               lca_index == field_path1_len) {
+                       /*
+                        * This means that both field paths never split.
+                        * This is invalid because the target cannot be
+                        * an ancestor of the source.
+                        */
+                       _printf_error("In source and target: one is an ancestor of the other\n");
+                       lca_index = -1;
+                       break;
+               }
+
+               target_index = g_array_index(field_path1->path_indexes, int,
+                       lca_index);
+               ctx_index = g_array_index(field_path2->path_indexes, int,
+                       lca_index);
+
+               if (target_index != ctx_index) {
+                       /* LCA index is the previous */
+                       break;
+               }
+
+               lca_index++;
+       }
+
+       return lca_index;
+}
+
+/*
+ * Validates a target field path.
+ *
+ * `target_field_path` and `target_type` are owned by the caller.
+ */
+static
+int validate_target_field_path(struct bt_ctf_field_path *target_field_path,
+               struct bt_ctf_field_type *target_type,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       struct bt_ctf_field_path *ctx_field_path;
+       int target_field_path_len = target_field_path->path_indexes->len;
+       int lca_index;
+       int ctx_cur_field_type_id;
+       int target_type_id;
+
+       /* Get context field path */
+       ctx_field_path = get_ctx_stack_field_path(ctx);
+       if (!ctx_field_path) {
+               _printf_error("Cannot get source field path\n");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Make sure the target is not a root.
+        */
+       if (target_field_path_len == 0) {
+               _printf_error("Target field path's length is 0 (targeting the root)\n");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Make sure the root of the target field path is not located
+        * after the context field path's root.
+        */
+       if (target_field_path->root > ctx_field_path->root) {
+               _printf_error("Target is located after source\n");
+               ret = -1;
+               goto end;
+       }
+
+       if (target_field_path->root == ctx_field_path->root) {
+               int target_index, ctx_index;
+
+               /*
+                * Find the index of the lowest common ancestor of both field
+                * paths.
+                */
+               lca_index = get_field_paths_lca_index(target_field_path,
+                       ctx_field_path);
+               if (lca_index < 0) {
+                       _printf_error("Cannot get least common ancestor\n");
+                       ret = -1;
+                       goto end;
+               }
+
+               /*
+                * Make sure the target field path is located before the
+                * context field path.
+                */
+               target_index = g_array_index(target_field_path->path_indexes,
+                       int, lca_index);
+               ctx_index = g_array_index(ctx_field_path->path_indexes,
+                       int, lca_index);
+
+               if (target_index >= ctx_index) {
+                       _printf_error("Target index (%d) is greater or equal to source index (%d) in LCA\n",
+                               target_index, ctx_index);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * Make sure the target type has the right type and properties.
+        */
+       ctx_cur_field_type_id = bt_ctf_field_type_get_type_id(
+               ctx->cur_field_type);
+       target_type_id = bt_ctf_field_type_get_type_id(target_type);
+
+       if (ctx_cur_field_type_id == CTF_TYPE_VARIANT) {
+               if (target_type_id != CTF_TYPE_ENUM) {
+                       _printf_error("Variant type's tag field type is not an enumeration\n");
+                       ret = -1;
+                       goto end;
+               }
+       } else if (ctx_cur_field_type_id == CTF_TYPE_SEQUENCE) {
+               if (target_type_id != CTF_TYPE_INTEGER ||
+                               bt_ctf_field_type_integer_get_signed(
+                                       target_type)) {
+                       _printf_error("Sequence type's length field type is not an unsigned integer\n");
+                       ret = -1;
+                       goto end;
+               }
+       } else {
+               assert(false);
+       }
+
+end:
+       bt_ctf_field_path_destroy(ctx_field_path);
+       return ret;
+}
+
+/*
+ * Resolves a variant or sequence field type `type`.
+ *
+ * `type` is owned by the caller.
+ */
+static
+int resolve_sequence_or_variant_type(struct bt_ctf_field_type *type,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       const char *pathstr;
+       int type_id = bt_ctf_field_type_get_type_id(type);
+       struct bt_ctf_field_path *target_field_path = NULL;
+       struct bt_ctf_field_type *target_type = NULL;
+
+       /* Get path string */
+       switch (type_id) {
+       case CTF_TYPE_SEQUENCE:
+               pathstr =
+                       bt_ctf_field_type_sequence_get_length_field_name(type);
+               break;
+       case CTF_TYPE_VARIANT:
+               pathstr =
+                       bt_ctf_field_type_variant_get_tag_name(type);
+               break;
+       default:
+               assert(false);
+       }
+
+       /* Get target field path out of path string */
+       target_field_path = pathstr_to_field_path(pathstr, ctx);
+       if (!target_field_path) {
+               _printf_error("Cannot get target field path for path string \"%s\"\n",
+                       pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       /* Get target field type */
+       target_type = field_path_to_field_type(target_field_path, ctx);
+       if (!target_type) {
+               _printf_error("Cannot get target field type for path string \"%s\"\n",
+                       pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       ret = validate_target_field_path(target_field_path, target_type, ctx);
+       if (ret) {
+               _printf_error("Invalid target field path for path string \"%s\"\n",
+                       pathstr);
+               goto end;
+       }
+
+       /* Set target field path and target field type */
+       if (type_id == CTF_TYPE_SEQUENCE) {
+               ret = bt_ctf_field_type_sequence_set_length_field_path(
+                       type, target_field_path);
+               if (ret) {
+                       _printf_error("Cannot set sequence field type's length field path\n");
+                       goto end;
+               }
+
+               target_field_path = NULL;
+       } else if (type_id == CTF_TYPE_VARIANT) {
+               ret = bt_ctf_field_type_variant_set_tag_field_path(
+                       type, target_field_path);
+               if (ret) {
+                       _printf_error("Cannot set variant field type's tag field path\n");
+                       goto end;
+               }
+
+               target_field_path = NULL;
+
+               ret = bt_ctf_field_type_variant_set_tag(type, target_type);
+               if (ret) {
+                       _printf_error("Cannot set variant field type's tag field type\n");
+                       goto end;
+               }
+       } else {
+               assert(false);
+       }
+
+end:
+       bt_ctf_field_path_destroy(target_field_path);
+       BT_PUT(target_type);
+       return ret;
+}
+
+/*
+ * Resolves a field type `type`.
+ *
+ * `type` is owned by the caller.
+ */
+static
+int resolve_type(struct bt_ctf_field_type *type, struct resolve_context *ctx)
+{
+       int ret = 0;
+       int type_id;
+
+       if (!type) {
+               /* Type is not available; still valid */
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_get_type_id(type);
+       ctx->cur_field_type = type;
+
+       /* Resolve sequence/variant field type */
+       switch (type_id) {
+       case CTF_TYPE_SEQUENCE:
+       case CTF_TYPE_VARIANT:
+               ret = resolve_sequence_or_variant_type(type, ctx);
+               if (ret) {
+                       _printf_error("Cannot resolve sequence or variant field type's length/tag\n");
+                       goto end;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* Recurse into compound types */
+       switch (type_id) {
+       case CTF_TYPE_STRUCT:
+       case CTF_TYPE_VARIANT:
+       case CTF_TYPE_SEQUENCE:
+       case CTF_TYPE_ARRAY:
+       {
+               int field_count, f_index;
+
+               ret = type_stack_push(ctx->type_stack, type);
+               if (ret) {
+                       _printf_error("Cannot push field type on type stack\n");
+                       _printf_error("  Stack size: %zu\n",
+                               type_stack_size(ctx->type_stack));
+                       goto end;
+               }
+
+               field_count = bt_ctf_field_type_get_field_count(type);
+               if (field_count < 0) {
+                       _printf_error("Cannot get field type field count\n");
+                       ret = field_count;
+                       goto end;
+               }
+
+               for (f_index = 0; f_index < field_count; f_index++) {
+                       struct bt_ctf_field_type *child_type =
+                               bt_ctf_field_type_get_field_at_index(type,
+                                       f_index);
+
+                       if (!child_type) {
+                               _printf_error("Cannot get field type field at index %d/%d\n",
+                                       f_index, field_count);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       if (type_id == CTF_TYPE_ARRAY ||
+                                       type_id == CTF_TYPE_SEQUENCE) {
+                               type_stack_peek(ctx->type_stack)->index = -1;
+                       } else {
+                               type_stack_peek(ctx->type_stack)->index =
+                                       f_index;
+                       }
+
+                       ret = resolve_type(child_type, ctx);
+                       BT_PUT(child_type);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               type_stack_pop(ctx->type_stack);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Resolves the root field type corresponding to the scope `root_scope`.
+ */
+static
+int resolve_root_type(enum ctf_type_id root_node, struct resolve_context *ctx)
+{
+       int ret;
+
+       assert(type_stack_size(ctx->type_stack) == 0);
+       ctx->root_node = root_node;
+       ret = resolve_type(get_type_from_ctx(ctx, root_node), ctx);
+       ctx->root_node = CTF_NODE_UNKNOWN;
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_resolve_types(
+               struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type,
+               struct bt_ctf_field_type *stream_event_ctx_type,
+               struct bt_ctf_field_type *event_context_type,
+               struct bt_ctf_field_type *event_payload_type,
+               enum bt_ctf_resolve_flag flags)
+{
+       int ret = 0;
+       struct resolve_context ctx = {
+               .environment = environment,
+               .scopes = {
+                       packet_header_type,
+                       packet_context_type,
+                       event_header_type,
+                       stream_event_ctx_type,
+                       event_context_type,
+                       event_payload_type,
+               },
+               .root_node = CTF_NODE_UNKNOWN,
+       };
+
+       /* Initialize type stack */
+       ctx.type_stack = type_stack_create();
+       if (!ctx.type_stack) {
+               printf_error("Cannot create type stack\n");
+               ret = -1;
+               goto end;
+       }
+
+       /* Resolve packet header type */
+       if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) {
+               ret = resolve_root_type(CTF_NODE_TRACE_PACKET_HEADER, &ctx);
+               if (ret) {
+                       _printf_error("Cannot resolve trace packet header type\n");
+                       goto end;
+               }
+       }
+
+       /* Resolve packet context type */
+       if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) {
+               ret = resolve_root_type(CTF_NODE_STREAM_PACKET_CONTEXT, &ctx);
+               if (ret) {
+                       _printf_error("Cannot resolve stream packet context type\n");
+                       goto end;
+               }
+       }
+
+       /* Resolve event header type */
+       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) {
+               ret = resolve_root_type(CTF_NODE_STREAM_EVENT_HEADER, &ctx);
+
+               if (ret) {
+                       _printf_error("Cannot resolve stream event header type\n");
+                       goto end;
+               }
+       }
+
+       /* Resolve stream event context type */
+       if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) {
+               ret = resolve_root_type(CTF_NODE_STREAM_EVENT_CONTEXT, &ctx);
+               if (ret) {
+                       _printf_error("Cannot resolve stream event context type\n");
+                       goto end;
+               }
+       }
+
+       /* Resolve event context type */
+       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) {
+               ret = resolve_root_type(CTF_NODE_EVENT_CONTEXT, &ctx);
+               if (ret) {
+                       _printf_error("Cannot resolve event context type\n");
+                       goto end;
+               }
+       }
+
+       /* Resolve event payload type */
+       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) {
+               ret = resolve_root_type(CTF_NODE_EVENT_FIELDS, &ctx);
+               if (ret) {
+                       _printf_error("Cannot resolve event payload type\n");
+                       goto end;
+               }
+       }
+
+end:
+       type_stack_destroy(ctx.type_stack);
+
+       return ret;
+}
index 14f7a6189573a748651780d68d21b3e5dbd9d8e7..b5e7e79dca12b2f7330a68ee838101a1da6f4b89 100644 (file)
@@ -34,7 +34,7 @@
 #include <babeltrace/ctf-ir/event-fields-internal.h>
 #include <babeltrace/ctf-writer/stream.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
-#include <babeltrace/ctf-ir/visitor-internal.h>
+#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/ctf-writer/functor-internal.h>
 #include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/ref.h>
@@ -318,6 +318,15 @@ int bt_ctf_stream_class_add_event_class(
        int64_t event_id;
        struct bt_ctf_trace *trace = NULL;
        struct bt_ctf_stream_class *old_stream_class = NULL;
+       struct bt_ctf_validation_output validation_output = { 0 };
+       struct bt_ctf_field_type *packet_header_type = NULL;
+       struct bt_ctf_field_type *packet_context_type = NULL;
+       struct bt_ctf_field_type *event_header_type = NULL;
+       struct bt_ctf_field_type *stream_event_ctx_type = NULL;
+       struct bt_ctf_field_type *event_context_type = NULL;
+       struct bt_ctf_field_type *event_payload_type = NULL;
+       const enum bt_ctf_validation_flag validation_flags =
+               BT_CTF_VALIDATION_FLAG_EVENT;
 
        if (!stream_class || !event_class) {
                ret = -1;
@@ -333,31 +342,72 @@ int bt_ctf_stream_class_add_event_class(
                goto end;
        }
 
-       old_stream_class = (struct bt_ctf_stream_class *) bt_object_get_parent(
-               event_class);
+       old_stream_class = bt_ctf_event_class_get_stream_class(event_class);
        if (old_stream_class) {
                /* Event class is already associated to a stream class. */
                ret = -1;
                goto end;
        }
 
-       /*
-        * Resolve the event's sequence length and variant tags if the
-        * stream is already associated with a trace. Otherwise, this
-        * validation will be performed once the stream is registered
-        * to a trace.
-        */
-       trace = (struct bt_ctf_trace *) bt_object_get_parent(
-               stream_class);
+       trace = bt_ctf_stream_class_get_trace(stream_class);
        if (trace) {
-               ret = bt_ctf_event_class_resolve_types(event_class,
-                       trace, stream_class);
+               /*
+                * If the stream class is associated with a trace, then
+                * both those objects are frozen. Also, this event class
+                * is about to be frozen.
+                *
+                * Therefore the event class must be validated here.
+                * The trace and stream class should be valid at this
+                * point.
+                */
+               assert(trace->valid);
+               assert(stream_class->valid);
+               packet_header_type =
+                       bt_ctf_trace_get_packet_header_type(trace);
+               packet_context_type =
+                       bt_ctf_stream_class_get_packet_context_type(
+                               stream_class);
+               event_header_type =
+                       bt_ctf_stream_class_get_event_header_type(stream_class);
+               stream_event_ctx_type =
+                       bt_ctf_stream_class_get_event_context_type(
+                               stream_class);
+               event_context_type =
+                       bt_ctf_event_class_get_context_type(event_class);
+               event_payload_type =
+                       bt_ctf_event_class_get_payload_type(event_class);
+               ret = bt_ctf_validate_class_types(
+                       trace->environment, packet_header_type,
+                       packet_context_type, event_header_type,
+                       stream_event_ctx_type, event_context_type,
+                       event_payload_type, trace->valid,
+                       stream_class->valid, event_class->valid,
+                       &validation_output, validation_flags);
+               BT_PUT(packet_header_type);
+               BT_PUT(packet_context_type);
+               BT_PUT(event_header_type);
+               BT_PUT(stream_event_ctx_type);
+               BT_PUT(event_context_type);
+               BT_PUT(event_payload_type);
+
                if (ret) {
+                       /*
+                        * This means something went wrong during the
+                        * validation process, not that the objects are
+                        * invalid.
+                        */
+                       goto end;
+               }
+
+               if ((validation_output.valid_flags & validation_flags) !=
+                               validation_flags) {
+                       /* Invalid event class */
+                       ret = -1;
                        goto end;
                }
        }
 
-       /* Only set an event id if none was explicitly set before */
+       /* Only set an event ID if none was explicitly set before */
        event_id = bt_ctf_event_class_get_id(event_class);
        if (event_id < 0) {
                if (bt_ctf_event_class_set_id(event_class,
@@ -373,7 +423,29 @@ int bt_ctf_stream_class_add_event_class(
        }
 
        bt_object_set_parent(event_class, stream_class);
+
+       if (trace) {
+               /*
+                * At this point we know that the function will be
+                * successful. Therefore we can replace the event
+                * class's field types with what's in the validation
+                * output structure and mark this event class as valid.
+                */
+               bt_ctf_validation_replace_types(NULL, NULL, event_class,
+                       &validation_output, validation_flags);
+               event_class->valid = 1;
+
+               /*
+                * Put what was not moved in
+                * bt_ctf_validation_replace_types().
+                */
+               bt_ctf_validation_output_put_types(&validation_output);
+       }
+
+       /* Add to the event classes of the stream class */
        g_ptr_array_add(stream_class->event_classes, event_class);
+
+       /* Freeze the event class */
        bt_ctf_event_class_freeze(event_class);
 
        if (stream_class->byte_order) {
@@ -382,14 +454,23 @@ int bt_ctf_stream_class_add_event_class(
                 * when the stream class was added to a trace.
                 *
                 * If not set here, this will be set when the stream
-                * classe will be added to a trace.
+                * class is added to a trace.
                 */
                bt_ctf_event_class_set_native_byte_order(event_class,
                        stream_class->byte_order);
        }
+
 end:
        BT_PUT(trace);
        BT_PUT(old_stream_class);
+       bt_ctf_validation_output_put_types(&validation_output);
+       assert(!packet_header_type);
+       assert(!packet_context_type);
+       assert(!event_header_type);
+       assert(!stream_event_ctx_type);
+       assert(!event_context_type);
+       assert(!event_payload_type);
+
        return ret;
 }
 
index 717925761336bfef2ada9b1f5b2287ff3f3fdd3e..cc5548b548033345239bd1e4c0234e2c116f3460 100644 (file)
@@ -584,7 +584,8 @@ int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
        }
 
        field_type = bt_ctf_field_get_type(field);
-       if (field_type != stream->stream_class->packet_context_type) {
+       if (bt_ctf_field_type_compare(field_type,
+                       stream->stream_class->packet_context_type)) {
                ret = -1;
                goto end;
        }
@@ -626,7 +627,8 @@ int bt_ctf_stream_set_event_context(struct bt_ctf_stream *stream,
        }
 
        field_type = bt_ctf_field_get_type(field);
-       if (field_type != stream->stream_class->event_context_type) {
+       if (bt_ctf_field_type_compare(field_type,
+                       stream->stream_class->event_context_type)) {
                ret = -1;
                goto end;
        }
@@ -670,7 +672,7 @@ int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
 
        trace = (struct bt_ctf_trace *) bt_object_get_parent(stream);
        field_type = bt_ctf_field_get_type(field);
-       if (field_type != trace->packet_header_type) {
+       if (bt_ctf_field_type_compare(field_type, trace->packet_header_type)) {
                ret = -1;
                goto end;
        }
index 21718ac9dd82f2e97638c903c630e214dbd1b924..dce9474baa787f33faea3c797880e7f67ebb4757 100644 (file)
 #include <babeltrace/ctf-ir/clock-internal.h>
 #include <babeltrace/ctf-ir/stream-internal.h>
 #include <babeltrace/ctf-ir/stream-class-internal.h>
+#include <babeltrace/ctf-ir/event-internal.h>
 #include <babeltrace/ctf-writer/functor-internal.h>
 #include <babeltrace/ctf-ir/event-types-internal.h>
 #include <babeltrace/ctf-ir/attributes-internal.h>
-#include <babeltrace/ctf-ir/visitor-internal.h>
+#include <babeltrace/ctf-ir/validation-internal.h>
 #include <babeltrace/ctf-ir/utils.h>
 #include <babeltrace/compiler.h>
 #include <babeltrace/values.h>
@@ -48,7 +49,7 @@ void bt_ctf_trace_destroy(struct bt_object *obj);
 static
 int init_trace_packet_header(struct bt_ctf_trace *trace);
 static
-int bt_ctf_trace_freeze(struct bt_ctf_trace *trace);
+void bt_ctf_trace_freeze(struct bt_ctf_trace *trace);
 
 static
 const unsigned int field_type_aliases_alignments[] = {
@@ -421,25 +422,132 @@ int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
 {
        int ret, i;
        int64_t stream_id;
+       struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
+       struct bt_ctf_validation_output *ec_validation_outputs = NULL;
+       const enum bt_ctf_validation_flag trace_sc_validation_flags =
+               BT_CTF_VALIDATION_FLAG_TRACE |
+               BT_CTF_VALIDATION_FLAG_STREAM;
+       const enum bt_ctf_validation_flag ec_validation_flags =
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_field_type *packet_header_type = NULL;
+       struct bt_ctf_field_type *packet_context_type = NULL;
+       struct bt_ctf_field_type *event_header_type = NULL;
+       struct bt_ctf_field_type *stream_event_ctx_type = NULL;
+       int event_class_count;
 
        if (!trace || !stream_class) {
                ret = -1;
                goto end;
        }
 
+       event_class_count =
+               bt_ctf_stream_class_get_event_class_count(stream_class);
+       assert(event_class_count >= 0);
+
+       /* Check for duplicate stream classes */
        for (i = 0; i < trace->stream_classes->len; i++) {
                if (trace->stream_classes->pdata[i] == stream_class) {
-                       /* Stream already registered to the trace */
+                       /* Stream class already registered to the trace */
                        ret = -1;
                        goto end;
                }
        }
 
-       ret = bt_ctf_stream_class_resolve_types(stream_class, trace);
+       /*
+        * We're about to freeze both the trace and the stream class.
+        * Also, each event class contained in this stream class are
+        * already frozen.
+        *
+        * This trace, this stream class, and all its event classes
+        * should be valid at this point.
+        *
+        * Validate trace and stream class first, then each event
+        * class of this stream class can be validated individually.
+        */
+       packet_header_type =
+               bt_ctf_trace_get_packet_header_type(trace);
+       packet_context_type =
+               bt_ctf_stream_class_get_packet_context_type(stream_class);
+       event_header_type =
+               bt_ctf_stream_class_get_event_header_type(stream_class);
+       stream_event_ctx_type =
+               bt_ctf_stream_class_get_event_context_type(stream_class);
+       ret = bt_ctf_validate_class_types(trace->environment,
+               packet_header_type, packet_context_type, event_header_type,
+               stream_event_ctx_type, NULL, NULL, trace->valid,
+               stream_class->valid, 1, &trace_sc_validation_output,
+               trace_sc_validation_flags);
+       BT_PUT(packet_header_type);
+       BT_PUT(packet_context_type);
+       BT_PUT(event_header_type);
+       BT_PUT(stream_event_ctx_type);
+
        if (ret) {
+               /*
+                * This means something went wrong during the validation
+                * process, not that the objects are invalid.
+                */
                goto end;
        }
 
+       if ((trace_sc_validation_output.valid_flags &
+                       trace_sc_validation_flags) !=
+                       trace_sc_validation_flags) {
+               /* Invalid trace/stream class */
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class_count > 0) {
+               ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
+                       event_class_count);
+               if (!ec_validation_outputs) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /* Validate each event class individually */
+       for (i = 0; i < event_class_count; ++i) {
+               struct bt_ctf_event_class *event_class =
+                       bt_ctf_stream_class_get_event_class(stream_class, i);
+               struct bt_ctf_field_type *event_context_type = NULL;
+               struct bt_ctf_field_type *event_payload_type = NULL;
+
+               event_context_type =
+                       bt_ctf_event_class_get_context_type(event_class);
+               event_payload_type =
+                       bt_ctf_event_class_get_payload_type(event_class);
+
+               /*
+                * It is important to use the field types returned by
+                * the previous trace and stream class validation here
+                * because copies could have been made.
+                */
+               ret = bt_ctf_validate_class_types(trace->environment,
+                       trace_sc_validation_output.packet_header_type,
+                       trace_sc_validation_output.packet_context_type,
+                       trace_sc_validation_output.event_header_type,
+                       trace_sc_validation_output.stream_event_ctx_type,
+                       event_context_type, event_payload_type,
+                       1, 1, event_class->valid, &ec_validation_outputs[i],
+                       ec_validation_flags);
+               BT_PUT(event_context_type);
+               BT_PUT(event_payload_type);
+               BT_PUT(event_class);
+
+               if (ret) {
+                       goto end;
+               }
+
+               if ((ec_validation_outputs[i].valid_flags &
+                               ec_validation_flags) != ec_validation_flags) {
+                       /* Invalid event class */
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        stream_id = bt_ctf_stream_class_get_id(stream_class);
        if (stream_id < 0) {
                stream_id = trace->next_stream_id++;
@@ -466,8 +574,40 @@ int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
        g_ptr_array_add(trace->stream_classes, stream_class);
 
        /*
-        * Freeze the trace and its packet header.
-        *
+        * At this point we know that the function will be successful.
+        * Therefore we can replace the trace and stream class field
+        * types with what's in their validation output structure and
+        * mark them as valid. We can also replace the field types of
+        * all the event classes of the stream class and mark them as
+        * valid.
+        */
+       bt_ctf_validation_replace_types(trace, stream_class, NULL,
+               &trace_sc_validation_output, trace_sc_validation_flags);
+       trace->valid = 1;
+       stream_class->valid = 1;
+
+       /*
+        * Put what was not moved in bt_ctf_validation_replace_types().
+        */
+       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
+
+       for (i = 0; i < event_class_count; ++i) {
+               struct bt_ctf_event_class *event_class =
+                       bt_ctf_stream_class_get_event_class(stream_class, i);
+
+               bt_ctf_validation_replace_types(NULL, NULL, event_class,
+                       &ec_validation_outputs[i], ec_validation_flags);
+               event_class->valid = 1;
+               BT_PUT(event_class);
+
+               /*
+                * Put what was not moved in
+                * bt_ctf_validation_replace_types().
+                */
+               bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
+       }
+
+       /*
         * All field type byte orders set as "native" byte ordering can now be
         * safely set to trace's own endianness, including the stream class'.
         */
@@ -475,14 +615,31 @@ int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
                trace->byte_order);
        bt_ctf_stream_class_set_byte_order(stream_class, trace->byte_order);
 
+       /*
+        * Freeze the trace and the stream class.
+        */
        bt_ctf_stream_class_freeze(stream_class);
-       if (!trace->frozen) {
-               ret = bt_ctf_trace_freeze(trace);
-       }
+       bt_ctf_trace_freeze(trace);
+
 end:
        if (ret) {
                bt_object_set_parent(stream_class, NULL);
+
+               if (ec_validation_outputs) {
+                       for (i = 0; i < event_class_count; ++i) {
+                               bt_ctf_validation_output_put_types(
+                                       &ec_validation_outputs[i]);
+                       }
+               }
        }
+
+       g_free(ec_validation_outputs);
+       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
+       assert(!packet_header_type);
+       assert(!packet_context_type);
+       assert(!event_header_type);
+       assert(!stream_event_ctx_type);
+
        return ret;
 }
 
@@ -887,19 +1044,11 @@ end:
 }
 
 static
-int bt_ctf_trace_freeze(struct bt_ctf_trace *trace)
+void bt_ctf_trace_freeze(struct bt_ctf_trace *trace)
 {
-       int ret = 0;
-
-       ret = bt_ctf_trace_resolve_types(trace);
-       if (ret) {
-               goto end;
-       }
-
+       bt_ctf_field_type_freeze(trace->packet_header_type);
        bt_ctf_attributes_freeze(trace->environment);
        trace->frozen = 1;
-end:
-       return ret;
 }
 
 static
diff --git a/formats/ctf/ir/validation.c b/formats/ctf/ir/validation.c
new file mode 100644 (file)
index 0000000..aabcd9b
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * validation.c
+ *
+ * Babeltrace - CTF IR: Validation of trace, stream class, and event class
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/validation-internal.h>
+#include <babeltrace/ctf-ir/resolve-internal.h>
+#include <babeltrace/ctf-ir/trace-internal.h>
+#include <babeltrace/ctf-ir/stream-class-internal.h>
+#include <babeltrace/ctf-ir/event-internal.h>
+#include <babeltrace/ctf-ir/event-types-internal.h>
+#include <babeltrace/values.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ref.h>
+
+#define _printf_error(fmt, args...) \
+       printf_verbose("[validation] " fmt, ## args)
+
+/*
+ * This function resolves and validates the field types of an event
+ * class. Only `event_context_type` and `event_payload_type` are
+ * resolved and validated; the other field types are used as eventual
+ * resolving targets.
+ *
+ * All parameters are owned by the caller.
+ */
+static
+int validate_event_class_types(struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type,
+               struct bt_ctf_field_type *stream_event_ctx_type,
+               struct bt_ctf_field_type *event_context_type,
+               struct bt_ctf_field_type *event_payload_type)
+{
+       int ret = 0;
+
+       /* Resolve sequence type lengths and variant type tags first */
+       ret = bt_ctf_resolve_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               event_context_type, event_payload_type,
+               BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT |
+               BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD);
+       if (ret) {
+               _printf_error("Cannot resolve event class types\n");
+               goto end;
+       }
+
+       /* Validate field types individually */
+       if (event_context_type) {
+               ret = bt_ctf_field_type_validate(event_context_type);
+               if (ret) {
+                       _printf_error("Invalid event context type\n");
+                       goto end;
+               }
+       }
+
+       if (event_payload_type) {
+               ret = bt_ctf_field_type_validate(event_payload_type);
+               if (ret) {
+                       _printf_error("Invalid event payload type\n");
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function resolves and validates the field types of a stream
+ * class. Only `packet_context_type`, `event_header_type`, and
+ * `stream_event_ctx_type` are resolved and validated; the other field
+ * type is used as an eventual resolving target.
+ *
+ * All parameters are owned by the caller.
+ */
+static
+int validate_stream_class_types(struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type,
+               struct bt_ctf_field_type *stream_event_ctx_type)
+{
+       int ret = 0;
+
+       /* Resolve sequence type lengths and variant type tags first */
+       ret = bt_ctf_resolve_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               NULL, NULL,
+               BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT |
+               BT_CTF_RESOLVE_FLAG_EVENT_HEADER |
+               BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX);
+       if (ret) {
+               _printf_error("Cannot resolve stream class types\n");
+               goto end;
+       }
+
+       /* Validate field types individually */
+       if (packet_context_type) {
+               ret = bt_ctf_field_type_validate(packet_context_type);
+               if (ret) {
+                       _printf_error("Invalid stream packet context type\n");
+                       goto end;
+               }
+       }
+
+       if (event_header_type) {
+               ret = bt_ctf_field_type_validate(event_header_type);
+               if (ret) {
+                       _printf_error("Invalid stream event header type\n");
+                       goto end;
+               }
+       }
+
+       if (stream_event_ctx_type) {
+               ret = bt_ctf_field_type_validate(
+                       stream_event_ctx_type);
+               if (ret) {
+                       _printf_error("Invalid stream event context type\n");
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function resolves and validates the field types of a trace.
+ *
+ * All parameters are owned by the caller.
+ */
+static
+int validate_trace_types(struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type)
+{
+       int ret = 0;
+
+       /* Resolve sequence type lengths and variant type tags first */
+       ret = bt_ctf_resolve_types(environment, packet_header_type,
+               NULL, NULL, NULL, NULL, NULL,
+               BT_CTF_RESOLVE_FLAG_PACKET_HEADER);
+       if (ret) {
+               _printf_error("Cannot resolve trace types\n");
+               goto end;
+       }
+
+       /* Validate field types individually */
+       if (packet_header_type) {
+               ret = bt_ctf_field_type_validate(packet_header_type);
+               if (ret) {
+                       _printf_error("Invalid trace packet header type\n");
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Checks whether or not `field_type` contains a variant or a sequence
+ * field type, recursively. Returns 1 if it's the case.
+ *
+ * `field_type` is owned by the caller.
+ */
+static
+int field_type_contains_sequence_or_variant_ft(struct bt_ctf_field_type *type)
+{
+       int ret = 0;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
+
+       switch (type_id) {
+       case CTF_TYPE_SEQUENCE:
+       case CTF_TYPE_VARIANT:
+               ret = 1;
+               goto end;
+       case CTF_TYPE_ARRAY:
+       case CTF_TYPE_STRUCT:
+       {
+               int i;
+               int field_count = bt_ctf_field_type_get_field_count(type);
+
+               if (field_count < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               for (i = 0; i < field_count; ++i) {
+                       struct bt_ctf_field_type *child_type =
+                               bt_ctf_field_type_get_field_at_index(type, i);
+
+                       ret = field_type_contains_sequence_or_variant_ft(
+                               child_type);
+                       BT_PUT(child_type);
+                       if (ret != 0) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_validate_class_types(struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type,
+               struct bt_ctf_field_type *stream_event_ctx_type,
+               struct bt_ctf_field_type *event_context_type,
+               struct bt_ctf_field_type *event_payload_type,
+               int trace_valid, int stream_class_valid, int event_class_valid,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag validate_flags)
+{
+       int ret = 0;
+       int contains_seq_var;
+       int valid_ret;
+
+       /* Clean output values */
+       memset(output, 0, sizeof(*output));
+
+       /* Set initial valid flags according to valid parameters */
+       if (trace_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE;
+       }
+
+       if (stream_class_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
+       }
+
+       if (event_class_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
+       }
+
+       /* Own the type parameters */
+       bt_get(packet_header_type);
+       bt_get(packet_context_type);
+       bt_get(event_header_type);
+       bt_get(stream_event_ctx_type);
+       bt_get(event_context_type);
+       bt_get(event_payload_type);
+
+       /* Validate trace */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) {
+               struct bt_ctf_field_type *packet_header_type_copy = NULL;
+
+               /* Create field type copies */
+               if (packet_header_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       packet_header_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               packet_header_type_copy = packet_header_type;
+                               bt_get(packet_header_type_copy);
+                               goto skip_packet_header_type_copy;
+                       }
+
+                       packet_header_type_copy =
+                               bt_ctf_field_type_copy(packet_header_type);
+                       if (!packet_header_type_copy) {
+                               ret = -1;
+                               _printf_error("Cannot copy packet header type\n");
+                               goto error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_freeze(packet_header_type_copy);
+               }
+
+skip_packet_header_type_copy:
+               /* Put original reference and move copy */
+               BT_MOVE(packet_header_type, packet_header_type_copy);
+
+               /* Validate trace field types */
+               valid_ret = validate_trace_types(environment,
+                       packet_header_type);
+               if (!valid_ret) {
+                       /* Trace is valid */
+                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE;
+               }
+       }
+
+       /* Validate stream class */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) &&
+                       !stream_class_valid) {
+               struct bt_ctf_field_type *packet_context_type_copy = NULL;
+               struct bt_ctf_field_type *event_header_type_copy = NULL;
+               struct bt_ctf_field_type *stream_event_ctx_type_copy = NULL;
+
+               if (packet_context_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       packet_context_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               packet_context_type_copy = packet_context_type;
+                               bt_get(packet_context_type_copy);
+                               goto skip_packet_context_type_copy;
+                       }
+
+                       packet_context_type_copy =
+                               bt_ctf_field_type_copy(packet_context_type);
+                       if (!packet_context_type_copy) {
+                               _printf_error("Cannot copy packet context type\n");
+                               goto sc_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_freeze(packet_context_type_copy);
+               }
+
+skip_packet_context_type_copy:
+               if (event_header_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       event_header_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               event_header_type_copy = event_header_type;
+                               bt_get(event_header_type_copy);
+                               goto skip_event_header_type_copy;
+                       }
+
+                       event_header_type_copy =
+                               bt_ctf_field_type_copy(event_header_type);
+                       if (!event_header_type_copy) {
+                               _printf_error("Cannot copy event header type\n");
+                               goto sc_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_freeze(event_header_type_copy);
+               }
+
+skip_event_header_type_copy:
+               if (stream_event_ctx_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       stream_event_ctx_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               stream_event_ctx_type_copy =
+                                       stream_event_ctx_type;
+                               bt_get(stream_event_ctx_type_copy);
+                               goto skip_stream_event_ctx_type_copy;
+                       }
+
+                       stream_event_ctx_type_copy =
+                               bt_ctf_field_type_copy(stream_event_ctx_type);
+                       if (!stream_event_ctx_type_copy) {
+                               _printf_error("Cannot copy stream event context type\n");
+                               goto sc_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_freeze(stream_event_ctx_type_copy);
+               }
+
+skip_stream_event_ctx_type_copy:
+               /* Put original references and move copies */
+               BT_MOVE(packet_context_type, packet_context_type_copy);
+               BT_MOVE(event_header_type, event_header_type_copy);
+               BT_MOVE(stream_event_ctx_type, stream_event_ctx_type_copy);
+
+               /* Validate stream class field types */
+               valid_ret = validate_stream_class_types(environment,
+                       packet_header_type, packet_context_type,
+                       event_header_type, stream_event_ctx_type);
+               if (!valid_ret) {
+                       /* Stream class is valid */
+                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
+               }
+
+               goto sc_validation_done;
+
+sc_validation_error:
+               BT_PUT(packet_context_type_copy);
+               BT_PUT(event_header_type_copy);
+               BT_PUT(stream_event_ctx_type_copy);
+               ret = -1;
+               goto error;
+       }
+
+sc_validation_done:
+       /* Validate event class */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) &&
+                       !event_class_valid) {
+               struct bt_ctf_field_type *event_context_type_copy = NULL;
+               struct bt_ctf_field_type *event_payload_type_copy = NULL;
+
+               if (event_context_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       event_context_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               event_context_type_copy = event_context_type;
+                               bt_get(event_context_type_copy);
+                               goto skip_event_context_type_copy;
+                       }
+
+                       event_context_type_copy =
+                               bt_ctf_field_type_copy(event_context_type);
+                       if (!event_context_type_copy) {
+                               _printf_error("Cannot copy event context type\n");
+                               goto ec_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_freeze(event_context_type_copy);
+               }
+
+skip_event_context_type_copy:
+               if (event_payload_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       event_payload_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               event_payload_type_copy = event_payload_type;
+                               bt_get(event_payload_type_copy);
+                               goto skip_event_payload_type_copy;
+                       }
+
+                       event_payload_type_copy =
+                               bt_ctf_field_type_copy(event_payload_type);
+                       if (!event_payload_type_copy) {
+                               _printf_error("Cannot copy event payload type\n");
+                               goto ec_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_freeze(event_payload_type_copy);
+               }
+
+skip_event_payload_type_copy:
+               /* Put original references and move copies */
+               BT_MOVE(event_context_type, event_context_type_copy);
+               BT_MOVE(event_payload_type, event_payload_type_copy);
+
+               /* Validate event class field types */
+               valid_ret = validate_event_class_types(environment,
+                       packet_header_type, packet_context_type,
+                       event_header_type, stream_event_ctx_type,
+                       event_context_type, event_payload_type);
+               if (!valid_ret) {
+                       /* Event class is valid */
+                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
+               }
+
+               goto ec_validation_done;
+
+ec_validation_error:
+               BT_PUT(event_context_type_copy);
+               BT_PUT(event_payload_type_copy);
+               ret = -1;
+               goto error;
+       }
+
+ec_validation_done:
+       /*
+        * Validation is complete. Move the field types that were used
+        * to validate (and that were possibly altered by the validation
+        * process) to the output values.
+        */
+       BT_MOVE(output->packet_header_type, packet_header_type);
+       BT_MOVE(output->packet_context_type, packet_context_type);
+       BT_MOVE(output->event_header_type, event_header_type);
+       BT_MOVE(output->stream_event_ctx_type, stream_event_ctx_type);
+       BT_MOVE(output->event_context_type, event_context_type);
+       BT_MOVE(output->event_payload_type, event_payload_type);
+
+       return ret;
+
+error:
+       BT_PUT(packet_header_type);
+       BT_PUT(packet_context_type);
+       BT_PUT(event_header_type);
+       BT_PUT(stream_event_ctx_type);
+       BT_PUT(event_context_type);
+       BT_PUT(event_payload_type);
+
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_validation_replace_types(struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag replace_flags)
+{
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) {
+               BT_MOVE(trace->packet_header_type, output->packet_header_type);
+       }
+
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) {
+               BT_MOVE(stream_class->packet_context_type,
+                       output->packet_context_type);
+               BT_MOVE(stream_class->event_header_type,
+                       output->event_header_type);
+               BT_MOVE(stream_class->event_context_type,
+                       output->stream_event_ctx_type);
+       }
+
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) {
+               BT_MOVE(event_class->context, output->event_context_type);
+               BT_MOVE(event_class->fields, output->event_payload_type);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_validation_output_put_types(
+               struct bt_ctf_validation_output *output)
+{
+       BT_PUT(output->packet_header_type);
+       BT_PUT(output->packet_context_type);
+       BT_PUT(output->event_header_type);
+       BT_PUT(output->stream_event_ctx_type);
+       BT_PUT(output->event_context_type);
+       BT_PUT(output->event_payload_type);
+}
diff --git a/formats/ctf/ir/visitor.c b/formats/ctf/ir/visitor.c
deleted file mode 100644 (file)
index 704a804..0000000
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * visitor.c
- *
- * Babeltrace CTF IR - Trace Visitor
- *
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace/ctf-ir/event.h>
-#include <babeltrace/ctf-ir/stream-class.h>
-#include <babeltrace/ctf-ir/visitor-internal.h>
-#include <babeltrace/ctf-ir/event-types-internal.h>
-#include <babeltrace/ctf-ir/event-internal.h>
-#include <babeltrace/babeltrace-internal.h>
-
-/* TSDL dynamic scope prefixes defined in CTF Section 7.3.2 */
-static const char * const absolute_path_prefixes[] = {
-       [CTF_NODE_ENV] = "env.",
-       [CTF_NODE_TRACE_PACKET_HEADER] = "trace.packet.header.",
-       [CTF_NODE_STREAM_PACKET_CONTEXT] = "stream.packet.context.",
-       [CTF_NODE_STREAM_EVENT_HEADER] = "stream.event.header.",
-       [CTF_NODE_STREAM_EVENT_CONTEXT] = "stream.event.context.",
-       [CTF_NODE_EVENT_CONTEXT] = "event.context.",
-       [CTF_NODE_EVENT_FIELDS] = "event.fields.",
-};
-
-const int absolute_path_prefix_token_counts[] = {
-       [CTF_NODE_ENV] = 1,
-       [CTF_NODE_TRACE_PACKET_HEADER] = 3,
-       [CTF_NODE_STREAM_PACKET_CONTEXT] = 3,
-       [CTF_NODE_STREAM_EVENT_HEADER] = 3,
-       [CTF_NODE_STREAM_EVENT_CONTEXT] = 3,
-       [CTF_NODE_EVENT_CONTEXT] = 2,
-       [CTF_NODE_EVENT_FIELDS] = 2,
-};
-
-static const char * const type_names[] = {
-       [CTF_TYPE_UNKNOWN] = "unknown",
-       [CTF_TYPE_INTEGER] = "integer",
-       [CTF_TYPE_FLOAT] = "float",
-       [CTF_TYPE_ENUM] = "enumeration",
-       [CTF_TYPE_STRING] = "string",
-       [CTF_TYPE_STRUCT] = "structure",
-       [CTF_TYPE_UNTAGGED_VARIANT] = "untagged variant",
-       [CTF_TYPE_VARIANT] = "variant",
-       [CTF_TYPE_ARRAY] = "array",
-       [CTF_TYPE_SEQUENCE] = "sequence",
-};
-
-static
-int field_type_visit(struct bt_ctf_field_type *type,
-               struct ctf_type_visitor_context *context,
-               ctf_type_visitor_func func);
-
-static
-int field_type_recursive_visit(struct bt_ctf_field_type *type,
-               struct ctf_type_visitor_context *context,
-               ctf_type_visitor_func func);
-
-static inline
-int get_type_field_count(struct bt_ctf_field_type *type)
-{
-       int field_count = -1;
-       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
-
-       if (type_id == CTF_TYPE_STRUCT) {
-               field_count = bt_ctf_field_type_structure_get_field_count(type);
-       } else if (type_id == CTF_TYPE_VARIANT) {
-               field_count = bt_ctf_field_type_variant_get_field_count(type);
-       }
-       return field_count;
-}
-
-static inline
-struct bt_ctf_field_type *get_type_field(struct bt_ctf_field_type *type, int i)
-{
-       struct bt_ctf_field_type *field = NULL;
-       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
-
-       if (type_id == CTF_TYPE_STRUCT) {
-               bt_ctf_field_type_structure_get_field(type, NULL,
-                       &field, i);
-       } else if (type_id == CTF_TYPE_VARIANT) {
-               bt_ctf_field_type_variant_get_field(type,
-                       NULL, &field, i);
-       }
-
-       return field;
-}
-
-static inline
-int set_type_field(struct bt_ctf_field_type *type,
-               struct bt_ctf_field_type *field, int i)
-{
-       int ret = -1;
-       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
-
-       if (type_id == CTF_TYPE_STRUCT) {
-               ret = bt_ctf_field_type_structure_set_field_index(
-                       type, field, i);
-       } else if (type_id == CTF_TYPE_VARIANT) {
-               ret = bt_ctf_field_type_variant_set_field_index(
-                       type, field, i);
-       }
-
-       return ret;
-}
-
-static inline
-int get_type_field_index(struct bt_ctf_field_type *type, const char *name)
-{
-       int field_index = -1;
-       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
-
-       if (type_id == CTF_TYPE_STRUCT) {
-               field_index = bt_ctf_field_type_structure_get_field_name_index(
-                       type, name);
-       } else if (type_id == CTF_TYPE_VARIANT) {
-               field_index = bt_ctf_field_type_variant_get_field_name_index(
-                       type, name);
-       }
-
-       return field_index;
-}
-
-BT_HIDDEN
-ctf_type_stack *ctf_type_stack_create(void)
-{
-       return g_ptr_array_new();
-}
-
-BT_HIDDEN
-void ctf_type_stack_destroy(
-               ctf_type_stack *stack)
-{
-       g_ptr_array_free(stack, TRUE);
-}
-
-BT_HIDDEN
-int ctf_type_stack_push(ctf_type_stack *stack,
-               struct ctf_type_stack_frame *entry)
-{
-       int ret = 0;
-
-       if (!stack || !entry) {
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_add(stack, entry);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct ctf_type_stack_frame *ctf_type_stack_peek(ctf_type_stack *stack)
-{
-       struct ctf_type_stack_frame *entry = NULL;
-
-       if (!stack || stack->len == 0) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, stack->len - 1);
-end:
-       return entry;
-}
-
-BT_HIDDEN
-struct ctf_type_stack_frame *ctf_type_stack_pop(ctf_type_stack *stack)
-{
-       struct ctf_type_stack_frame *entry = NULL;
-
-       entry = ctf_type_stack_peek(stack);
-       if (entry) {
-               g_ptr_array_set_size(stack, stack->len - 1);
-       }
-       return entry;
-}
-
-static
-int field_type_visit(struct bt_ctf_field_type *type,
-               struct ctf_type_visitor_context *context,
-               ctf_type_visitor_func func)
-{
-       int ret;
-       enum ctf_type_id type_id;
-       struct ctf_type_stack_frame *frame = NULL;
-
-       ret = func(type, context);
-       if (ret) {
-               goto end;
-       }
-
-       type_id = bt_ctf_field_type_get_type_id(type);
-       if (type_id == CTF_TYPE_SEQUENCE || type_id == CTF_TYPE_ARRAY) {
-               struct bt_ctf_field_type *element =
-                       type_id == CTF_TYPE_SEQUENCE ?
-                       bt_ctf_field_type_sequence_get_element_type(type) :
-                       bt_ctf_field_type_array_get_element_type(type);
-
-               ret = field_type_recursive_visit(element, context, func);
-               bt_ctf_field_type_put(element);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       if (type_id != CTF_TYPE_STRUCT &&
-               type_id != CTF_TYPE_VARIANT) {
-               /* No need to create a new stack frame */
-               goto end;
-       }
-
-       frame = g_new0(struct ctf_type_stack_frame, 1);
-       if (!frame) {
-               ret = -1;
-               goto end;
-       }
-
-       frame->type = type;
-       ret = ctf_type_stack_push(context->stack, frame);
-       if (ret) {
-               g_free(frame);
-               goto end;
-       }
-end:
-       return ret;
-}
-
-static
-int field_type_recursive_visit(struct bt_ctf_field_type *type,
-               struct ctf_type_visitor_context *context,
-               ctf_type_visitor_func func)
-{
-       int ret = 0;
-       struct ctf_type_stack_frame *stack_marker = NULL;
-
-       ret = field_type_visit(type, context, func);
-       if (ret) {
-               goto end;
-       }
-
-       stack_marker = ctf_type_stack_peek(context->stack);
-       if (!stack_marker || stack_marker->type != type) {
-               /* No need for a recursive visit */
-               goto end;
-       }
-
-       while (true) {
-               struct bt_ctf_field_type *field;
-               struct ctf_type_stack_frame *entry =
-                       ctf_type_stack_peek(context->stack);
-               int field_count = get_type_field_count(entry->type);
-
-               if (field_count <= 0 &&
-                               !bt_ctf_field_type_is_structure(entry->type)) {
-                       /*
-                        * Propagate error if one was given, else return
-                        * -1 since empty variants are invalid
-                        * at this point.
-                        */
-                       ret = field_count < 0 ? field_count : -1;
-                       goto end;
-               }
-
-               if (entry->index == field_count) {
-                       /* This level has been completely visited */
-                       entry = ctf_type_stack_pop(context->stack);
-                       if (entry) {
-                               g_free(entry);
-                       }
-
-                       if (entry == stack_marker) {
-                               /* Completed visit */
-                               break;
-                       } else {
-                               continue;
-                       }
-               }
-
-               field = get_type_field(entry->type, entry->index);
-               /* Will push a new stack frame if field is struct or variant */
-               ret = field_type_visit(field, context, func);
-               bt_ctf_field_type_put(field);
-               if (ret) {
-                       goto end;
-               }
-
-               entry->index++;
-       }
-end:
-       return ret;
-}
-
-static
-int bt_ctf_event_class_visit(struct bt_ctf_event_class *event_class,
-               struct bt_ctf_trace *trace,
-               struct bt_ctf_stream_class *stream_class,
-               ctf_type_visitor_func func)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *type;
-       struct ctf_type_visitor_context context = { 0 };
-
-       if (!event_class || !func) {
-               ret = -1;
-               goto end;
-       }
-
-       context.trace = trace;
-       context.stream_class = stream_class;
-       context.event_class = event_class;
-       context.stack = ctf_type_stack_create();
-       if (!context.stack) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Visit event context */
-       context.root_node = CTF_NODE_EVENT_CONTEXT;
-       type = bt_ctf_event_class_get_context_type(event_class);
-       if (type) {
-               ret = field_type_recursive_visit(type, &context, func);
-               bt_ctf_field_type_put(type);
-               type = NULL;
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Visit event payload */
-       context.root_node = CTF_NODE_EVENT_FIELDS;
-       type = bt_ctf_event_class_get_payload_type(event_class);
-       if (type) {
-               ret = field_type_recursive_visit(type, &context, func);
-               bt_ctf_field_type_put(type);
-               type = NULL;
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       if (context.stack) {
-               ctf_type_stack_destroy(context.stack);
-       }
-       return ret;
-}
-
-static
-int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_trace *trace,
-               ctf_type_visitor_func func)
-{
-       int i, ret = 0, event_count;
-       struct bt_ctf_field_type *type;
-       struct ctf_type_visitor_context context = { 0 };
-
-       if (!stream_class || !func) {
-               ret = -1;
-               goto end;
-       }
-
-       context.trace = trace;
-       context.stream_class = stream_class;
-       context.stack = ctf_type_stack_create();
-       if (!context.stack) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Visit stream packet context header */
-       context.root_node = CTF_NODE_STREAM_PACKET_CONTEXT;
-       type = bt_ctf_stream_class_get_packet_context_type(stream_class);
-       if (type) {
-               ret = field_type_recursive_visit(type, &context, func);
-               bt_ctf_field_type_put(type);
-               type = NULL;
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Visit stream event header */
-       context.root_node = CTF_NODE_STREAM_EVENT_HEADER;
-       type = bt_ctf_stream_class_get_event_header_type(stream_class);
-       if (type) {
-               ret = field_type_recursive_visit(type, &context, func);
-               bt_ctf_field_type_put(type);
-               type = NULL;
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Visit stream event context */
-       context.root_node = CTF_NODE_STREAM_EVENT_CONTEXT;
-       type = bt_ctf_stream_class_get_event_context_type(stream_class);
-       if (type) {
-               ret = field_type_recursive_visit(type, &context, func);
-               bt_ctf_field_type_put(type);
-               type = NULL;
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Visit event classes */
-       event_count = bt_ctf_stream_class_get_event_class_count(stream_class);
-       if (event_count < 0) {
-               ret = event_count;
-               goto end;
-       }
-       for (i = 0; i < event_count; i++) {
-               struct bt_ctf_event_class *event_class =
-                       bt_ctf_stream_class_get_event_class(stream_class, i);
-
-               ret = bt_ctf_event_class_visit(event_class, trace,
-                       stream_class, func);
-               bt_ctf_event_class_put(event_class);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       if (context.stack) {
-               ctf_type_stack_destroy(context.stack);
-       }
-       return ret;
-}
-
-static
-int set_field_path_relative(struct ctf_type_visitor_context *context,
-               struct bt_ctf_field_path *field_path,
-               GList **path_tokens, struct bt_ctf_field_type **resolved_field)
-{
-       int ret = 0;
-       GArray *root_path;
-       struct bt_ctf_field_type *field = NULL;
-       struct ctf_type_stack_frame *frame =
-               ctf_type_stack_peek(context->stack);
-       size_t token_count = g_list_length(*path_tokens), i;
-
-       if (!frame) {
-               ret = -1;
-               goto end;
-       }
-
-       field = frame->type;
-       bt_ctf_field_type_get(field);
-       for (i = 0; i < token_count; i++) {
-               struct bt_ctf_field_type *next_field = NULL;
-               int field_index = get_type_field_index(field,
-                       (*path_tokens)->data);
-
-               if (field_index < 0) {
-                       /* Field name not found, abort */
-                       printf_verbose("Could not resolve field \"%s\"\n",
-                               (char *) (*path_tokens)->data);
-                       ret = -1;
-                       goto end;
-               }
-
-               if (field_index >= frame->index) {
-                       printf_verbose("Invalid relative path refers to a member after the current one\n");
-                       ret = -1;
-                       goto end;
-               }
-
-               next_field = get_type_field(field, field_index);
-               if (!next_field) {
-                       ret = -1;
-                       goto end;
-               }
-
-               bt_ctf_field_type_put(field);
-               field = next_field;
-               g_array_append_val(field_path->path_indexes, field_index);
-
-               /*
-                * Free token and remove from list. This function does not
-                * assume the ownership of path_tokens; it is therefore _not_
-                * a leak to leave elements in this list. The caller should
-                * clean-up what is left (in case of error).
-                */
-               free((*path_tokens)->data);
-               *path_tokens = g_list_delete_link(*path_tokens, *path_tokens);
-       }
-
-       root_path = g_array_sized_new(FALSE, FALSE,
-               sizeof(int), context->stack->len - 1);
-       if (!root_path) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Set the current root node as the resolved type's root */
-       field_path->root = context->root_node;
-       /*
-        * Prepend the current fields' path to the relative path that
-        * was found by walking the stack.
-        */
-       for (i = 0; i < context->stack->len - 1; i++) {
-               int index;
-               struct ctf_type_stack_frame *frame =
-                       g_ptr_array_index(context->stack, i);
-
-               /* Decrement "index" since it points to the next field */
-               index = frame->index - 1;
-               g_array_append_val(root_path, index);
-       }
-       g_array_prepend_vals(field_path->path_indexes, root_path->data,
-               root_path->len);
-       g_array_free(root_path, TRUE);
-end:
-       if (field) {
-               bt_ctf_field_type_put(field);
-               *resolved_field = field;
-       }
-
-       return ret;
-}
-
-static
-int set_field_path_absolute(struct ctf_type_visitor_context *context,
-               struct bt_ctf_field_path *field_path,
-               GList **path_tokens, struct bt_ctf_field_type **resolved_field)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field = NULL;
-       size_t token_count = g_list_length(*path_tokens), i;
-
-       if (field_path->root > context->root_node) {
-               /*
-                * The target path's root is lower in the dynamic scope
-                * hierarchy than the current field being visited. This
-                * is invalid since it would not be possible to have read
-                * the target before the current field.
-                */
-               ret = -1;
-               printf_verbose("The target path's root is lower in the dynamic scope than the current field.\n");
-               goto end;
-       }
-
-       /* Set the appropriate root field */
-       switch (field_path->root) {
-       case CTF_NODE_TRACE_PACKET_HEADER:
-               field = bt_ctf_trace_get_packet_header_type(context->trace);
-               break;
-       case CTF_NODE_STREAM_PACKET_CONTEXT:
-               field = bt_ctf_stream_class_get_packet_context_type(
-                       context->stream_class);
-               break;
-       case CTF_NODE_STREAM_EVENT_HEADER:
-               field = bt_ctf_stream_class_get_event_header_type(
-                       context->stream_class);
-               break;
-       case CTF_NODE_STREAM_EVENT_CONTEXT:
-               field = bt_ctf_stream_class_get_event_context_type(
-                       context->stream_class);
-               break;
-       case CTF_NODE_EVENT_CONTEXT:
-               field = bt_ctf_event_class_get_context_type(
-                       context->event_class);
-               break;
-       case CTF_NODE_EVENT_FIELDS:
-               field = bt_ctf_event_class_get_payload_type(
-                       context->event_class);
-               break;
-       default:
-               ret = -1;
-               goto end;
-       }
-
-       if (!field) {
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < token_count; i++) {
-               int field_index = get_type_field_index(field,
-                       (*path_tokens)->data);
-               struct bt_ctf_field_type *next_field = NULL;
-
-               if (field_index < 0) {
-                       /* Field name not found, abort */
-                       printf_verbose("Could not resolve field \"%s\"\n",
-                               (char *) (*path_tokens)->data);
-                       ret = -1;
-                       goto end;
-               }
-
-               next_field = get_type_field(field, field_index);
-               if (!next_field) {
-                       ret = -1;
-                       goto end;
-               }
-
-               bt_ctf_field_type_put(field);
-               field = next_field;
-               g_array_append_val(field_path->path_indexes, field_index);
-
-               /*
-                * Free token and remove from list. This function does not
-                * assume the ownership of path_tokens; it is therefore _not_
-                * a leak to leave elements in this list. The caller should
-                * clean-up what is left (in case of error).
-                */
-               free((*path_tokens)->data);
-               *path_tokens = g_list_delete_link(*path_tokens, *path_tokens);
-       }
-end:
-       if (field) {
-               bt_ctf_field_type_put(field);
-               *resolved_field = field;
-       }
-       return ret;
-}
-
-static
-int get_field_path(struct ctf_type_visitor_context *context,
-               const char *path, struct bt_ctf_field_path **field_path,
-               struct bt_ctf_field_type **resolved_field)
-{
-       int i, ret = 0;
-       GList *path_tokens = NULL;
-       char *name_copy, *save_ptr, *token;
-
-       /* Tokenize path to a list of strings */
-       name_copy = strdup(path);
-       if (!name_copy) {
-               goto error;
-       }
-
-       token = strtok_r(name_copy, ".", &save_ptr);
-       while (token) {
-               char *token_string = strdup(token);
-
-               if (!token_string) {
-                       ret = -1;
-                       goto error;
-               }
-               path_tokens = g_list_append(path_tokens, token_string);
-               token = strtok_r(NULL, ".", &save_ptr);
-       }
-
-       if (!path_tokens) {
-               ret = -1;
-               goto error;
-       }
-
-       *field_path = bt_ctf_field_path_create();
-       if (!*field_path) {
-               ret = -1;
-               goto error;
-       }
-
-       /* Check if the path is absolute */
-       for (i = 0; i < sizeof(absolute_path_prefixes) / sizeof(char *); i++) {
-               int j;
-
-               /*
-                * Chech if "path" starts with a known absolute path prefix.
-                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
-                */
-               if (strncmp(path, absolute_path_prefixes[i],
-                       strlen(absolute_path_prefixes[i]))) {
-                       /* Wrong prefix, try the next one */
-                       continue;
-               }
-
-               /*
-                * Remove the first n tokens of this prefix.
-                * e.g. trace.packet.header: remove the first 3 tokens.
-                */
-               for (j = 0; j < absolute_path_prefix_token_counts[i]; j++) {
-                       free(path_tokens->data);
-                       path_tokens = g_list_delete_link(
-                               path_tokens, path_tokens);
-               }
-
-               /* i maps to enum bt_ctf_node constants */
-               (*field_path)->root = (enum bt_ctf_node) i;
-               break;
-       }
-
-       if ((*field_path)->root == CTF_NODE_UNKNOWN) {
-               /* Relative path */
-               ret = set_field_path_relative(context,
-                       *field_path, &path_tokens, resolved_field);
-               if (ret) {
-                       goto error;
-               }
-       } else {
-               /* Absolute path */
-               ret = set_field_path_absolute(context,
-                       *field_path, &path_tokens, resolved_field);
-               if (ret) {
-                       goto error;
-               }
-       }
-end:
-       if (name_copy) {
-               g_free(name_copy);
-       }
-       if (path_tokens) {
-               g_list_foreach(path_tokens, (GFunc) free, NULL);
-               g_list_free(path_tokens);
-       }
-       return ret;
-error:
-       if (*field_path) {
-               bt_ctf_field_path_destroy(*field_path);
-               *field_path = NULL;
-       }
-       goto end;
-}
-
-void print_path(const char *field_name,
-               struct bt_ctf_field_type *resolved_type,
-               struct bt_ctf_field_path *field_path)
-{
-       int i;
-       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(
-               resolved_type);
-
-       if (type_id < CTF_TYPE_UNKNOWN || type_id >= NR_CTF_TYPES) {
-               type_id = CTF_TYPE_UNKNOWN;
-       }
-
-       printf_verbose("Resolved field \"%s\" as type \"%s\", ",
-               field_name, type_names[type_id]);
-       printf_verbose("path: %s",
-               absolute_path_prefixes[field_path->root]);
-
-       for (i = 0; i < field_path->path_indexes->len; i++) {
-               printf_verbose(" %d",
-                       g_array_index(field_path->path_indexes, int, i));
-       }
-       printf_verbose("\n");
-}
-
-static
-int type_resolve_func(struct bt_ctf_field_type *type,
-               struct ctf_type_visitor_context *context)
-{
-       int ret = 0;
-       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
-       const char *field_name = NULL;
-       struct bt_ctf_field_path *field_path = NULL;
-       struct bt_ctf_field_type *resolved_type = NULL;
-       struct bt_ctf_field_type *type_copy = NULL;
-       struct ctf_type_stack_frame *frame;
-
-       if (type_id != CTF_TYPE_SEQUENCE &&
-               type_id != CTF_TYPE_VARIANT) {
-               goto end;
-       }
-
-       field_name = type_id == CTF_TYPE_SEQUENCE ?
-               bt_ctf_field_type_sequence_get_length_field_name(type) :
-               bt_ctf_field_type_variant_get_tag_name(type);
-       if (!field_name) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = get_field_path(context, field_name,
-               &field_path, &resolved_type);
-       if (ret) {
-               goto end;
-       }
-
-       assert(field_path && resolved_type);
-
-       /* Print path if in verbose mode */
-       print_path(field_name, resolved_type, field_path);
-
-       /*
-        * Set field type's path.
-        *
-        * The original field is copied since it may have been reused
-        * in multiple structures which would cause a conflict.
-        */
-       type_copy = bt_ctf_field_type_copy(type);
-       if (!type_copy) {
-               ret = -1;
-               goto end;
-       }
-
-       if (type_id == CTF_TYPE_VARIANT) {
-               if (bt_ctf_field_type_get_type_id(resolved_type) !=
-                       CTF_TYPE_ENUM) {
-                       printf_verbose("Invalid variant tag \"%s\"; expected enum\n", field_name);
-                       ret = -1;
-                       goto end;
-               }
-               ret = bt_ctf_field_type_variant_set_tag(
-                       type_copy, resolved_type);
-               if (ret) {
-                       goto end;
-               }
-
-               ret = bt_ctf_field_type_variant_set_tag_field_path(type_copy,
-                       field_path);
-               if (ret) {
-                       goto end;
-               }
-       } else {
-               /* Sequence */
-               if (bt_ctf_field_type_get_type_id(resolved_type) !=
-                       CTF_TYPE_INTEGER) {
-                       printf_verbose("Invalid sequence length field \"%s\"; expected integer\n", field_name);
-                       ret = -1;
-                       goto end;
-               }
-
-               if (bt_ctf_field_type_integer_get_signed(resolved_type) != 0) {
-                       printf_verbose("Invalid sequence length field \"%s\"; integer should be unsigned\n", field_name);
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = bt_ctf_field_type_sequence_set_length_field_path(
-                       type_copy, field_path);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Replace the original field */
-       frame = ctf_type_stack_peek(context->stack);
-       ret = set_type_field(frame->type, type_copy, frame->index);
-       bt_ctf_field_type_put(type_copy);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
-               ctf_type_visitor_func func)
-{
-       int i, stream_count, ret = 0;
-       struct bt_ctf_field_type *type = NULL;
-       struct ctf_type_visitor_context visitor_ctx = { 0 };
-
-       if (!trace || !func) {
-               ret = -1;
-               goto end;
-       }
-
-       visitor_ctx.trace = trace;
-       visitor_ctx.stack = ctf_type_stack_create();
-       if (!visitor_ctx.stack) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Visit trace packet header */
-       type = bt_ctf_trace_get_packet_header_type(trace);
-       if (type) {
-               visitor_ctx.root_node = CTF_NODE_TRACE_PACKET_HEADER;
-               ret = field_type_recursive_visit(type, &visitor_ctx, func);
-               visitor_ctx.root_node = CTF_NODE_UNKNOWN;
-               bt_ctf_field_type_put(type);
-               type = NULL;
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       stream_count = bt_ctf_trace_get_stream_class_count(trace);
-       for (i = 0; i < stream_count; i++) {
-               struct bt_ctf_stream_class *stream_class =
-                       bt_ctf_trace_get_stream_class(trace, i);
-
-               /* Visit streams */
-               ret = bt_ctf_stream_class_visit(stream_class, trace,
-                       func);
-               bt_ctf_stream_class_put(stream_class);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       if (visitor_ctx.stack) {
-               ctf_type_stack_destroy(visitor_ctx.stack);
-       }
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_resolve_types(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_visit(trace, type_resolve_func);
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_resolve_types(struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_trace *trace)
-{
-       return bt_ctf_stream_class_visit(stream_class, trace,
-               type_resolve_func);
-}
-
-BT_HIDDEN
-int bt_ctf_event_class_resolve_types(struct bt_ctf_event_class *event_class,
-               struct bt_ctf_trace *trace,
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_event_class_visit(event_class, trace, stream_class,
-               type_resolve_func);
-}
index ef03773450af5c517027b2f7633059ddc00269fd..25d64df7adfae0c76385efc03d9c0fe09b563e67 100644 (file)
@@ -60,10 +60,11 @@ noinst_HEADERS = \
        babeltrace/ctf-ir/event-fields-internal.h \
        babeltrace/ctf-ir/event-internal.h \
        babeltrace/ctf-ir/clock-internal.h \
+       babeltrace/ctf-ir/resolve-internal.h \
        babeltrace/ctf-ir/stream-class-internal.h \
        babeltrace/ctf-ir/stream-internal.h \
        babeltrace/ctf-ir/trace-internal.h \
-       babeltrace/ctf-ir/visitor-internal.h \
+       babeltrace/ctf-ir/validation-internal.h \
        babeltrace/ctf-writer/functor-internal.h \
        babeltrace/trace-handle-internal.h \
        babeltrace/compat/uuid.h \
index 857ea01d03cbda886e8a1f313a63a0caf17d0aaa..43a12ba52d64fd22782ec2b1e9ca456d0f567884 100644 (file)
@@ -48,6 +48,14 @@ struct bt_ctf_event_class {
        /* Structure type containing the event's fields */
        struct bt_ctf_field_type *fields;
        int frozen;
+
+       /*
+        * This flag indicates if the event class is valid. A valid
+        * event class is _always_ frozen. However, an event class
+        * may be frozen, but not valid yet. This is okay, as long as
+        * no events are created out of this event class.
+        */
+       int valid;
 };
 
 struct bt_ctf_event {
index ba979682e9a6f268fb3cefff021f357b40a7f383..a8abef35ef6430c4d5ee42c9447094c7fddfd4f7 100644 (file)
@@ -54,9 +54,12 @@ enum bt_ctf_node {
 
 struct bt_ctf_field_path {
        enum bt_ctf_node root;
+
        /*
         * Array of integers (int) indicating the index in either
-        * structures or variants that make-up the path to a field.
+        * structures, variants, arrays, or sequences that make up
+        * the path to a field type. -1 means the "current element
+        * of an array or sequence type".
         */
        GArray *path_indexes;
 };
@@ -278,4 +281,15 @@ BT_HIDDEN
 int bt_ctf_field_type_sequence_set_element_type(struct bt_ctf_field_type *array,
                struct bt_ctf_field_type *element_type);
 
+BT_HIDDEN
+int bt_ctf_field_type_get_field_count(struct bt_ctf_field_type *type);
+
+BT_HIDDEN
+struct bt_ctf_field_type *bt_ctf_field_type_get_field_at_index(
+               struct bt_ctf_field_type *type, int index);
+
+BT_HIDDEN
+int bt_ctf_field_type_get_field_index(struct bt_ctf_field_type *type,
+               const char *name);
+
 #endif /* BABELTRACE_CTF_IR_EVENT_TYPES_INTERNAL_H */
diff --git a/include/babeltrace/ctf-ir/resolve-internal.h b/include/babeltrace/ctf-ir/resolve-internal.h
new file mode 100644 (file)
index 0000000..bd35f62
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef BABELTRACE_CTF_IR_RESOLVE_INTERNAL_H
+#define BABELTRACE_CTF_IR_RESOLVE_INTERNAL_H
+
+/*
+ * Babeltrace - CTF IR: Type resolving internal
+ *
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *          Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/event-types.h>
+#include <babeltrace/ctf-ir/event-types-internal.h>
+#include <babeltrace/values.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <glib.h>
+
+enum bt_ctf_resolve_flag {
+       BT_CTF_RESOLVE_FLAG_PACKET_HEADER       = 0x01,
+       BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT      = 0x02,
+       BT_CTF_RESOLVE_FLAG_EVENT_HEADER        = 0x04,
+       BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX    = 0x08,
+       BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT       = 0x10,
+       BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD       = 0x20,
+};
+
+/*
+ * Resolves CTF IR field types: recursively locates the tag and length
+ * field types of resp. variant and sequence field types.
+ *
+ * All `*_type` parameters may be resolved, and may as well serve as
+ * resolving targets.
+ *
+ * Resolving is performed based on the flags in `flags`.
+ *
+ * It is expected that, amongst all the provided types, no common
+ * references to sequence variant field types exist. In other words,
+ * this function does not copy field types.
+ *
+ * All parameters are owned by the caller.
+ */
+BT_HIDDEN
+int bt_ctf_resolve_types(struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type,
+               struct bt_ctf_field_type *stream_event_ctx_type,
+               struct bt_ctf_field_type *event_context_type,
+               struct bt_ctf_field_type *event_payload_type,
+               enum bt_ctf_resolve_flag flags);
+
+#endif /* BABELTRACE_CTF_IR_RESOLVE_INTERNAL_H */
index 94dc6206146d763eb728f222b084120a3cbe6658..453b08515a8be31819a1233f78f6888696211d9a 100644 (file)
@@ -50,6 +50,12 @@ struct bt_ctf_stream_class {
        struct bt_ctf_field_type *event_context_type;
        int frozen;
        int byte_order;
+
+       /*
+        * This flag indicates if the stream class is valid. A valid
+        * stream class is _always_ frozen.
+        */
+       int valid;
 };
 
 BT_HIDDEN
index 227120dc86817097b8a84ecba2e507d34ca2ec8f..e92eb7c1ade9f084a1d1ae2cee9ee477ce3661e2 100644 (file)
@@ -58,6 +58,12 @@ struct bt_ctf_trace {
        GPtrArray *streams; /* Array of ptrs to bt_ctf_stream */
        struct bt_ctf_field_type *packet_header_type;
        uint64_t next_stream_id;
+
+       /*
+        * This flag indicates if the trace is valid. A valid
+        * trace is _always_ frozen.
+        */
+       int valid;
 };
 
 struct metadata_context {
diff --git a/include/babeltrace/ctf-ir/validation-internal.h b/include/babeltrace/ctf-ir/validation-internal.h
new file mode 100644 (file)
index 0000000..065b32e
--- /dev/null
@@ -0,0 +1,124 @@
+#ifndef BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H
+#define BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H
+
+/*
+ * Babeltrace - CTF IR: Validation of trace, stream class, and event class
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/event-types.h>
+#include <babeltrace/ctf-ir/event.h>
+#include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/trace.h>
+#include <babeltrace/values.h>
+#include <babeltrace/babeltrace-internal.h>
+
+enum bt_ctf_validation_flag {
+       BT_CTF_VALIDATION_FLAG_TRACE    = 1,
+       BT_CTF_VALIDATION_FLAG_STREAM   = 2,
+       BT_CTF_VALIDATION_FLAG_EVENT    = 4,
+};
+
+/*
+ * Validation output structure.
+ *
+ * This is where the results of the validation function go. The field
+ * types are the validated ones which should replace the original field
+ * types of a trace, a stream class, and an event class.
+ *
+ * `valid_flags` contains the results of the validation.
+ */
+struct bt_ctf_validation_output {
+       struct bt_ctf_field_type *packet_header_type;
+       struct bt_ctf_field_type *packet_context_type;
+       struct bt_ctf_field_type *event_header_type;
+       struct bt_ctf_field_type *stream_event_ctx_type;
+       struct bt_ctf_field_type *event_context_type;
+       struct bt_ctf_field_type *event_payload_type;
+       enum bt_ctf_validation_flag valid_flags;
+};
+
+/*
+ * This function resolves and validates the field types of an event
+ * class, a stream class, and a trace. Copies are created if needed
+ * and the resulting field types to use are placed in the `output`
+ * validation structure, which also contains the results of the
+ * validation. Copies can replace the original field types of a trace,
+ * a stream class, and an event class using
+ * bt_ctf_validation_replace_types().
+ *
+ * The current known validity of the field types of the trace,
+ * stream class, and event class must be indicated with the
+ * `trace_valid`, `stream_class_valid`, and `event_class_valid`
+ * parameters. If a class is valid, its field types are not copied,
+ * validated, or resolved during this call.
+ *
+ * The validation flags `validate_flags` indicate which classes should
+ * have their field types validated.
+ *
+ * All parameters are owned by the caller.
+ */
+BT_HIDDEN
+int bt_ctf_validate_class_types(struct bt_value *environment,
+               struct bt_ctf_field_type *packet_header_type,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type,
+               struct bt_ctf_field_type *stream_event_ctx_type,
+               struct bt_ctf_field_type *event_context_type,
+               struct bt_ctf_field_type *event_payload_type,
+               int trace_valid, int stream_class_valid, int event_class_valid,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag validate_flags);
+
+/*
+ * This function replaces the actual field types of a trace, a stream
+ * class, and an event class with the appropriate field types contained
+ * in a validation output structure.
+ *
+ * The replace flags `replace_flags` indicate which classes should have
+ * their field types replaced.
+ *
+ * Note that the field types that are not used in the validation output
+ * structure are still owned by it at the end of this call.
+ * bt_ctf_validation_output_put_types() should be called to clean the
+ * structure.
+ *
+ * All parameters are owned by the caller.
+ */
+BT_HIDDEN
+void bt_ctf_validation_replace_types(struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag replace_flags);
+
+/*
+ * This function puts all the field types contained in a given
+ * validation output structure.
+ *
+ * `output` is owned by the caller and is not freed here.
+ */
+BT_HIDDEN
+void bt_ctf_validation_output_put_types(
+               struct bt_ctf_validation_output *output);
+
+#endif /* BABELTRACE_CTF_IR_VALIDATION_INTERNAL_H */
diff --git a/include/babeltrace/ctf-ir/visitor-internal.h b/include/babeltrace/ctf-ir/visitor-internal.h
deleted file mode 100644 (file)
index 8243dfe..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef BABELTRACE_CTF_IR_VISITOR_INTERNAL_H
-#define BABELTRACE_CTF_IR_VISITOR_INTERNAL_H
-
-/*
- * BabelTrace - CTF IR: Visitor internal
- *
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace/ctf-ir/event-types.h>
-#include <babeltrace/ctf-ir/event-types-internal.h>
-#include <babeltrace/babeltrace-internal.h>
-#include <glib.h>
-
-struct ctf_type_stack_frame {
-       struct bt_ctf_field_type *type;
-       int index;
-};
-
-typedef GPtrArray ctf_type_stack;
-
-struct ctf_type_visitor_context {
-       struct bt_ctf_trace *trace;
-       struct bt_ctf_stream_class *stream_class;
-       struct bt_ctf_event_class *event_class;
-       /* Root node being visited */
-       enum bt_ctf_node root_node;
-       ctf_type_stack *stack;
-};
-
-typedef int (*ctf_type_visitor_func)(struct bt_ctf_field_type *,
-       struct ctf_type_visitor_context *);
-
-BT_HIDDEN
-ctf_type_stack *ctf_type_stack_create(void);
-
-BT_HIDDEN
-void ctf_type_stack_destroy(ctf_type_stack *stack);
-
-BT_HIDDEN
-int ctf_type_stack_push(ctf_type_stack *stack,
-               struct ctf_type_stack_frame *entry);
-
-BT_HIDDEN
-struct ctf_type_stack_frame *ctf_type_stack_peek(
-               ctf_type_stack *stack);
-
-BT_HIDDEN
-struct ctf_type_stack_frame *ctf_type_stack_pop(ctf_type_stack *stack);
-
-BT_HIDDEN
-int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
-               ctf_type_visitor_func func);
-
-BT_HIDDEN
-int bt_ctf_trace_resolve_types(struct bt_ctf_trace *trace);
-
-BT_HIDDEN
-int bt_ctf_stream_class_resolve_types(struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_trace *trace);
-
-BT_HIDDEN
-int bt_ctf_event_class_resolve_types(struct bt_ctf_event_class *event_class,
-               struct bt_ctf_trace *trace,
-               struct bt_ctf_stream_class *stream_class);
-
-#endif /* BABELTRACE_CTF_IR_VISITOR_INTERNAL_H */
index a7b2513f797eacd1e0eee7d3b6c0967ba2e30e50..f75daba95de4d8f407a000c133b2766e24a94d2a 100644 (file)
@@ -57,7 +57,7 @@
 #define DEFAULT_CLOCK_IS_ABSOLUTE 0
 #define DEFAULT_CLOCK_TIME 0
 
-#define NR_TESTS 597
+#define NR_TESTS 594
 
 static int64_t current_time = 42;
 
@@ -380,6 +380,7 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
                bt_ctf_field_type_enumeration_create(uint_12_type);
        struct bt_ctf_field_type *event_context_type =
                bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *event_payload_type = NULL;
        struct bt_ctf_field_type *returned_type;
        struct bt_ctf_event *simple_event;
        struct bt_ctf_field *integer_field;
@@ -403,6 +404,9 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
        struct bt_ctf_field *stream_event_context_field;
        struct bt_ctf_field *event_context;
        struct bt_ctf_field *event_context_field;
+       struct bt_ctf_field_type *ep_integer_field_type = NULL;
+       struct bt_ctf_field_type *ep_enum_field_type = NULL;
+       struct bt_ctf_field_type *ep_enum_field_unsigned_type = NULL;
        int ret;
 
        ok(uint_12_type, "Create an unsigned integer type");
@@ -568,6 +572,32 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
 
        bt_ctf_stream_class_add_event_class(stream_class, simple_event_class);
 
+       /*
+        * bt_ctf_stream_class_add_event_class() copies the field types
+        * of simple_event_class, so we retrieve the new ones to create
+        * the appropriate fields.
+        */
+       BT_PUT(event_context_type);
+       BT_PUT(event_payload_type);
+       event_payload_type = bt_ctf_event_class_get_payload_type(
+               simple_event_class);
+       assert(event_payload_type);
+       event_context_type = bt_ctf_event_class_get_context_type(
+               simple_event_class);
+       assert(event_context_type);
+       ep_integer_field_type =
+               bt_ctf_field_type_structure_get_field_type_by_name(
+                       event_payload_type, "integer_field");
+       assert(ep_integer_field_type);
+       ep_enum_field_type =
+               bt_ctf_field_type_structure_get_field_type_by_name(
+                       event_payload_type, "enum_field");
+       assert(ep_enum_field_type);
+       ep_enum_field_unsigned_type =
+               bt_ctf_field_type_structure_get_field_type_by_name(
+                       event_payload_type, "enum_field_unsigned");
+       assert(ep_enum_field_unsigned_type);
+
        ok(bt_ctf_stream_class_get_event_class_count(NULL) < 0,
                "bt_ctf_stream_class_get_event_class_count handles NULL correctly");
        ok(bt_ctf_stream_class_get_event_class_count(stream_class) == 1,
@@ -612,7 +642,7 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
                "bt_ctf_event_get_clock returns a correct clock");
        bt_put(clock);
 
-       integer_field = bt_ctf_field_create(uint_12_type);
+       integer_field = bt_ctf_field_create(ep_integer_field_type);
        bt_ctf_field_unsigned_integer_set_value(integer_field, 42);
        ok(bt_ctf_event_set_payload(simple_event, "integer_field",
                integer_field) == 0, "Use bt_ctf_event_set_payload to set a manually allocated field");
@@ -630,7 +660,8 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
        ok(fabs(ret_double - double_test_value) <= DBL_EPSILON,
                "bt_ctf_field_floating_point_get_value returns a correct value");
 
-       enum_field = bt_ctf_field_create(enum_type);
+       enum_field = bt_ctf_field_create(ep_enum_field_type);
+       assert(enum_field);
        ret_char = bt_ctf_field_enumeration_get_mapping_name(NULL);
        ok(!ret_char, "bt_ctf_field_enumeration_get_mapping_name handles NULL correctly");
        ret_char = bt_ctf_field_enumeration_get_mapping_name(enum_field);
@@ -646,7 +677,8 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
        ret = bt_ctf_event_set_payload(simple_event, "enum_field", enum_field);
        assert(!ret);
 
-       enum_field_unsigned = bt_ctf_field_create(enum_type_unsigned);
+       enum_field_unsigned = bt_ctf_field_create(ep_enum_field_unsigned_type);
+       assert(enum_field_unsigned);
        enum_container_field_unsigned = bt_ctf_field_enumeration_get_container(
                enum_field_unsigned);
        ok(bt_ctf_field_unsigned_integer_set_value(
@@ -740,6 +772,10 @@ void append_simple_event(struct bt_ctf_stream_class *stream_class,
        bt_put(stream_event_context_field);
        bt_put(event_context);
        bt_put(event_context_field);
+       bt_put(event_payload_type);
+       bt_put(ep_integer_field_type);
+       bt_put(ep_enum_field_type);
+       bt_put(ep_enum_field_unsigned_type);
 }
 
 void append_complex_event(struct bt_ctf_stream_class *stream_class,
@@ -1102,7 +1138,7 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class,
        ok(bt_ctf_event_class_get_field(event_class, &ret_string,
                &ret_field_type, 0) == 0,
                "bt_ctf_event_class_get_field returns a field");
-       ok(ret_field_type == uint_35_type,
+       ok(bt_ctf_field_type_compare(ret_field_type, uint_35_type) == 0,
                "bt_ctf_event_class_get_field returns a correct field type");
        bt_put(ret_field_type);
        ok(!strcmp(ret_string, "uint_35"),
@@ -1115,7 +1151,7 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class,
                "bt_ctf_event_class_get_field_by_name handles an invalid field name correctly");
        ret_field_type = bt_ctf_event_class_get_field_by_name(event_class,
                "complex_structure");
-       ok(ret_field_type == complex_structure_type,
+       ok(bt_ctf_field_type_compare(ret_field_type, complex_structure_type) == 0,
                "bt_ctf_event_class_get_field_by_name returns a correct field type");
        bt_put(ret_field_type);
 
@@ -1177,7 +1213,7 @@ void append_complex_event(struct bt_ctf_stream_class *stream_class,
                complex_structure_field, 3);
        ret_field_type = bt_ctf_field_get_type(inner_structure_field);
        bt_put(inner_structure_field);
-       ok(ret_field_type == inner_structure_type,
+       ok(bt_ctf_field_type_compare(ret_field_type, inner_structure_type) == 0,
                "bt_ctf_field_structure_get_field_by_index returns a correct field");
        bt_put(ret_field_type);
 
@@ -1855,8 +1891,6 @@ void type_field_tests()
        struct bt_ctf_field_type *uint_12_type =
                bt_ctf_field_type_integer_create(12);
        struct bt_ctf_field_type *enumeration_type;
-       struct bt_ctf_field_type *enumeration_sequence_type;
-       struct bt_ctf_field_type *enumeration_array_type;
        struct bt_ctf_field_type *returned_type;
        const char *ret_string;
 
@@ -2102,17 +2136,6 @@ void type_field_tests()
        enumeration_type = bt_ctf_field_type_enumeration_create(uint_12_type);
        ok(enumeration_type,
                "Create an enumeration type with an unsigned 12-bit integer as container");
-       enumeration_sequence_type = bt_ctf_field_type_sequence_create(
-               enumeration_type, "count");
-       ok(!enumeration_sequence_type,
-               "Check enumeration types are validated when creating a sequence");
-       enumeration_array_type = bt_ctf_field_type_array_create(
-               enumeration_type, 10);
-       ok(!enumeration_array_type,
-               "Check enumeration types are validated when creating an array");
-       ok(bt_ctf_field_type_structure_add_field(composite_structure_type,
-               enumeration_type, "enumeration"),
-               "Check enumeration types are validated when adding them as structure members");
        enumeration = bt_ctf_field_create(enumeration_type);
        ok(!enumeration,
                "Check enumeration types are validated before instantiation");
@@ -2129,8 +2152,6 @@ void type_field_tests()
        bt_put(int_16_type);
        bt_put(uint_12_type);
        bt_put(enumeration_type);
-       bt_put(enumeration_sequence_type);
-       bt_put(enumeration_array_type);
        bt_put(returned_type);
 }
 
@@ -2157,6 +2178,9 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class,
        int events_appended = 0;
        struct bt_ctf_field *packet_context = NULL,
                *packet_context_field = NULL, *event_context = NULL;
+       struct bt_ctf_field_type *ep_field_1_type = NULL;
+       struct bt_ctf_field_type *ep_a_string_type = NULL;
+       struct bt_ctf_field_type *ep_type = NULL;
 
        ret |= bt_ctf_event_class_add_field(event_class, integer_type,
                "field_1");
@@ -2168,10 +2192,24 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class,
                goto end;
        }
 
+       /*
+        * bt_ctf_stream_class_add_event_class() copies the field types
+        * of event_class, so we retrieve the new ones to create the
+        * appropriate fields.
+        */
+       ep_type = bt_ctf_event_class_get_payload_type(event_class);
+       assert(ep_type);
+       ep_field_1_type = bt_ctf_field_type_structure_get_field_type_by_name(
+               ep_type, "field_1");
+       assert(ep_field_1_type);
+       ep_a_string_type = bt_ctf_field_type_structure_get_field_type_by_name(
+               ep_type, "a_string");
+       assert(ep_a_string_type);
+
        event = bt_ctf_event_create(event_class);
        ret_field = bt_ctf_event_get_payload_by_index(event, 0);
        ret_field_type = bt_ctf_field_get_type(ret_field);
-       ok(ret_field_type == integer_type,
+       ok(bt_ctf_field_type_compare(ret_field_type, integer_type) == 0,
                "bt_ctf_event_get_payload_by_index returns a correct field");
        bt_put(ret_field_type);
        bt_put(ret_field);
@@ -2193,7 +2231,7 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class,
                "bt_ctf_stream_set_event_context handles a NULL stream event context correctly");
        ok(!bt_ctf_stream_set_event_context(stream, event_context),
                "bt_ctf_stream_set_event_context correctly set a stream event context");
-       ret_field = bt_ctf_field_create(integer_type);
+       ret_field = bt_ctf_field_create(ep_field_1_type);
        ok(bt_ctf_stream_set_event_context(stream, ret_field) < 0,
                "bt_ctf_stream_set_event_context rejects an event context of incorrect type");
        bt_put(ret_field);
@@ -2201,9 +2239,9 @@ void packet_resize_test(struct bt_ctf_stream_class *stream_class,
        for (i = 0; i < PACKET_RESIZE_TEST_LENGTH; i++) {
                event = bt_ctf_event_create(event_class);
                struct bt_ctf_field *integer =
-                       bt_ctf_field_create(integer_type);
+                       bt_ctf_field_create(ep_field_1_type);
                struct bt_ctf_field *string =
-                       bt_ctf_field_create(string_type);
+                       bt_ctf_field_create(ep_a_string_type);
 
                ret |= bt_ctf_clock_set_time(clock, ++current_time);
                ret |= bt_ctf_field_unsigned_integer_set_value(integer, i);
@@ -2266,6 +2304,9 @@ end:
        bt_put(packet_context_field);
        bt_put(event_context);
        bt_put(event_class);
+       bt_put(ep_field_1_type);
+       bt_put(ep_a_string_type);
+       bt_put(ep_type);
 }
 
 void test_empty_stream(struct bt_ctf_writer *writer)
@@ -3213,6 +3254,23 @@ int main(int argc, char **argv)
        ok(ret_stream_class == stream_class,
                "Returned stream class is of the correct type");
 
+       /*
+        * Packet header, packet context, event header, and stream
+        * event context types were copied for the resolving
+        * process
+        */
+       BT_PUT(packet_header_type);
+       BT_PUT(packet_context_type);
+       BT_PUT(stream_event_context_type);
+       packet_header_type = bt_ctf_trace_get_packet_header_type(trace);
+       assert(packet_header_type);
+       packet_context_type =
+               bt_ctf_stream_class_get_packet_context_type(stream_class);
+       assert(packet_context_type);
+       stream_event_context_type =
+               bt_ctf_stream_class_get_event_context_type(stream_class);
+       assert(stream_event_context_type);
+
        /*
         * Try to modify the packet context type after a stream has been
         * created.
@@ -3259,7 +3317,7 @@ int main(int argc, char **argv)
        ok(packet_header_field,
                "Packet header structure contains a custom field with the appropriate name");
        ret_field_type = bt_ctf_field_get_type(packet_header_field);
-       ok(ret_field_type == packet_header_field_type,
+       ok(bt_ctf_field_type_compare(ret_field_type, packet_header_field_type) == 0,
                "Custom packet header field is of the expected type");
        ok(!bt_ctf_field_unsigned_integer_set_value(packet_header_field,
                54321), "Set custom packet header value successfully");
This page took 0.077936 seconds and 4 git commands to generate.