Fix: enum must use last value + 1 as next item value
[babeltrace.git] / formats / ctf / metadata / ctf-visitor-generate-io-struct.c
index 6fbc7c02b0f74aeb41026a7bc0ed8391febaf2d6..500482f57f03f5c77b445dc92938a12b4fe779c2 100644 (file)
 #include <assert.h>
 #include <glib.h>
 #include <inttypes.h>
-#include <endian.h>
 #include <errno.h>
-#include <babeltrace/babeltrace.h>
+#include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/list.h>
 #include <babeltrace/types.h>
 #include <babeltrace/ctf/metadata.h>
-#include <uuid/uuid.h>
+#include <babeltrace/uuid.h>
+#include <babeltrace/endian.h>
+#include <babeltrace/ctf/events-internal.h>
 #include "ctf-scanner.h"
 #include "ctf-parser.h"
 #include "ctf-ast.h"
 
 #define fprintf_dbg(fd, fmt, args...)  fprintf(fd, "%s: " fmt, __func__, ## args)
 
-#define _cds_list_first_entry(ptr, type, member)       \
-       cds_list_entry((ptr)->next, type, member)
+#define _bt_list_first_entry(ptr, type, member)        \
+       bt_list_entry((ptr)->next, type, member)
+
+struct last_enum_value {
+       union {
+               int64_t s;
+               uint64_t u;
+       } u;
+};
+
+int opt_clock_force_correlate;
 
 static
 struct declaration *ctf_type_specifier_list_visit(FILE *fd,
@@ -49,18 +59,32 @@ static
 int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
                     struct declaration_scope *parent_declaration_scope, struct ctf_trace *trace);
 
+static
+int is_unary_string(struct bt_list_head *head)
+{
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               if (node->type != NODE_UNARY_EXPRESSION)
+                       return 0;
+               if (node->u.unary_expression.type != UNARY_STRING)
+                       return 0;
+       }
+       return 1;
+}
+
 /*
  * String returned must be freed by the caller using g_free.
  */
 static
-char *concatenate_unary_strings(struct cds_list_head *head)
+char *concatenate_unary_strings(struct bt_list_head *head)
 {
        struct ctf_node *node;
        GString *str;
        int i = 0;
 
        str = g_string_new("");
-       cds_list_for_each_entry(node, head, siblings) {
+       bt_list_for_each_entry(node, head, siblings) {
                char *src_string;
 
                assert(node->type == NODE_UNARY_EXPRESSION);
@@ -88,12 +112,70 @@ char *concatenate_unary_strings(struct cds_list_head *head)
 }
 
 static
-int get_unary_unsigned(struct cds_list_head *head, uint64_t *value)
+GQuark get_map_clock_name_value(struct bt_list_head *head)
 {
        struct ctf_node *node;
+       const char *name = NULL;
        int i = 0;
 
-       cds_list_for_each_entry(node, head, siblings) {
+       bt_list_for_each_entry(node, head, siblings) {
+               char *src_string;
+
+               assert(node->type == NODE_UNARY_EXPRESSION);
+               assert(node->u.unary_expression.type == UNARY_STRING);
+               assert((node->u.unary_expression.link == UNARY_LINK_UNKNOWN)
+                       ^ (i != 0));
+               /* needs to be chained with . */
+               switch (node->u.unary_expression.link) {
+               case UNARY_DOTLINK:
+                       break;
+               case UNARY_ARROWLINK:
+               case UNARY_DOTDOTDOT:
+                       return 0;
+               default:
+                       break;
+               }
+               src_string = node->u.unary_expression.u.string;
+               switch (i) {
+               case 0: if (strcmp("clock", src_string) != 0) {
+                               return 0;
+                       }
+                       break;
+               case 1: name = src_string;
+                       break;
+               case 2: if (strcmp("value", src_string) != 0) {
+                               return 0;
+                       }
+                       break;
+               default:
+                       return 0;       /* extra identifier, unknown */
+               }
+               i++;
+       }
+       return g_quark_from_string(name);
+}
+
+static
+int is_unary_unsigned(struct bt_list_head *head)
+{
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               if (node->type != NODE_UNARY_EXPRESSION)
+                       return 0;
+               if (node->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT)
+                       return 0;
+       }
+       return 1;
+}
+
+static
+int get_unary_unsigned(struct bt_list_head *head, uint64_t *value)
+{
+       struct ctf_node *node;
+       int i = 0;
+
+       bt_list_for_each_entry(node, head, siblings) {
                assert(node->type == NODE_UNARY_EXPRESSION);
                assert(node->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT);
                assert(node->u.unary_expression.link == UNARY_LINK_UNKNOWN);
@@ -105,13 +187,54 @@ int get_unary_unsigned(struct cds_list_head *head, uint64_t *value)
 }
 
 static
-int get_unary_uuid(struct cds_list_head *head, uuid_t *uuid)
+int is_unary_signed(struct bt_list_head *head)
+{
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               if (node->type != NODE_UNARY_EXPRESSION)
+                       return 0;
+               if (node->u.unary_expression.type != UNARY_SIGNED_CONSTANT)
+                       return 0;
+       }
+       return 1;
+}
+
+static
+int get_unary_signed(struct bt_list_head *head, int64_t *value)
+{
+       struct ctf_node *node;
+       int i = 0;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               assert(node->type == NODE_UNARY_EXPRESSION);
+               assert(node->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT
+                       || node->u.unary_expression.type == UNARY_SIGNED_CONSTANT);
+               assert(node->u.unary_expression.link == UNARY_LINK_UNKNOWN);
+               assert(i == 0);
+               switch (node->u.unary_expression.type) {
+               case UNARY_UNSIGNED_CONSTANT:
+                       *value = (int64_t) node->u.unary_expression.u.unsigned_constant;
+                       break;
+               case UNARY_SIGNED_CONSTANT:
+                       *value = node->u.unary_expression.u.signed_constant;
+                       break;
+               default:
+                       assert(0);
+               }
+               i++;
+       }
+       return 0;
+}
+
+static
+int get_unary_uuid(struct bt_list_head *head, unsigned char *uuid)
 {
        struct ctf_node *node;
        int i = 0;
        int ret = -1;
 
-       cds_list_for_each_entry(node, head, siblings) {
+       bt_list_for_each_entry(node, head, siblings) {
                const char *src_string;
 
                assert(node->type == NODE_UNARY_EXPRESSION);
@@ -119,19 +242,25 @@ int get_unary_uuid(struct cds_list_head *head, uuid_t *uuid)
                assert(node->u.unary_expression.link == UNARY_LINK_UNKNOWN);
                assert(i == 0);
                src_string = node->u.unary_expression.u.string;
-               ret = uuid_parse(src_string, *uuid);
+               ret = babeltrace_uuid_parse(src_string, uuid);
        }
        return ret;
 }
 
 static
-struct ctf_stream_class *trace_stream_lookup(struct ctf_trace *trace, uint64_t stream_id)
+struct ctf_stream_declaration *trace_stream_lookup(struct ctf_trace *trace, uint64_t stream_id)
 {
        if (trace->streams->len <= stream_id)
                return NULL;
        return g_ptr_array_index(trace->streams, stream_id);
 }
 
+static
+struct ctf_clock *trace_clock_lookup(struct ctf_trace *trace, GQuark clock_name)
+{
+       return g_hash_table_lookup(trace->clocks, (gpointer) (unsigned long) clock_name);
+}
+
 static
 int visit_type_specifier(FILE *fd, struct ctf_node *type_specifier, GString *str)
 {
@@ -234,7 +363,7 @@ int visit_type_specifier_list(FILE *fd, struct ctf_node *type_specifier_list, GS
        int alias_item_nr = 0;
        int ret;
 
-       cds_list_for_each_entry(iter, &type_specifier_list->u.type_specifier_list.head, siblings) {
+       bt_list_for_each_entry(iter, &type_specifier_list->u.type_specifier_list.head, siblings) {
                if (alias_item_nr != 0)
                        g_string_append(str, " ");
                alias_item_nr++;
@@ -262,7 +391,7 @@ GQuark create_typealias_identifier(FILE *fd, int depth,
                g_string_free(str, TRUE);
                return 0;
        }
-       cds_list_for_each_entry(iter, &node_type_declarator->u.type_declarator.pointers, siblings) {
+       bt_list_for_each_entry(iter, &node_type_declarator->u.type_declarator.pointers, siblings) {
                g_string_append(str, " *");
                if (iter->u.pointer.const_qualifier)
                        g_string_append(str, " const");
@@ -299,7 +428,7 @@ struct declaration *ctf_type_declarator_visit(FILE *fd, int depth,
        }
 
        if (!nested_declaration) {
-               if (node_type_declarator && !cds_list_empty(&node_type_declarator->u.type_declarator.pointers)) {
+               if (node_type_declarator && !bt_list_empty(&node_type_declarator->u.type_declarator.pointers)) {
                        GQuark alias_q;
 
                        /*
@@ -325,7 +454,8 @@ struct declaration *ctf_type_declarator_visit(FILE *fd, int depth,
                                         */
                                        integer_declaration = integer_declaration_new(integer_declaration->len,
                                                integer_declaration->byte_order, integer_declaration->signedness,
-                                               integer_declaration->p.alignment, 16, integer_declaration->encoding);
+                                               integer_declaration->p.alignment, 16, integer_declaration->encoding,
+                                               integer_declaration->clock);
                                        nested_declaration = &integer_declaration->p;
                                }
                        }
@@ -356,11 +486,11 @@ struct declaration *ctf_type_declarator_visit(FILE *fd, int depth,
                }
 
                /* create array/sequence, pass nested_declaration as child. */
-               if (cds_list_empty(&node_type_declarator->u.type_declarator.u.nested.length)) {
+               if (bt_list_empty(&node_type_declarator->u.type_declarator.u.nested.length)) {
                        fprintf(fd, "[error] %s: expecting length field reference or value.\n", __func__);
                        return NULL;
                }
-               first = _cds_list_first_entry(&node_type_declarator->u.type_declarator.u.nested.length, 
+               first = _bt_list_first_entry(&node_type_declarator->u.type_declarator.u.nested.length, 
                                struct ctf_node, siblings);
                assert(first->type == NODE_UNARY_EXPRESSION);
 
@@ -412,14 +542,14 @@ static
 int ctf_struct_type_declarators_visit(FILE *fd, int depth,
        struct declaration_struct *struct_declaration,
        struct ctf_node *type_specifier_list,
-       struct cds_list_head *type_declarators,
+       struct bt_list_head *type_declarators,
        struct declaration_scope *declaration_scope,
        struct ctf_trace *trace)
 {
        struct ctf_node *iter;
        GQuark field_name;
 
-       cds_list_for_each_entry(iter, type_declarators, siblings) {
+       bt_list_for_each_entry(iter, type_declarators, siblings) {
                struct declaration *field_declaration;
 
                field_declaration = ctf_type_declarator_visit(fd, depth,
@@ -449,14 +579,14 @@ static
 int ctf_variant_type_declarators_visit(FILE *fd, int depth,
        struct declaration_untagged_variant *untagged_variant_declaration,
        struct ctf_node *type_specifier_list,
-       struct cds_list_head *type_declarators,
+       struct bt_list_head *type_declarators,
        struct declaration_scope *declaration_scope,
        struct ctf_trace *trace)
 {
        struct ctf_node *iter;
        GQuark field_name;
 
-       cds_list_for_each_entry(iter, type_declarators, siblings) {
+       bt_list_for_each_entry(iter, type_declarators, siblings) {
                struct declaration *field_declaration;
 
                field_declaration = ctf_type_declarator_visit(fd, depth,
@@ -485,13 +615,13 @@ int ctf_variant_type_declarators_visit(FILE *fd, int depth,
 static
 int ctf_typedef_visit(FILE *fd, int depth, struct declaration_scope *scope,
                struct ctf_node *type_specifier_list,
-               struct cds_list_head *type_declarators,
+               struct bt_list_head *type_declarators,
                struct ctf_trace *trace)
 {
        struct ctf_node *iter;
        GQuark identifier;
 
-       cds_list_for_each_entry(iter, type_declarators, siblings) {
+       bt_list_for_each_entry(iter, type_declarators, siblings) {
                struct declaration *type_declaration;
                int ret;
        
@@ -538,10 +668,10 @@ int ctf_typealias_visit(FILE *fd, int depth, struct declaration_scope *scope,
         * Create target type declaration.
         */
 
-       if (cds_list_empty(&target->u.typealias_target.type_declarators))
+       if (bt_list_empty(&target->u.typealias_target.type_declarators))
                node = NULL;
        else
-               node = _cds_list_first_entry(&target->u.typealias_target.type_declarators,
+               node = _bt_list_first_entry(&target->u.typealias_target.type_declarators,
                                struct ctf_node, siblings);
        type_declaration = ctf_type_declarator_visit(fd, depth,
                target->u.typealias_target.type_specifier_list,
@@ -574,7 +704,7 @@ int ctf_typealias_visit(FILE *fd, int depth, struct declaration_scope *scope,
         * Create alias identifier.
         */
 
-       node = _cds_list_first_entry(&alias->u.typealias_alias.type_declarators,
+       node = _bt_list_first_entry(&alias->u.typealias_alias.type_declarators,
                                struct ctf_node, siblings);
        alias_q = create_typealias_identifier(fd, depth,
                        alias->u.typealias_alias.type_specifier_list, node);
@@ -679,8 +809,8 @@ int ctf_variant_declaration_list_visit(FILE *fd, int depth,
 
 static
 struct declaration *ctf_declaration_struct_visit(FILE *fd,
-       int depth, const char *name, struct cds_list_head *declaration_list,
-       int has_body, struct cds_list_head *min_align,
+       int depth, const char *name, struct bt_list_head *declaration_list,
+       int has_body, struct bt_list_head *min_align,
        struct declaration_scope *declaration_scope,
        struct ctf_trace *trace)
 {
@@ -712,7 +842,7 @@ struct declaration *ctf_declaration_struct_visit(FILE *fd,
                                return NULL;
                        }
                }
-               if (!cds_list_empty(min_align)) {
+               if (!bt_list_empty(min_align)) {
                        ret = get_unary_unsigned(min_align, &min_align_value);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for structure \"align\" attribute\n", __func__);
@@ -722,7 +852,7 @@ struct declaration *ctf_declaration_struct_visit(FILE *fd,
                }
                struct_declaration = struct_declaration_new(declaration_scope,
                                                            min_align_value);
-               cds_list_for_each_entry(iter, declaration_list, siblings) {
+               bt_list_for_each_entry(iter, declaration_list, siblings) {
                        ret = ctf_struct_declaration_list_visit(fd, depth + 1, iter,
                                struct_declaration, trace);
                        if (ret)
@@ -745,7 +875,7 @@ error:
 static
 struct declaration *ctf_declaration_variant_visit(FILE *fd,
        int depth, const char *name, const char *choice,
-       struct cds_list_head *declaration_list,
+       struct bt_list_head *declaration_list,
        int has_body, struct declaration_scope *declaration_scope,
        struct ctf_trace *trace)
 {
@@ -776,7 +906,7 @@ struct declaration *ctf_declaration_variant_visit(FILE *fd,
                        }
                }
                untagged_variant_declaration = untagged_variant_declaration_new(declaration_scope);
-               cds_list_for_each_entry(iter, declaration_list, siblings) {
+               bt_list_for_each_entry(iter, declaration_list, siblings) {
                        ret = ctf_variant_declaration_list_visit(fd, depth + 1, iter,
                                untagged_variant_declaration, trace);
                        if (ret)
@@ -810,7 +940,8 @@ error:
 static
 int ctf_enumerator_list_visit(FILE *fd, int depth,
                struct ctf_node *enumerator,
-               struct declaration_enum *enum_declaration)
+               struct declaration_enum *enum_declaration,
+               struct last_enum_value *last)
 {
        GQuark q;
        struct ctf_node *iter;
@@ -820,7 +951,7 @@ int ctf_enumerator_list_visit(FILE *fd, int depth,
                int64_t start, end;
                int nr_vals = 0;
 
-               cds_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
+               bt_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
                        int64_t *target;
 
                        assert(iter->type == NODE_UNARY_EXPRESSION);
@@ -846,14 +977,17 @@ int ctf_enumerator_list_visit(FILE *fd, int depth,
                        }
                        nr_vals++;
                }
-               if (nr_vals == 1)
+               if (nr_vals == 0)
+                       start = last->u.s;
+               if (nr_vals <= 1)
                        end = start;
+               last->u.s = end + 1;
                enum_signed_insert(enum_declaration, start, end, q);
        } else {
                uint64_t start, end;
                int nr_vals = 0;
 
-               cds_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
+               bt_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
                        uint64_t *target;
 
                        assert(iter->type == NODE_UNARY_EXPRESSION);
@@ -883,8 +1017,11 @@ int ctf_enumerator_list_visit(FILE *fd, int depth,
                        }
                        nr_vals++;
                }
-               if (nr_vals == 1)
+               if (nr_vals == 0)
+                       start = last->u.u;
+               if (nr_vals <= 1)
                        end = start;
+               last->u.u = end + 1;
                enum_unsigned_insert(enum_declaration, start, end, q);
        }
        return 0;
@@ -894,7 +1031,7 @@ static
 struct declaration *ctf_declaration_enum_visit(FILE *fd, int depth,
                        const char *name,
                        struct ctf_node *container_type,
-                       struct cds_list_head *enumerator_list,
+                       struct bt_list_head *enumerator_list,
                        int has_body,
                        struct declaration_scope *declaration_scope,
                        struct ctf_trace *trace)
@@ -902,6 +1039,7 @@ struct declaration *ctf_declaration_enum_visit(FILE *fd, int depth,
        struct declaration *declaration;
        struct declaration_enum *enum_declaration;
        struct declaration_integer *integer_declaration;
+       struct last_enum_value last_value;
        struct ctf_node *iter;
        GQuark dummy_id;
        int ret;
@@ -953,8 +1091,14 @@ struct declaration *ctf_declaration_enum_visit(FILE *fd, int depth,
                integer_declaration = container_of(declaration, struct declaration_integer, p);
                enum_declaration = enum_declaration_new(integer_declaration);
                declaration_unref(&integer_declaration->p);     /* leave ref to enum */
-               cds_list_for_each_entry(iter, enumerator_list, siblings) {
-                       ret = ctf_enumerator_list_visit(fd, depth + 1, iter, enum_declaration);
+               if (enum_declaration->integer_declaration->signedness) {
+                       last_value.u.s = 0;
+               } else {
+                       last_value.u.u = 0;
+               }
+               bt_list_for_each_entry(iter, enumerator_list, siblings) {
+                       ret = ctf_enumerator_list_visit(fd, depth + 1, iter, enum_declaration,
+                                       &last_value);
                        if (ret)
                                goto error;
                }
@@ -1089,7 +1233,7 @@ int get_byte_order(FILE *fd, int depth, struct ctf_node *unary_expression,
 
 static
 struct declaration *ctf_declaration_integer_visit(FILE *fd, int depth,
-               struct cds_list_head *expressions,
+               struct bt_list_head *expressions,
                struct ctf_trace *trace)
 {
        struct ctf_node *expression;
@@ -1099,13 +1243,14 @@ struct declaration *ctf_declaration_integer_visit(FILE *fd, int depth,
        int has_alignment = 0, has_size = 0;
        int base = 0;
        enum ctf_string_encoding encoding = CTF_STRING_NONE;
+       struct ctf_clock *clock = NULL;
        struct declaration_integer *integer_declaration;
 
-       cds_list_for_each_entry(expression, expressions, siblings) {
+       bt_list_for_each_entry(expression, expressions, siblings) {
                struct ctf_node *left, *right;
 
-               left = _cds_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
-               right = _cds_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
+               left = _bt_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
+               right = _bt_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
                assert(left->u.unary_expression.type == UNARY_STRING);
                if (!strcmp(left->u.unary_expression.u.string, "signed")) {
                        signedness = get_boolean(fd, depth, right);
@@ -1217,10 +1362,40 @@ struct declaration *ctf_declaration_integer_visit(FILE *fd, int depth,
                                return NULL;
                        }
                        g_free(s_right);
+               } else if (!strcmp(left->u.unary_expression.u.string, "map")) {
+                       GQuark clock_name;
+
+                       if (right->u.unary_expression.type != UNARY_STRING) {
+                               fprintf(fd, "[error] %s: map: expecting identifier\n",
+                                       __func__);
+                               return NULL;
+                       }
+                       /* currently only support clock.name.value */
+                       clock_name = get_map_clock_name_value(&expression->u.ctf_expression.right);
+                       if (!clock_name) {
+                               char *s_right;
+
+                               s_right = concatenate_unary_strings(&expression->u.ctf_expression.right);
+                               if (!s_right) {
+                                       fprintf(fd, "[error] %s: unexpected unary expression for integer map\n", __func__);
+                                       g_free(s_right);
+                                       return NULL;
+                               }
+                               fprintf(fd, "[warning] %s: unknown map %s in integer declaration\n", __func__,
+                                       s_right);
+                               g_free(s_right);
+                               continue;
+                       }
+                       clock = trace_clock_lookup(trace, clock_name);
+                       if (!clock) {
+                               fprintf(fd, "[error] %s: map: unable to find clock %s declaration\n",
+                                       __func__, g_quark_to_string(clock_name));
+                               return NULL;
+                       }
                } else {
-                       fprintf(fd, "[error] %s: unknown attribute name %s\n",
+                       fprintf(fd, "[warning] %s: unknown attribute name %s\n",
                                __func__, left->u.unary_expression.u.string);
-                       return NULL;
+                       /* Fall-through after warning */
                }
        }
        if (!has_size) {
@@ -1238,13 +1413,13 @@ struct declaration *ctf_declaration_integer_visit(FILE *fd, int depth,
        }
        integer_declaration = integer_declaration_new(size,
                                byte_order, signedness, alignment,
-                               base, encoding);
+                               base, encoding, clock);
        return &integer_declaration->p;
 }
 
 static
 struct declaration *ctf_declaration_floating_point_visit(FILE *fd, int depth,
-               struct cds_list_head *expressions,
+               struct bt_list_head *expressions,
                struct ctf_trace *trace)
 {
        struct ctf_node *expression;
@@ -1253,11 +1428,11 @@ struct declaration *ctf_declaration_floating_point_visit(FILE *fd, int depth,
        int has_alignment = 0, has_exp_dig = 0, has_mant_dig = 0;
        struct declaration_float *float_declaration;
 
-       cds_list_for_each_entry(expression, expressions, siblings) {
+       bt_list_for_each_entry(expression, expressions, siblings) {
                struct ctf_node *left, *right;
 
-               left = _cds_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
-               right = _cds_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
+               left = _bt_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
+               right = _bt_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
                assert(left->u.unary_expression.type == UNARY_STRING);
                if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
                        byte_order = get_byte_order(fd, depth, right, trace);
@@ -1294,9 +1469,9 @@ struct declaration *ctf_declaration_floating_point_visit(FILE *fd, int depth,
                        }
                        has_alignment = 1;
                } else {
-                       fprintf(fd, "[error] %s: unknown attribute name %s\n",
+                       fprintf(fd, "[warning] %s: unknown attribute name %s\n",
                                __func__, left->u.unary_expression.u.string);
-                       return NULL;
+                       /* Fall-through after warning */
                }
        }
        if (!has_mant_dig) {
@@ -1323,7 +1498,7 @@ struct declaration *ctf_declaration_floating_point_visit(FILE *fd, int depth,
 
 static
 struct declaration *ctf_declaration_string_visit(FILE *fd, int depth,
-               struct cds_list_head *expressions,
+               struct bt_list_head *expressions,
                struct ctf_trace *trace)
 {
        struct ctf_node *expression;
@@ -1331,11 +1506,11 @@ struct declaration *ctf_declaration_string_visit(FILE *fd, int depth,
        enum ctf_string_encoding encoding = CTF_STRING_UTF8;
        struct declaration_string *string_declaration;
 
-       cds_list_for_each_entry(expression, expressions, siblings) {
+       bt_list_for_each_entry(expression, expressions, siblings) {
                struct ctf_node *left, *right;
 
-               left = _cds_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
-               right = _cds_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
+               left = _bt_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
+               right = _bt_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
                assert(left->u.unary_expression.type == UNARY_STRING);
                if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
                        if (right->u.unary_expression.type != UNARY_STRING) {
@@ -1345,9 +1520,9 @@ struct declaration *ctf_declaration_string_visit(FILE *fd, int depth,
                        }
                        encoding_c = right->u.unary_expression.u.string;
                } else {
-                       fprintf(fd, "[error] %s: unknown attribute name %s\n",
+                       fprintf(fd, "[warning] %s: unknown attribute name %s\n",
                                __func__, left->u.unary_expression.u.string);
-                       return NULL;
+                       /* Fall-through after warning */
                }
        }
        if (encoding_c && !strcmp(encoding_c, "ASCII"))
@@ -1368,7 +1543,7 @@ struct declaration *ctf_type_specifier_list_visit(FILE *fd,
 
        assert(type_specifier_list->type == NODE_TYPE_SPECIFIER_LIST);
 
-       first = _cds_list_first_entry(&type_specifier_list->u.type_specifier_list.head, struct ctf_node, siblings);
+       first = _bt_list_first_entry(&type_specifier_list->u.type_specifier_list.head, struct ctf_node, siblings);
 
        assert(first->type == NODE_TYPE_SPECIFIER);
 
@@ -1432,7 +1607,7 @@ struct declaration *ctf_type_specifier_list_visit(FILE *fd,
 }
 
 static
-int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_event *event, struct ctf_trace *trace)
+int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_event_declaration *event, struct ctf_trace *trace)
 {
        int ret = 0;
 
@@ -1517,7 +1692,7 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                                goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
-                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                       _bt_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        event->declaration_scope, trace);
                        if (!declaration) {
@@ -1538,7 +1713,7 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                                goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
-                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                       _bt_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        event->declaration_scope, trace);
                        if (!declaration) {
@@ -1550,10 +1725,25 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                                goto error;
                        }
                        event->fields_decl = container_of(declaration, struct declaration_struct, p);
+               } else if (!strcmp(left, "loglevel")) {
+                       int64_t loglevel = -1;
+
+                       if (CTF_EVENT_FIELD_IS_SET(event, loglevel)) {
+                               fprintf(fd, "[error] %s: loglevel already declared in event declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       ret = get_unary_signed(&node->u.ctf_expression.right, &loglevel);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for event loglevel\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       event->loglevel = (int) loglevel;
+                       CTF_EVENT_SET_FIELD(event, loglevel);
                } else {
-                       fprintf(fd, "[error] %s: attribute \"%s\" is unknown in event declaration.\n", __func__, left);
-                       ret = -EINVAL;
-                       goto error;
+                       fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in event declaration.\n", __func__, left);
+                       /* Fall-through after warning */
                }
 error:
                g_free(left);
@@ -1573,11 +1763,14 @@ int ctf_event_visit(FILE *fd, int depth, struct ctf_node *node,
 {
        int ret = 0;
        struct ctf_node *iter;
-       struct ctf_event *event;
+       struct ctf_event_declaration *event;
+       struct bt_ctf_event_decl *event_decl;
 
-       event = g_new0(struct ctf_event, 1);
+       event_decl = g_new0(struct bt_ctf_event_decl, 1);
+       event = &event_decl->parent;
        event->declaration_scope = new_declaration_scope(parent_declaration_scope);
-       cds_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
+       event->loglevel = -1;
+       bt_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
                ret = ctf_event_declaration_visit(fd, depth + 1, iter, event, trace);
                if (ret)
                        goto error;
@@ -1616,8 +1809,9 @@ int ctf_event_visit(FILE *fd, int depth, struct ctf_node *node,
                g_ptr_array_set_size(event->stream->events_by_id, event->id + 1);
        g_ptr_array_index(event->stream->events_by_id, event->id) = event;
        g_hash_table_insert(event->stream->event_quark_to_id,
-                           (gpointer)(unsigned long) event->name,
+                           (gpointer) (unsigned long) event->name,
                            &event->id);
+       g_ptr_array_add(trace->event_declarations, event_decl);
        return 0;
 
 error:
@@ -1626,13 +1820,13 @@ error:
        if (event->context_decl)
                declaration_unref(&event->context_decl->p);
        free_declaration_scope(event->declaration_scope);
-       g_free(event);
+       g_free(event_decl);
        return ret;
 }
 
  
 static
-int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_stream_class *stream, struct ctf_trace *trace)
+int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_stream_declaration *stream, struct ctf_trace *trace)
 {
        int ret = 0;
 
@@ -1681,7 +1875,7 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
                                goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
-                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                       _bt_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
                        if (!declaration) {
@@ -1702,7 +1896,7 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
                                goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
-                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                       _bt_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
                        if (!declaration) {
@@ -1723,7 +1917,7 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
                                goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
-                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                       _bt_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
                        if (!declaration) {
@@ -1736,9 +1930,8 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
                        }
                        stream->packet_context_decl = container_of(declaration, struct declaration_struct, p);
                } else {
-                       fprintf(fd, "[error] %s: attribute \"%s\" is unknown in stream declaration.\n", __func__, left);
-                       ret = -EINVAL;
-                       goto error;
+                       fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in stream declaration.\n", __func__, left);
+                       /* Fall-through after warning */
                }
 
 error:
@@ -1759,15 +1952,15 @@ int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
 {
        int ret = 0;
        struct ctf_node *iter;
-       struct ctf_stream_class *stream;
+       struct ctf_stream_declaration *stream;
 
-       stream = g_new0(struct ctf_stream_class, 1);
+       stream = g_new0(struct ctf_stream_declaration, 1);
        stream->declaration_scope = new_declaration_scope(parent_declaration_scope);
        stream->events_by_id = g_ptr_array_new();
        stream->event_quark_to_id = g_hash_table_new(g_direct_hash, g_direct_equal);
        stream->streams = g_ptr_array_new();
        if (node) {
-               cds_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
+               bt_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
                        ret = ctf_stream_declaration_visit(fd, depth + 1, iter, stream, trace);
                        if (ret)
                                goto error;
@@ -1793,6 +1986,7 @@ int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
        if (trace->streams->len <= stream->stream_id)
                g_ptr_array_set_size(trace->streams, stream->stream_id + 1);
        g_ptr_array_index(trace->streams, stream->stream_id) = stream;
+       stream->trace = trace;
 
        return 0;
 
@@ -1866,16 +2060,16 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                        }
                        CTF_TRACE_SET_FIELD(trace, minor);
                } else if (!strcmp(left, "uuid")) {
-                       uuid_t uuid;
+                       unsigned char uuid[BABELTRACE_UUID_LEN];
 
-                       ret = get_unary_uuid(&node->u.ctf_expression.right, &uuid);
+                       ret = get_unary_uuid(&node->u.ctf_expression.right, uuid);
                        if (ret) {
                                fprintf(fd, "[error] %s: unexpected unary expression for trace uuid\n", __func__);
                                ret = -EINVAL;
                                goto error;
                        }
                        if (CTF_TRACE_FIELD_IS_SET(trace, uuid)
-                               && uuid_compare(uuid, trace->uuid)) {
+                               && babeltrace_uuid_compare(uuid, trace->uuid)) {
                                fprintf(fd, "[error] %s: uuid mismatch\n", __func__);
                                ret = -EPERM;
                                goto error;
@@ -1887,7 +2081,7 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                        struct ctf_node *right;
                        int byte_order;
 
-                       right = _cds_list_first_entry(&node->u.ctf_expression.right, struct ctf_node, siblings);
+                       right = _bt_list_first_entry(&node->u.ctf_expression.right, struct ctf_node, siblings);
                        byte_order = get_trace_byte_order(fd, depth, right);
                        if (byte_order < 0)
                                return -EINVAL;
@@ -1921,7 +2115,7 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                                goto error;
                        }
                        declaration = ctf_type_specifier_list_visit(fd, depth,
-                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                       _bt_list_first_entry(&node->u.ctf_expression.right,
                                                struct ctf_node, siblings),
                                        trace->declaration_scope, trace);
                        if (!declaration) {
@@ -1934,9 +2128,7 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                        }
                        trace->packet_header_decl = container_of(declaration, struct declaration_struct, p);
                } else {
-                       fprintf(fd, "[error] %s: attribute \"%s\" is unknown in trace declaration.\n", __func__, left);
-                       ret = -EINVAL;
-                       goto error;
+                       fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in trace declaration.\n", __func__, left);
                }
 
 error:
@@ -1961,7 +2153,8 @@ int ctf_trace_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace
                return -EEXIST;
        trace->declaration_scope = new_declaration_scope(trace->root_declaration_scope);
        trace->streams = g_ptr_array_new();
-       cds_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
+       trace->event_declarations = g_ptr_array_new();
+       bt_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
                ret = ctf_trace_declaration_visit(fd, depth + 1, iter, trace);
                if (ret)
                        goto error;
@@ -1976,11 +2169,6 @@ int ctf_trace_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace
                fprintf(fd, "[error] %s: missing minor field in trace declaration\n", __func__);
                goto error;
        }
-       if (!CTF_TRACE_FIELD_IS_SET(trace, uuid)) {
-               ret = -EPERM;
-               fprintf(fd, "[error] %s: missing uuid field in trace declaration\n", __func__);
-               goto error;
-       }
        if (!CTF_TRACE_FIELD_IS_SET(trace, byte_order)) {
                ret = -EPERM;
                fprintf(fd, "[error] %s: missing byte_order field in trace declaration\n", __func__);
@@ -2004,11 +2192,389 @@ error:
                trace->packet_header_decl = NULL;
        }
        g_ptr_array_free(trace->streams, TRUE);
+       g_ptr_array_free(trace->event_declarations, TRUE);
        free_declaration_scope(trace->declaration_scope);
        trace->declaration_scope = NULL;
        return ret;
 }
 
+static
+int ctf_clock_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
+               struct ctf_clock *clock, struct ctf_trace *trace)
+{
+       int ret = 0;
+
+       switch (node->type) {
+       case NODE_CTF_EXPRESSION:
+       {
+               char *left;
+
+               left = concatenate_unary_strings(&node->u.ctf_expression.left);
+               if (!strcmp(left, "name")) {
+                       char *right;
+
+                       if (CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+                               fprintf(fd, "[error] %s: name already declared in clock declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for clock name\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       clock->name = g_quark_from_string(right);
+                       g_free(right);
+                       CTF_CLOCK_SET_FIELD(clock, name);
+               } else if (!strcmp(left, "uuid")) {
+                       char *right;
+
+                       if (clock->uuid) {
+                               fprintf(fd, "[error] %s: uuid already declared in clock declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for clock uuid\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       clock->uuid = g_quark_from_string(right);
+                       g_free(right);
+               } else if (!strcmp(left, "description")) {
+                       char *right;
+
+                       if (clock->description) {
+                               fprintf(fd, "[warning] %s: duplicated clock description\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for clock description\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       clock->description = right;
+               } else if (!strcmp(left, "freq")) {
+                       if (CTF_CLOCK_FIELD_IS_SET(clock, freq)) {
+                               fprintf(fd, "[error] %s: freq already declared in clock declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->freq);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for clock freq\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       CTF_CLOCK_SET_FIELD(clock, freq);
+               } else if (!strcmp(left, "precision")) {
+                       if (clock->precision) {
+                               fprintf(fd, "[error] %s: precision already declared in clock declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->precision);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for clock precision\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               } else if (!strcmp(left, "offset_s")) {
+                       if (clock->offset_s) {
+                               fprintf(fd, "[error] %s: offset_s already declared in clock declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->offset_s);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for clock offset_s\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               } else if (!strcmp(left, "offset")) {
+                       if (clock->offset) {
+                               fprintf(fd, "[error] %s: offset already declared in clock declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->offset);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for clock offset\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               } else if (!strcmp(left, "absolute")) {
+                       struct ctf_node *right;
+
+                       right = _bt_list_first_entry(&node->u.ctf_expression.right, struct ctf_node, siblings);
+                       ret = get_boolean(fd, depth, right);
+                       if (ret < 0) {
+                               fprintf(fd, "[error] %s: unexpected \"absolute\" right member\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       clock->absolute = ret;
+               } else {
+                       fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in clock declaration.\n", __func__, left);
+               }
+
+error:
+               g_free(left);
+               break;
+       }
+       default:
+               return -EPERM;
+       /* TODO: declaration specifier should be added. */
+       }
+
+       return ret;
+}
+
+static
+int ctf_clock_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+       struct ctf_clock *clock;
+
+       clock = g_new0(struct ctf_clock, 1);
+       /* Default clock frequency is set to 1000000000 */
+       clock->freq = 1000000000ULL;
+       bt_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
+               ret = ctf_clock_declaration_visit(fd, depth + 1, iter, clock, trace);
+               if (ret)
+                       goto error;
+       }
+       if (opt_clock_force_correlate) {
+               /*
+                * User requested to forcibly correlate the clock
+                * sources, even if we have no correlatation
+                * information.
+                */
+               if (!clock->absolute) {
+                       fprintf(fd, "[warning] Forcibly correlating trace clock sources (--clock-force-correlate).\n");
+               }
+               clock->absolute = 1;
+       }
+       if (!CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+               ret = -EPERM;
+               fprintf(fd, "[error] %s: missing namefield in clock declaration\n", __func__);
+               goto error;
+       }
+       if (g_hash_table_size(trace->clocks) > 0) {
+               fprintf(fd, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
+               ret = -EINVAL;
+               goto error;
+       }
+       trace->single_clock = clock;
+       g_hash_table_insert(trace->clocks, (gpointer) (unsigned long) clock->name, clock);
+       return 0;
+
+error:
+       g_free(clock->description);
+       g_free(clock);
+       return ret;
+}
+
+static
+void ctf_clock_default(FILE *fd, int depth, struct ctf_trace *trace)
+{
+       struct ctf_clock *clock;
+
+       clock = g_new0(struct ctf_clock, 1);
+       clock->name = g_quark_from_string("monotonic");
+       clock->uuid = 0;
+       clock->description = g_strdup("Default clock");
+       /* Default clock frequency is set to 1000000000 */
+       clock->freq = 1000000000ULL;
+       if (opt_clock_force_correlate) {
+               /*
+                * User requested to forcibly correlate the clock
+                * sources, even if we have no correlatation
+                * information.
+                */
+               if (!clock->absolute) {
+                       fprintf(fd, "[warning] Forcibly correlating trace clock sources (--clock-force-correlate).\n");
+               }
+               clock->absolute = 1;
+       } else {
+               clock->absolute = 0;    /* Not an absolute reference across traces */
+       }
+
+       trace->single_clock = clock;
+       g_hash_table_insert(trace->clocks, (gpointer) (unsigned long) clock->name, clock);
+}
+
+static
+void clock_free(gpointer data)
+{
+       struct ctf_clock *clock = data;
+
+       g_free(clock->description);
+       g_free(clock);
+}
+
+static
+int ctf_env_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
+               struct ctf_trace *trace)
+{
+       int ret = 0;
+       struct ctf_tracer_env *env = &trace->env;
+
+       switch (node->type) {
+       case NODE_CTF_EXPRESSION:
+       {
+               char *left;
+
+               left = concatenate_unary_strings(&node->u.ctf_expression.left);
+               if (!strcmp(left, "vpid")) {
+                       uint64_t v;
+
+                       if (env->vpid != -1) {
+                               fprintf(fd, "[error] %s: vpid already declared in env declaration\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &v);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for env vpid\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       env->vpid = (int) v;
+                       printf_verbose("env.vpid = %d\n", env->vpid);
+               } else if (!strcmp(left, "procname")) {
+                       char *right;
+
+                       if (env->procname[0]) {
+                               fprintf(fd, "[warning] %s: duplicated env procname\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for env procname\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       strncpy(env->procname, right, TRACER_ENV_LEN);
+                       env->procname[TRACER_ENV_LEN - 1] = '\0';
+                       printf_verbose("env.procname = \"%s\"\n", env->procname);
+               } else if (!strcmp(left, "domain")) {
+                       char *right;
+
+                       if (env->domain[0]) {
+                               fprintf(fd, "[warning] %s: duplicated env domain\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for env domain\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       strncpy(env->domain, right, TRACER_ENV_LEN);
+                       env->domain[TRACER_ENV_LEN - 1] = '\0';
+                       printf_verbose("env.domain = \"%s\"\n", env->domain);
+               } else if (!strcmp(left, "sysname")) {
+                       char *right;
+
+                       if (env->sysname[0]) {
+                               fprintf(fd, "[warning] %s: duplicated env sysname\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for env sysname\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       strncpy(env->sysname, right, TRACER_ENV_LEN);
+                       env->sysname[TRACER_ENV_LEN - 1] = '\0';
+                       printf_verbose("env.sysname = \"%s\"\n", env->sysname);
+               } else if (!strcmp(left, "kernel_release")) {
+                       char *right;
+
+                       if (env->release[0]) {
+                               fprintf(fd, "[warning] %s: duplicated env release\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for env release\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       strncpy(env->release, right, TRACER_ENV_LEN);
+                       env->release[TRACER_ENV_LEN - 1] = '\0';
+                       printf_verbose("env.release = \"%s\"\n", env->release);
+               } else if (!strcmp(left, "kernel_version")) {
+                       char *right;
+
+                       if (env->version[0]) {
+                               fprintf(fd, "[warning] %s: duplicated env version\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                       if (!right) {
+                               fprintf(fd, "[warning] %s: unexpected unary expression for env version\n", __func__);
+                               goto error;     /* ret is 0, so not an actual error, just warn. */
+                       }
+                       strncpy(env->version, right, TRACER_ENV_LEN);
+                       env->version[TRACER_ENV_LEN - 1] = '\0';
+                       printf_verbose("env.version = \"%s\"\n", env->version);
+               } else {
+                       if (is_unary_string(&node->u.ctf_expression.right)) {
+                               char *right;
+
+                               right = concatenate_unary_strings(&node->u.ctf_expression.right);
+                               printf_verbose("env.%s = \"%s\"\n", left, right);
+                       } else if (is_unary_unsigned(&node->u.ctf_expression.right)) {
+                               uint64_t v;
+                               int ret;
+
+                               ret = get_unary_unsigned(&node->u.ctf_expression.right, &v);
+                               assert(ret == 0);
+                               printf_verbose("env.%s = %" PRIu64 "\n", left, v);
+                       } else if (is_unary_signed(&node->u.ctf_expression.right)) {
+                               int64_t v;
+                               int ret;
+
+                               ret = get_unary_signed(&node->u.ctf_expression.right, &v);
+                               assert(ret == 0);
+                               printf_verbose("env.%s = %" PRId64 "\n", left, v);
+                       } else {
+                               printf_verbose("%s: attribute \"%s\" has unknown type.\n", __func__, left);
+                       }
+               }
+
+error:
+               g_free(left);
+               break;
+       }
+       default:
+               return -EPERM;
+       }
+
+       return ret;
+}
+
+static
+int ctf_env_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+
+       trace->env.vpid = -1;
+       trace->env.procname[0] = '\0';
+       trace->env.domain[0] = '\0';
+       trace->env.sysname[0] = '\0';
+       trace->env.release[0] = '\0';
+       trace->env.version[0] = '\0';
+       bt_list_for_each_entry(iter, &node->u.env.declaration_list, siblings) {
+               ret = ctf_env_declaration_visit(fd, depth + 1, iter, trace);
+               if (ret)
+                       goto error;
+       }
+error:
+       return 0;
+}
+
 static
 int ctf_root_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
 {
@@ -2054,21 +2620,44 @@ int ctf_root_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struc
        return 0;
 }
 
+/* TODO: missing metadata "destroy" (memory leak) */
 int ctf_visitor_construct_metadata(FILE *fd, int depth, struct ctf_node *node,
                struct ctf_trace *trace, int byte_order)
 {
        int ret = 0;
        struct ctf_node *iter;
+       int env_clock_done = 0;
 
        printf_verbose("CTF visitor: metadata construction... ");
        trace->byte_order = byte_order;
+       trace->clocks = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                               NULL, clock_free);
 
 retry:
        trace->root_declaration_scope = new_declaration_scope(NULL);
 
        switch (node->type) {
        case NODE_ROOT:
-               cds_list_for_each_entry(iter, &node->u.root.declaration_list,
+               if (!env_clock_done) {
+                       /*
+                        * declarations need to query clock hash table,
+                        * so clock need to be treated first.
+                        */
+                       if (bt_list_empty(&node->u.root.clock)) {
+                               ctf_clock_default(fd, depth + 1, trace);
+                       } else {
+                               bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
+                                       ret = ctf_clock_visit(fd, depth + 1, iter,
+                                                             trace);
+                                       if (ret) {
+                                               fprintf(fd, "[error] %s: clock declaration error\n", __func__);
+                                               goto error;
+                                       }
+                               }
+                       }
+                       env_clock_done = 1;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.declaration_list,
                                        siblings) {
                        ret = ctf_root_declaration_visit(fd, depth + 1, iter, trace);
                        if (ret) {
@@ -2076,7 +2665,7 @@ retry:
                                goto error;
                        }
                }
-               cds_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
                        ret = ctf_trace_visit(fd, depth + 1, iter, trace);
                        if (ret == -EINTR) {
                                free_declaration_scope(trace->root_declaration_scope);
@@ -2097,7 +2686,14 @@ retry:
                        ret = -EINVAL;
                        goto error;
                }
-               cds_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+               bt_list_for_each_entry(iter, &node->u.root.env, siblings) {
+                       ret = ctf_env_visit(fd, depth + 1, iter, trace);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: env declaration error\n", __func__);
+                               goto error;
+                       }
+               }
+               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
                        ret = ctf_stream_visit(fd, depth + 1, iter,
                                               trace->root_declaration_scope, trace);
                        if (ret) {
@@ -2105,7 +2701,7 @@ retry:
                                goto error;
                        }
                }
-               cds_list_for_each_entry(iter, &node->u.root.event, siblings) {
+               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
                        ret = ctf_event_visit(fd, depth + 1, iter,
                                              trace->root_declaration_scope, trace);
                        if (ret) {
@@ -2126,5 +2722,6 @@ retry:
 
 error:
        free_declaration_scope(trace->root_declaration_scope);
+       g_hash_table_destroy(trace->clocks);
        return ret;
 }
This page took 0.041655 seconds and 4 git commands to generate.