Show env. in verbose mode
[babeltrace.git] / formats / ctf / metadata / ctf-visitor-generate-io-struct.c
index dd7c9f411f7aa74ec138a96d4ecc9171d8a7976e..4a71a27e04024dae8ecfab95d69cd5854391bc13 100644 (file)
 #include <inttypes.h>
 #include <endian.h>
 #include <errno.h>
+#include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/list.h>
+#include <babeltrace/types.h>
+#include <babeltrace/ctf/metadata.h>
 #include <uuid/uuid.h>
 #include "ctf-scanner.h"
 #include "ctf-parser.h"
        cds_list_entry((ptr)->next, type, member)
 
 static
-struct declaration *ctf_declaration_specifier_visit(FILE *fd,
-               int depth, struct cds_list_head *head,
+struct declaration *ctf_type_specifier_list_visit(FILE *fd,
+               int depth, struct ctf_node *type_specifier_list,
                struct declaration_scope *declaration_scope,
                struct ctf_trace *trace);
 
+static
+int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
+                    struct declaration_scope *parent_declaration_scope, struct ctf_trace *trace);
+
 /*
  * String returned must be freed by the caller using g_free.
  */
@@ -52,32 +59,78 @@ char *concatenate_unary_strings(struct cds_list_head *head)
        GString *str;
        int i = 0;
 
-       str = g_string_new();
+       str = g_string_new("");
        cds_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))
+                       ^ (i != 0));
                switch (node->u.unary_expression.link) {
                case UNARY_DOTLINK:
-                       g_string_append(str, ".")
+                       g_string_append(str, ".");
                        break;
                case UNARY_ARROWLINK:
-                       g_string_append(str, "->")
+                       g_string_append(str, "->");
                        break;
                case UNARY_DOTDOTDOT:
-                       g_string_append(str, "...")
+                       g_string_append(str, "...");
+                       break;
+               default:
                        break;
                }
-               src_string = u.unary_expression.u.string;
+               src_string = node->u.unary_expression.u.string;
                g_string_append(str, src_string);
                i++;
        }
        return g_string_free(str, FALSE);
 }
 
+static
+GQuark get_map_clock_name_value(struct cds_list_head *head)
+{
+       struct ctf_node *node;
+       const char *name = NULL;
+       int i = 0;
+
+       cds_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 get_unary_unsigned(struct cds_list_head *head, uint64_t *value)
 {
@@ -89,7 +142,34 @@ int get_unary_unsigned(struct cds_list_head *head, uint64_t *value)
                assert(node->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT);
                assert(node->u.unary_expression.link == UNARY_LINK_UNKNOWN);
                assert(i == 0);
-               *value = node->u.unary_expression.unsigned_constant
+               *value = node->u.unary_expression.u.unsigned_constant;
+               i++;
+       }
+       return 0;
+}
+
+static
+int get_unary_signed(struct cds_list_head *head, int64_t *value)
+{
+       struct ctf_node *node;
+       int i = 0;
+
+       cds_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;
@@ -109,14 +189,14 @@ int get_unary_uuid(struct cds_list_head *head, uuid_t *uuid)
                assert(node->u.unary_expression.type == UNARY_STRING);
                assert(node->u.unary_expression.link == UNARY_LINK_UNKNOWN);
                assert(i == 0);
-               src_string = u.unary_expression.u.string;
-               ret = uuid_parse(u.unary_expression.u.string, *uuid);
+               src_string = node->u.unary_expression.u.string;
+               ret = uuid_parse(src_string, *uuid);
        }
        return ret;
 }
 
 static
-struct ctf_stream *trace_stream_lookup(struct ctf_trace *trace, uint64_t stream_id)
+struct ctf_stream_class *trace_stream_lookup(struct ctf_trace *trace, uint64_t stream_id)
 {
        if (trace->streams->len <= stream_id)
                return NULL;
@@ -124,119 +204,137 @@ struct ctf_stream *trace_stream_lookup(struct ctf_trace *trace, uint64_t stream_
 }
 
 static
-void visit_declaration_specifier(struct cds_list_head *declaration_specifier, GString *str)
+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)
+{
+       assert(type_specifier->type == NODE_TYPE_SPECIFIER);
+
+       switch (type_specifier->u.type_specifier.type) {
+       case TYPESPEC_VOID:
+               g_string_append(str, "void");
+               break;
+       case TYPESPEC_CHAR:
+               g_string_append(str, "char");
+               break;
+       case TYPESPEC_SHORT:
+               g_string_append(str, "short");
+               break;
+       case TYPESPEC_INT:
+               g_string_append(str, "int");
+               break;
+       case TYPESPEC_LONG:
+               g_string_append(str, "long");
+               break;
+       case TYPESPEC_FLOAT:
+               g_string_append(str, "float");
+               break;
+       case TYPESPEC_DOUBLE:
+               g_string_append(str, "double");
+               break;
+       case TYPESPEC_SIGNED:
+               g_string_append(str, "signed");
+               break;
+       case TYPESPEC_UNSIGNED:
+               g_string_append(str, "unsigned");
+               break;
+       case TYPESPEC_BOOL:
+               g_string_append(str, "bool");
+               break;
+       case TYPESPEC_COMPLEX:
+               g_string_append(str, "_Complex");
+               break;
+       case TYPESPEC_IMAGINARY:
+               g_string_append(str, "_Imaginary");
+               break;
+       case TYPESPEC_CONST:
+               g_string_append(str, "const");
+               break;
+       case TYPESPEC_ID_TYPE:
+               if (type_specifier->u.type_specifier.id_type)
+                       g_string_append(str, type_specifier->u.type_specifier.id_type);
+               break;
+       case TYPESPEC_STRUCT:
+       {
+               struct ctf_node *node = type_specifier->u.type_specifier.node;
+
+               if (!node->u._struct.name) {
+                       fprintf(fd, "[error] %s: unexpected empty variant name\n", __func__);
+                       return -EINVAL;
+               }
+               g_string_append(str, "struct ");
+               g_string_append(str, node->u._struct.name);
+               break;
+       }
+       case TYPESPEC_VARIANT:
+       {
+               struct ctf_node *node = type_specifier->u.type_specifier.node;
+
+               if (!node->u.variant.name) {
+                       fprintf(fd, "[error] %s: unexpected empty variant name\n", __func__);
+                       return -EINVAL;
+               }
+               g_string_append(str, "variant ");
+               g_string_append(str, node->u.variant.name);
+               break;
+       }
+       case TYPESPEC_ENUM:
+       {
+               struct ctf_node *node = type_specifier->u.type_specifier.node;
+
+               if (!node->u._enum.enum_id) {
+                       fprintf(fd, "[error] %s: unexpected empty enum ID\n", __func__);
+                       return -EINVAL;
+               }
+               g_string_append(str, "enum ");
+               g_string_append(str, node->u._enum.enum_id);
+               break;
+       }
+       case TYPESPEC_FLOATING_POINT:
+       case TYPESPEC_INTEGER:
+       case TYPESPEC_STRING:
+       default:
+               fprintf(fd, "[error] %s: unknown specifier\n", __func__);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+int visit_type_specifier_list(FILE *fd, struct ctf_node *type_specifier_list, GString *str)
 {
        struct ctf_node *iter;
        int alias_item_nr = 0;
-       int err;
+       int ret;
 
-       cds_list_for_each_entry(iter, declaration_specifier, siblings) {
+       cds_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++;
-
-               switch (iter->type) {
-               case NODE_TYPE_SPECIFIER:
-                       switch (iter->u.type_specifier.type) {
-                       case TYPESPEC_VOID:
-                               g_string_append(str, "void");
-                               break;
-                       case TYPESPEC_CHAR:
-                               g_string_append(str, "char");
-                               break;
-                       case TYPESPEC_SHORT:
-                               g_string_append(str, "short");
-                               break;
-                       case TYPESPEC_INT:
-                               g_string_append(str, "int");
-                               break;
-                       case TYPESPEC_LONG:
-                               g_string_append(str, "long");
-                               break;
-                       case TYPESPEC_FLOAT:
-                               g_string_append(str, "float");
-                               break;
-                       case TYPESPEC_DOUBLE:
-                               g_string_append(str, "double");
-                               break;
-                       case TYPESPEC_SIGNED:
-                               g_string_append(str, "signed");
-                               break;
-                       case TYPESPEC_UNSIGNED:
-                               g_string_append(str, "unsigned");
-                               break;
-                       case TYPESPEC_BOOL:
-                               g_string_append(str, "bool");
-                               break;
-                       case TYPESPEC_COMPLEX:
-                               g_string_append(str, "_Complex");
-                               break;
-                       case TYPESPEC_IMAGINARY:
-                               g_string_append(str, "_Imaginary");
-                               break;
-                       case TYPESPEC_CONST:
-                               g_string_append(str, "const");
-                               break;
-                       case TYPESPEC_ID_TYPE:
-                               if (iter->u.type_specifier.id_type)
-                                       g_string_append(str, iter->u.type_specifier.id_type);
-                               break;
-                       default:
-                               fprintf(stderr, "[error] %s: unknown specifier\n", __func__);
-                               err = -EINVAL;
-                               goto error;
-                       }
-                       break;
-               case NODE_ENUM:
-                       if (!iter->u._enum.enum_id) {
-                               fprintf(stderr, "[error] %s: unexpected empty enum ID\n", __func__);
-                               err = -EINVAL;
-                               goto error;
-                       }
-                       g_string_append(str, "enum ");
-                       g_string_append(str, iter->u._enum.enum_id);
-                       break;
-               case NODE_VARIANT:
-                       if (!iter->u.variant.name) {
-                               fprintf(stderr, "[error] %s: unexpected empty variant name\n", __func__);
-                               err = -EINVAL;
-                               goto error;
-                       }
-                       g_string_append(str, "variant ");
-                       g_string_append(str, iter->u.variant.name);
-                       break;
-               case NODE_STRUCT:
-                       if (!iter->u._struct.name) {
-                               fprintf(stderr, "[error] %s: unexpected empty variant name\n", __func__);
-                               err = -EINVAL;
-                               goto error;
-                       }
-                       g_string_append(str, "struct ");
-                       g_string_append(str, iter->u._struct.name);
-                       break;
-               default:
-                       fprintf(stderr, "[error] %s: unexpected node type %d\n", __func__, (int) iter->type);
-                       err = -EINVAL;
-                       goto error;
-               }
+               ret = visit_type_specifier(fd, iter, str);
+               if (ret)
+                       return ret;
        }
        return 0;
-error:
-       return err;
 }
 
 static
-GQuark create_typealias_identifier(int fd, int depth,
-       struct cds_list_head *declaration_specifier,
+GQuark create_typealias_identifier(FILE *fd, int depth,
+       struct ctf_node *type_specifier_list,
        struct ctf_node *node_type_declarator)
 {
+       struct ctf_node *iter;
        GString *str;
-       const char *str_c;
+       char *str_c;
        GQuark alias_q;
        int ret;
 
-       str = g_string_new();
-       ret = visit_declaration_specifier(declaration_specifier, str);
+       str = g_string_new("");
+       ret = visit_type_specifier_list(fd, type_specifier_list, str);
        if (ret) {
                g_string_free(str, TRUE);
                return 0;
@@ -253,12 +351,13 @@ GQuark create_typealias_identifier(int fd, int depth,
 }
 
 static
-struct declaration *ctf_type_declarator_visit(int fd, int depth,
-       struct cds_list_head *declaration_specifier,
+struct declaration *ctf_type_declarator_visit(FILE *fd, int depth,
+       struct ctf_node *type_specifier_list,
        GQuark *field_name,
        struct ctf_node *node_type_declarator,
        struct declaration_scope *declaration_scope,
-       struct declaration *nested_declaration)
+       struct declaration *nested_declaration,
+       struct ctf_trace *trace)
 {
        /*
         * Visit type declarator by first taking care of sequence/array
@@ -266,16 +365,18 @@ struct declaration *ctf_type_declarator_visit(int fd, int depth,
         * of pointers.
         */
 
-       assert(node_type_declarator->u.type_declarator.type != TYPEDEC_UNKNOWN);
+       if (node_type_declarator) {
+               assert(node_type_declarator->u.type_declarator.type != TYPEDEC_UNKNOWN);
 
-       /* TODO: gcc bitfields not supported yet. */
-       if (node_type_declarator->u.type_declarator.bitfield_len != NULL) {
-               fprintf(stderr, "[error] %s: gcc bitfields are not supported yet.\n", __func__);
-               return NULL;
+               /* TODO: gcc bitfields not supported yet. */
+               if (node_type_declarator->u.type_declarator.bitfield_len != NULL) {
+                       fprintf(fd, "[error] %s: gcc bitfields are not supported yet.\n", __func__);
+                       return NULL;
+               }
        }
 
        if (!nested_declaration) {
-               if (!cds_list_empty(&node_type_declarator->u.type_declarator.pointers)) {
+               if (node_type_declarator && !cds_list_empty(&node_type_declarator->u.type_declarator.pointers)) {
                        GQuark alias_q;
 
                        /*
@@ -283,17 +384,38 @@ struct declaration *ctf_type_declarator_visit(int fd, int depth,
                         * the typealiases (else fail).
                         */
                        alias_q = create_typealias_identifier(fd, depth,
-                               declaration_specifier, node_type_declarator);
+                               type_specifier_list, node_type_declarator);
                        nested_declaration = lookup_declaration(alias_q, declaration_scope);
                        if (!nested_declaration) {
-                               fprintf(stderr, "[error] %s: cannot find typealias \"%s\".\n", __func__, g_quark_to_string(alias_q));
+                               fprintf(fd, "[error] %s: cannot find typealias \"%s\".\n", __func__, g_quark_to_string(alias_q));
                                return NULL;
                        }
+                       if (nested_declaration->id == CTF_TYPE_INTEGER) {
+                               struct declaration_integer *integer_declaration =
+                                       container_of(nested_declaration, struct declaration_integer, p);
+                               /* For base to 16 for pointers (expected pretty-print) */
+                               if (!integer_declaration->base) {
+                                       /*
+                                        * We need to do a copy of the
+                                        * integer declaration to modify it. There could be other references to
+                                        * it.
+                                        */
+                                       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->clock);
+                                       nested_declaration = &integer_declaration->p;
+                               }
+                       }
                } else {
-                       nested_declaration = /* parse declaration_specifier */;
+                       nested_declaration = ctf_type_specifier_list_visit(fd, depth,
+                               type_specifier_list, declaration_scope, trace);
                }
        }
 
+       if (!node_type_declarator)
+               return nested_declaration;
+
        if (node_type_declarator->u.type_declarator.type == TYPEDEC_ID) {
                if (node_type_declarator->u.type_declarator.u.id)
                        *field_name = g_quark_from_string(node_type_declarator->u.type_declarator.u.id);
@@ -302,44 +424,75 @@ struct declaration *ctf_type_declarator_visit(int fd, int depth,
                return nested_declaration;
        } else {
                struct declaration *declaration;
-               struct node *length;
+               struct ctf_node *first;
 
                /* TYPEDEC_NESTED */
 
+               if (!nested_declaration) {
+                       fprintf(fd, "[error] %s: nested type is unknown.\n", __func__);
+                       return NULL;
+               }
+
                /* create array/sequence, pass nested_declaration as child. */
-               length = node_type_declarator->u.type_declarator.u.nested.length;
-               if (length) {
-                       switch (length->type) {
-                       case NODE_UNARY_EXPRESSION:
-                               /* Array */
-                               /* TODO */
-               .............
-                               declaration = /* create array */;
-                               break;
-                       case NODE_TYPE_SPECIFIER:
-                               /* Sequence */
-                               declaration = /* create sequence */;
-                               break;
-                       default:
-                               assert(0);
+               if (cds_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, 
+                               struct ctf_node, siblings);
+               assert(first->type == NODE_UNARY_EXPRESSION);
+
+               switch (first->u.unary_expression.type) {
+               case UNARY_UNSIGNED_CONSTANT:
+               {
+                       struct declaration_array *array_declaration;
+                       size_t len;
+
+                       len = first->u.unary_expression.u.unsigned_constant;
+                       array_declaration = array_declaration_new(len, nested_declaration,
+                                               declaration_scope);
+
+                       if (!array_declaration) {
+                               fprintf(fd, "[error] %s: cannot create array declaration.\n", __func__);
+                               return NULL;
+                       }
+                       declaration = &array_declaration->p;
+                       break;
+               }
+               case UNARY_STRING:
+               {
+                       /* Lookup unsigned integer definition, create sequence */
+                       char *length_name = concatenate_unary_strings(&node_type_declarator->u.type_declarator.u.nested.length);
+                       struct declaration_sequence *sequence_declaration;
+
+                       sequence_declaration = sequence_declaration_new(length_name, nested_declaration, declaration_scope);
+                       if (!sequence_declaration) {
+                               fprintf(fd, "[error] %s: cannot create sequence declaration.\n", __func__);
+                               return NULL;
                        }
+                       declaration = &sequence_declaration->p;
+                       break;
+               }
+               default:
+                       assert(0);
                }
 
                /* Pass it as content of outer container */
                declaration = ctf_type_declarator_visit(fd, depth,
-                               declaration_specifier, field_name,
+                               type_specifier_list, field_name,
                                node_type_declarator->u.type_declarator.u.nested.type_declarator,
-                               declaration_scope, declaration);
+                               declaration_scope, declaration, trace);
                return declaration;
        }
 }
 
 static
-int ctf_struct_type_declarators_visit(int fd, int depth,
+int ctf_struct_type_declarators_visit(FILE *fd, int depth,
        struct declaration_struct *struct_declaration,
-       struct cds_list_head *declaration_specifier,
+       struct ctf_node *type_specifier_list,
        struct cds_list_head *type_declarators,
-       struct declaration_scope *declaration_scope)
+       struct declaration_scope *declaration_scope,
+       struct ctf_trace *trace)
 {
        struct ctf_node *iter;
        GQuark field_name;
@@ -348,10 +501,21 @@ int ctf_struct_type_declarators_visit(int fd, int depth,
                struct declaration *field_declaration;
 
                field_declaration = ctf_type_declarator_visit(fd, depth,
-                                               declaration_specifier,
+                                               type_specifier_list,
                                                &field_name, iter,
                                                struct_declaration->scope,
-                                               NULL);
+                                               NULL, trace);
+               if (!field_declaration) {
+                       fprintf(fd, "[error] %s: unable to find struct field declaration type\n", __func__);
+                       return -EINVAL;
+               }
+
+               /* Check if field with same name already exists */
+               if (struct_declaration_lookup_field_index(struct_declaration, field_name) >= 0) {
+                       fprintf(fd, "[error] %s: duplicate field %s in struct\n", __func__, g_quark_to_string(field_name));
+                       return -EINVAL;
+               }
+
                struct_declaration_add_field(struct_declaration,
                                             g_quark_to_string(field_name),
                                             field_declaration);
@@ -360,11 +524,12 @@ int ctf_struct_type_declarators_visit(int fd, int depth,
 }
 
 static
-int ctf_variant_type_declarators_visit(int fd, int depth,
-       struct declaration_variant *variant_declaration,
-       struct cds_list_head *declaration_specifier,
+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 declaration_scope *declaration_scope)
+       struct declaration_scope *declaration_scope,
+       struct ctf_trace *trace)
 {
        struct ctf_node *iter;
        GQuark field_name;
@@ -373,11 +538,22 @@ int ctf_variant_type_declarators_visit(int fd, int depth,
                struct declaration *field_declaration;
 
                field_declaration = ctf_type_declarator_visit(fd, depth,
-                                               declaration_specifier,
+                                               type_specifier_list,
                                                &field_name, iter,
-                                               variant_declaration->scope,
-                                               NULL);
-               variant_declaration_add_field(variant_declaration,
+                                               untagged_variant_declaration->scope,
+                                               NULL, trace);
+               if (!field_declaration) {
+                       fprintf(fd, "[error] %s: unable to find variant field declaration type\n", __func__);
+                       return -EINVAL;
+               }
+
+               if (untagged_variant_declaration_get_field_from_tag(untagged_variant_declaration, field_name) != NULL) {
+                       fprintf(fd, "[error] %s: duplicate field %s in variant\n", __func__, g_quark_to_string(field_name));
+                       return -EINVAL;
+               }
+
+
+               untagged_variant_declaration_add_field(untagged_variant_declaration,
                                              g_quark_to_string(field_name),
                                              field_declaration);
        }
@@ -385,9 +561,10 @@ int ctf_variant_type_declarators_visit(int fd, int depth,
 }
 
 static
-int ctf_typedef_visit(int fd, int depth, struct declaration_scope *scope,
-               struct cds_list_head *declaration_specifier,
-               struct cds_list_head *type_declarators)
+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 ctf_trace *trace)
 {
        struct ctf_node *iter;
        GQuark identifier;
@@ -397,9 +574,22 @@ int ctf_typedef_visit(int fd, int depth, struct declaration_scope *scope,
                int ret;
        
                type_declaration = ctf_type_declarator_visit(fd, depth,
-                                       declaration_specifier,
+                                       type_specifier_list,
                                        &identifier, iter,
-                                       scope, NULL);
+                                       scope, NULL, trace);
+               if (!type_declaration) {
+                       fprintf(fd, "[error] %s: problem creating type declaration\n", __func__);
+                       return -EINVAL;
+               }
+               /*
+                * Don't allow typedef and typealias of untagged
+                * variants.
+                */
+               if (type_declaration->id == CTF_TYPE_UNTAGGED_VARIANT) {
+                       fprintf(fd, "[error] %s: typedef of untagged variant is not permitted.\n", __func__);
+                       declaration_unref(type_declaration);
+                       return -EPERM;
+               }
                ret = register_declaration(identifier, type_declaration, scope);
                if (ret) {
                        type_declaration->declaration_free(type_declaration);
@@ -410,13 +600,15 @@ int ctf_typedef_visit(int fd, int depth, struct declaration_scope *scope,
 }
 
 static
-int ctf_typealias_visit(int fd, int depth, struct declaration_scope *scope,
-               struct ctf_node *target, struct ctf_node *alias)
+int ctf_typealias_visit(FILE *fd, int depth, struct declaration_scope *scope,
+               struct ctf_node *target, struct ctf_node *alias,
+               struct ctf_trace *trace)
 {
        struct declaration *type_declaration;
-       struct ctf_node *iter, *node;
+       struct ctf_node *node;
        GQuark dummy_id;
        GQuark alias_q;
+       int err;
 
        /* See ctf_visitor_type_declarator() in the semantic validator. */
 
@@ -424,21 +616,35 @@ int ctf_typealias_visit(int fd, int depth, struct declaration_scope *scope,
         * Create target type declaration.
         */
 
+       if (cds_list_empty(&target->u.typealias_target.type_declarators))
+               node = NULL;
+       else
+               node = _cds_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.declaration_specifier,
-               &dummy_id, &target->u.typealias_target.type_declarators,
-               scope, NULL);
+               target->u.typealias_target.type_specifier_list,
+               &dummy_id, node,
+               scope, NULL, trace);
        if (!type_declaration) {
-               fprintf(stderr, "[error] %s: problem creating type declaration\n", __func__);
+               fprintf(fd, "[error] %s: problem creating type declaration\n", __func__);
                err = -EINVAL;
                goto error;
        }
+       /*
+        * Don't allow typedef and typealias of untagged
+        * variants.
+        */
+       if (type_declaration->id == CTF_TYPE_UNTAGGED_VARIANT) {
+               fprintf(fd, "[error] %s: typedef of untagged variant is not permitted.\n", __func__);
+               declaration_unref(type_declaration);
+               return -EPERM;
+       }
        /*
         * The semantic validator does not check whether the target is
         * abstract or not (if it has an identifier). Check it here.
         */
        if (dummy_id != 0) {
-               fprintf(stderr, "[error] %s: expecting empty identifier\n", __func__);
+               fprintf(fd, "[error] %s: expecting empty identifier\n", __func__);
                err = -EINVAL;
                goto error;
        }
@@ -447,24 +653,26 @@ int ctf_typealias_visit(int fd, int depth, struct declaration_scope *scope,
         */
 
        node = _cds_list_first_entry(&alias->u.typealias_alias.type_declarators,
-                               struct node, siblings);
+                               struct ctf_node, siblings);
        alias_q = create_typealias_identifier(fd, depth,
-                       &alias->u.typealias_alias.declaration_specifier, node);
-       ret = register_declaration(alias_q, type_declaration, scope);
-       if (ret)
+                       alias->u.typealias_alias.type_specifier_list, node);
+       err = register_declaration(alias_q, type_declaration, scope);
+       if (err)
                goto error;
        return 0;
 
 error:
-       type_declaration->declaration_free(type_declaration);
-       return ret;
+       if (type_declaration) {
+               type_declaration->declaration_free(type_declaration);
+       }
+       return err;
 }
 
 static
-int ctf_struct_declaration_list_visit(int fd, int depth,
-       struct ctf_node *iter, struct declaration_struct *struct_declaration)
+int ctf_struct_declaration_list_visit(FILE *fd, int depth,
+       struct ctf_node *iter, struct declaration_struct *struct_declaration,
+       struct ctf_trace *trace)
 {
-       struct declaration *declaration;
        int ret;
 
        switch (iter->type) {
@@ -472,8 +680,8 @@ int ctf_struct_declaration_list_visit(int fd, int depth,
                /* For each declarator, declare type and add type to struct declaration scope */
                ret = ctf_typedef_visit(fd, depth,
                        struct_declaration->scope,
-                       &iter->u._typedef.declaration_specifier,
-                       &iter->u._typedef.type_declarators);
+                       iter->u._typedef.type_specifier_list,
+                       &iter->u._typedef.type_declarators, trace);
                if (ret)
                        return ret;
                break;
@@ -482,7 +690,7 @@ int ctf_struct_declaration_list_visit(int fd, int depth,
                ret = ctf_typealias_visit(fd, depth,
                        struct_declaration->scope,
                        iter->u.typealias.target,
-                       iter->u.typealias.alias);
+                       iter->u.typealias.alias, trace);
                if (ret)
                        return ret;
                break;
@@ -490,68 +698,73 @@ int ctf_struct_declaration_list_visit(int fd, int depth,
                /* Add field to structure declaration */
                ret = ctf_struct_type_declarators_visit(fd, depth,
                                struct_declaration,
-                               &iter->u.struct_or_variant_declaration.declaration_specifier,
-                               &iter->u.struct_or_variant_declaration.type_declarators);
+                               iter->u.struct_or_variant_declaration.type_specifier_list,
+                               &iter->u.struct_or_variant_declaration.type_declarators,
+                               struct_declaration->scope, trace);
                if (ret)
                        return ret;
                break;
        default:
-               fprintf(stderr, "[error] %s: unexpected node type %d\n", __func__, (int) iter->type);
+               fprintf(fd, "[error] %s: unexpected node type %d\n", __func__, (int) iter->type);
                assert(0);
        }
        return 0;
 }
 
 static
-int ctf_variant_declaration_list_visit(int fd, int depth,
-       struct ctf_node *iter, struct declaration_variant *variant_declaration)
+int ctf_variant_declaration_list_visit(FILE *fd, int depth,
+       struct ctf_node *iter,
+       struct declaration_untagged_variant *untagged_variant_declaration,
+       struct ctf_trace *trace)
 {
-       struct declaration *declaration;
        int ret;
 
        switch (iter->type) {
        case NODE_TYPEDEF:
                /* For each declarator, declare type and add type to variant declaration scope */
                ret = ctf_typedef_visit(fd, depth,
-                       variant_declaration->scope,
-                       &iter->u._typedef.declaration_specifier,
-                       &iter->u._typedef.type_declarators);
+                       untagged_variant_declaration->scope,
+                       iter->u._typedef.type_specifier_list,
+                       &iter->u._typedef.type_declarators, trace);
                if (ret)
                        return ret;
                break;
        case NODE_TYPEALIAS:
                /* Declare type with declarator and add type to variant declaration scope */
                ret = ctf_typealias_visit(fd, depth,
-                       variant_declaration->scope,
+                       untagged_variant_declaration->scope,
                        iter->u.typealias.target,
-                       iter->u.typealias.alias);
+                       iter->u.typealias.alias, trace);
                if (ret)
                        return ret;
                break;
        case NODE_STRUCT_OR_VARIANT_DECLARATION:
                /* Add field to structure declaration */
                ret = ctf_variant_type_declarators_visit(fd, depth,
-                               variant_declaration,
-                               &iter->u.struct_or_variant_declaration.declaration_specifier,
-                               &iter->u.struct_or_variant_declaration.type_declarators);
+                               untagged_variant_declaration,
+                               iter->u.struct_or_variant_declaration.type_specifier_list,
+                               &iter->u.struct_or_variant_declaration.type_declarators,
+                               untagged_variant_declaration->scope, trace);
                if (ret)
                        return ret;
                break;
        default:
-               fprintf(stderr, "[error] %s: unexpected node type %d\n", __func__, (int) iter->type);
+               fprintf(fd, "[error] %s: unexpected node type %d\n", __func__, (int) iter->type);
                assert(0);
        }
        return 0;
 }
 
 static
-struct declaration_struct *ctf_declaration_struct_visit(FILE *fd,
+struct declaration *ctf_declaration_struct_visit(FILE *fd,
        int depth, const char *name, struct cds_list_head *declaration_list,
-       int has_body, struct declaration_scope *declaration_scope)
+       int has_body, struct cds_list_head *min_align,
+       struct declaration_scope *declaration_scope,
+       struct ctf_trace *trace)
 {
-       struct declaration *declaration;
        struct declaration_struct *struct_declaration;
        struct ctf_node *iter;
+       int ret;
 
        /*
         * For named struct (without body), lookup in
@@ -563,23 +776,35 @@ struct declaration_struct *ctf_declaration_struct_visit(FILE *fd,
                struct_declaration =
                        lookup_struct_declaration(g_quark_from_string(name),
                                                  declaration_scope);
-               return struct_declaration;
+               return &struct_declaration->p;
        } else {
+               uint64_t min_align_value = 0;
+
                /* For unnamed struct, create type */
                /* For named struct (with body), create type and add to declaration scope */
                if (name) {
                        if (lookup_struct_declaration(g_quark_from_string(name),
                                                      declaration_scope)) {
                                
-                               fprintf(stderr, "[error] %s: struct %s already declared in scope\n", __func__, name);
+                               fprintf(fd, "[error] %s: struct %s already declared in scope\n", __func__, name);
                                return NULL;
                        }
                }
-               struct_declaration = struct_declaration_new(name, declaration_scope);
+               if (!cds_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__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+               struct_declaration = struct_declaration_new(declaration_scope,
+                                                           min_align_value);
                cds_list_for_each_entry(iter, declaration_list, siblings) {
-                       ret = ctf_struct_declaration_list_visit(fd, depth + 1, iter, struct_declaration);
+                       ret = ctf_struct_declaration_list_visit(fd, depth + 1, iter,
+                               struct_declaration, trace);
                        if (ret)
-                               goto error;
+                               goto error_free_declaration;
                }
                if (name) {
                        ret = register_struct_declaration(g_quark_from_string(name),
@@ -587,21 +812,25 @@ struct declaration_struct *ctf_declaration_struct_visit(FILE *fd,
                                        declaration_scope);
                        assert(!ret);
                }
-               return struct_declaration;
+               return &struct_declaration->p;
        }
-error:
+error_free_declaration:
        struct_declaration->p.declaration_free(&struct_declaration->p);
+error:
        return NULL;
 }
 
 static
-struct declaration_variant *ctf_declaration_variant_visit(FILE *fd,
-       int depth, const char *name, struct cds_list_head *declaration_list,
-       int has_body, struct declaration_scope *declaration_scope)
+struct declaration *ctf_declaration_variant_visit(FILE *fd,
+       int depth, const char *name, const char *choice,
+       struct cds_list_head *declaration_list,
+       int has_body, struct declaration_scope *declaration_scope,
+       struct ctf_trace *trace)
 {
-       struct declaration *declaration;
+       struct declaration_untagged_variant *untagged_variant_declaration;
        struct declaration_variant *variant_declaration;
        struct ctf_node *iter;
+       int ret;
 
        /*
         * For named variant (without body), lookup in
@@ -610,10 +839,9 @@ struct declaration_variant *ctf_declaration_variant_visit(FILE *fd,
         */
        if (!has_body) {
                assert(name);
-               variant_declaration =
+               untagged_variant_declaration =
                        lookup_variant_declaration(g_quark_from_string(name),
                                                   declaration_scope);
-               return variant_declaration;
        } else {
                /* For unnamed variant, create type */
                /* For named variant (with body), create type and add to declaration scope */
@@ -621,31 +849,44 @@ struct declaration_variant *ctf_declaration_variant_visit(FILE *fd,
                        if (lookup_variant_declaration(g_quark_from_string(name),
                                                       declaration_scope)) {
                                
-                               fprintf(stderr, "[error] %s: variant %s already declared in scope\n", __func__, name);
+                               fprintf(fd, "[error] %s: variant %s already declared in scope\n", __func__, name);
                                return NULL;
                        }
                }
-               variant_declaration = variant_declaration_new(name, declaration_scope);
+               untagged_variant_declaration = untagged_variant_declaration_new(declaration_scope);
                cds_list_for_each_entry(iter, declaration_list, siblings) {
-                       ret = ctf_variant_declaration_list_visit(fd, depth + 1, iter, variant_declaration);
+                       ret = ctf_variant_declaration_list_visit(fd, depth + 1, iter,
+                               untagged_variant_declaration, trace);
                        if (ret)
                                goto error;
                }
                if (name) {
                        ret = register_variant_declaration(g_quark_from_string(name),
-                                       variant_declaration,
+                                       untagged_variant_declaration,
                                        declaration_scope);
                        assert(!ret);
                }
-               return variant_declaration;
+       }
+       /*
+        * if tagged, create tagged variant and return. else return
+        * untagged variant.
+        */
+       if (!choice) {
+               return &untagged_variant_declaration->p;
+       } else {
+               variant_declaration = variant_declaration_new(untagged_variant_declaration, choice);
+               if (!variant_declaration)
+                       goto error;
+               declaration_unref(&untagged_variant_declaration->p);
+               return &variant_declaration->p;
        }
 error:
-       variant_declaration->p.declaration_free(&variant_declaration->p);
+       untagged_variant_declaration->p.declaration_free(&untagged_variant_declaration->p);
        return NULL;
 }
 
 static
-int ctf_enumerator_list_visit(int fd, int depth,
+int ctf_enumerator_list_visit(FILE *fd, int depth,
                struct ctf_node *enumerator,
                struct declaration_enum *enum_declaration)
 {
@@ -653,11 +894,11 @@ int ctf_enumerator_list_visit(int fd, int depth,
        struct ctf_node *iter;
 
        q = g_quark_from_string(enumerator->u.enumerator.id);
-       if (enum_declaration->integer->signedness) {
+       if (enum_declaration->integer_declaration->signedness) {
                int64_t start, end;
                int nr_vals = 0;
 
-               cds_list_for_each_entry(iter, enumerator->u.enumerator.values, siblings) {
+               cds_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
                        int64_t *target;
 
                        assert(iter->type == NODE_UNARY_EXPRESSION);
@@ -674,11 +915,11 @@ int ctf_enumerator_list_visit(int fd, int depth,
                                *target = iter->u.unary_expression.u.unsigned_constant;
                                break;
                        default:
-                               fprintf(stderr, "[error] %s: invalid enumerator\n", __func__);
+                               fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
                                return -EINVAL;
                        }
                        if (nr_vals > 1) {
-                               fprintf(stderr, "[error] %s: invalid enumerator\n", __func__);
+                               fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
                                return -EINVAL;
                        }
                        nr_vals++;
@@ -686,12 +927,12 @@ int ctf_enumerator_list_visit(int fd, int depth,
                if (nr_vals == 1)
                        end = start;
                enum_signed_insert(enum_declaration, start, end, q);
-       } else
+       } else {
                uint64_t start, end;
                int nr_vals = 0;
 
-               cds_list_for_each_entry(iter, enumerator->u.enumerator.values, siblings) {
-                       int64_t *target;
+               cds_list_for_each_entry(iter, &enumerator->u.enumerator.values, siblings) {
+                       uint64_t *target;
 
                        assert(iter->type == NODE_UNARY_EXPRESSION);
                        if (nr_vals == 0)
@@ -708,14 +949,14 @@ int ctf_enumerator_list_visit(int fd, int depth,
                                 * We don't accept signed constants for enums with unsigned
                                 * container type.
                                 */
-                               fprintf(stderr, "[error] %s: invalid enumerator (signed constant encountered, but enum container type is unsigned)\n", __func__);
+                               fprintf(fd, "[error] %s: invalid enumerator (signed constant encountered, but enum container type is unsigned)\n", __func__);
                                return -EINVAL;
                        default:
-                               fprintf(stderr, "[error] %s: invalid enumerator\n", __func__);
+                               fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
                                return -EINVAL;
                        }
                        if (nr_vals > 1) {
-                               fprintf(stderr, "[error] %s: invalid enumerator\n", __func__);
+                               fprintf(fd, "[error] %s: invalid enumerator\n", __func__);
                                return -EINVAL;
                        }
                        nr_vals++;
@@ -728,9 +969,9 @@ int ctf_enumerator_list_visit(int fd, int depth,
 }
 
 static
-struct declaration *ctf_declaration_enum_visit(int fd, int depth,
+struct declaration *ctf_declaration_enum_visit(FILE *fd, int depth,
                        const char *name,
-                       struct cds_list_head *container_type,
+                       struct ctf_node *container_type,
                        struct cds_list_head *enumerator_list,
                        int has_body,
                        struct declaration_scope *declaration_scope,
@@ -739,8 +980,9 @@ struct declaration *ctf_declaration_enum_visit(int fd, int depth,
        struct declaration *declaration;
        struct declaration_enum *enum_declaration;
        struct declaration_integer *integer_declaration;
-       struct ctf_node *iter, *first;
+       struct ctf_node *iter;
        GQuark dummy_id;
+       int ret;
 
        /*
         * For named enum (without body), lookup in
@@ -752,7 +994,7 @@ struct declaration *ctf_declaration_enum_visit(int fd, int depth,
                enum_declaration =
                        lookup_enum_declaration(g_quark_from_string(name),
                                                declaration_scope);
-               return enum_declaration;
+               return &enum_declaration->p;
        } else {
                /* For unnamed enum, create type */
                /* For named enum (with body), create type and add to declaration scope */
@@ -760,32 +1002,34 @@ struct declaration *ctf_declaration_enum_visit(int fd, int depth,
                        if (lookup_enum_declaration(g_quark_from_string(name),
                                                    declaration_scope)) {
                                
-                               fprintf(stderr, "[error] %s: enum %s already declared in scope\n", __func__, name);
+                               fprintf(fd, "[error] %s: enum %s already declared in scope\n", __func__, name);
                                return NULL;
                        }
                }
-               if (cds_list_empty(container_type)) {
-                               fprintf(stderr, "[error] %s: missing container type for enumeration\n", __func__, name);
+               if (!container_type) {
+                       declaration = lookup_declaration(g_quark_from_static_string("int"),
+                                                        declaration_scope);
+                       if (!declaration) {
+                               fprintf(fd, "[error] %s: \"int\" type declaration missing for enumeration\n", __func__);
                                return NULL;
-                       
-               }
-               first = _cds_list_first_entry(container_type, struct node, siblings);
-               switch (first->type) {
-               case NODE_INTEGER:
-               case NODE_TYPE_SPECIFIER:
+                       }
+               } else {
                        declaration = ctf_type_declarator_visit(fd, depth,
                                                container_type,
-                                               &dummy_id, iter,
+                                               &dummy_id, NULL,
                                                declaration_scope,
-                                               NULL);
-                       assert(declaration->id == CTF_TYPE_INTEGER);
-                       integer_declaration = container_of(declaration, struct declaration_integer, p);
-                       break;
+                                               NULL, trace);
                }
-               default:
-                       assert(0);
+               if (!declaration) {
+                       fprintf(fd, "[error] %s: unable to create container type for enumeration\n", __func__);
+                       return NULL;
+               }
+               if (declaration->id != CTF_TYPE_INTEGER) {
+                       fprintf(fd, "[error] %s: container type for enumeration is not integer\n", __func__);
+                       return NULL;
                }
-               enum_declaration = enum_declaration_new(name, integer_declaration);
+               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);
@@ -798,7 +1042,7 @@ struct declaration *ctf_declaration_enum_visit(int fd, int depth,
                                        declaration_scope);
                        assert(!ret);
                }
-               return enum_declaration;
+               return &enum_declaration->p;
        }
 error:
        enum_declaration->p.declaration_free(&enum_declaration->p);
@@ -806,16 +1050,18 @@ error:
 }
 
 static
-struct declaration *ctf_declaration_type_specifier_visit(int fd, int depth,
-               struct cds_list_head *declaration_specifier,
+struct declaration *ctf_declaration_type_specifier_visit(FILE *fd, int depth,
+               struct ctf_node *type_specifier_list,
                struct declaration_scope *declaration_scope)
 {
        GString *str;
        struct declaration *declaration;
-       const char *str_c;
+       char *str_c;
+       int ret;
+       GQuark id_q;
 
-       str = g_string_new();
-       ret = visit_declaration_specifier(declaration_specifier, str);
+       str = g_string_new("");
+       ret = visit_type_specifier_list(fd, type_specifier_list, str);
        if (ret)
                return NULL;
        str_c = g_string_free(str, FALSE);
@@ -829,10 +1075,10 @@ struct declaration *ctf_declaration_type_specifier_visit(int fd, int depth,
  * Returns 0/1 boolean, or < 0 on error.
  */
 static
-int get_boolean(int fd, int depth, struct node *unary_expression)
+int get_boolean(FILE *fd, int depth, struct ctf_node *unary_expression)
 {
        if (unary_expression->type != NODE_UNARY_EXPRESSION) {
-               fprintf(stderr, "[error] %s: expecting unary expression\n",
+               fprintf(fd, "[error] %s: expecting unary expression\n",
                        __func__);
                return -EINVAL;
        }
@@ -857,13 +1103,13 @@ int get_boolean(int fd, int depth, struct node *unary_expression)
                else if (!strcmp(unary_expression->u.unary_expression.u.string, "FALSE"))
                        return 0;
                else {
-                       fprintf(stderr, "[error] %s: unexpected string \"%s\"\n",
+                       fprintf(fd, "[error] %s: unexpected string \"%s\"\n",
                                __func__, unary_expression->u.unary_expression.u.string);
                        return -EINVAL;
                }
                break;
        default:
-               fprintf(stderr, "[error] %s: unexpected unary expression type\n",
+               fprintf(fd, "[error] %s: unexpected unary expression type\n",
                        __func__);
                return -EINVAL;
        } 
@@ -871,12 +1117,35 @@ int get_boolean(int fd, int depth, struct node *unary_expression)
 }
 
 static
-int get_byte_order(int fd, int depth, struct node *unary_expression)
+int get_trace_byte_order(FILE *fd, int depth, struct ctf_node *unary_expression)
+{
+       int byte_order;
+
+       if (unary_expression->u.unary_expression.type != UNARY_STRING) {
+               fprintf(fd, "[error] %s: byte_order: expecting string\n",
+                       __func__);
+               return -EINVAL;
+       }
+       if (!strcmp(unary_expression->u.unary_expression.u.string, "be"))
+               byte_order = BIG_ENDIAN;
+       else if (!strcmp(unary_expression->u.unary_expression.u.string, "le"))
+               byte_order = LITTLE_ENDIAN;
+       else {
+               fprintf(fd, "[error] %s: unexpected string \"%s\". Should be \"native\", \"network\", \"be\" or \"le\".\n",
+                       __func__, unary_expression->u.unary_expression.u.string);
+               return -EINVAL;
+       }
+       return byte_order;
+}
+
+static
+int get_byte_order(FILE *fd, int depth, struct ctf_node *unary_expression,
+               struct ctf_trace *trace)
 {
        int byte_order;
 
        if (unary_expression->u.unary_expression.type != UNARY_STRING) {
-               fprintf(stderr, "[error] %s: byte_order: expecting string\n",
+               fprintf(fd, "[error] %s: byte_order: expecting string\n",
                        __func__);
                return -EINVAL;
        }
@@ -889,42 +1158,45 @@ int get_byte_order(int fd, int depth, struct node *unary_expression)
        else if (!strcmp(unary_expression->u.unary_expression.u.string, "le"))
                byte_order = LITTLE_ENDIAN;
        else {
-               fprintf(stderr, "[error] %s: unexpected string \"%s\". Should be \"native\", \"network\", \"be\" or \"le\".\n",
-                       __func__, right->u.unary_expression.u.string);
+               fprintf(fd, "[error] %s: unexpected string \"%s\". Should be \"native\", \"network\", \"be\" or \"le\".\n",
+                       __func__, unary_expression->u.unary_expression.u.string);
                return -EINVAL;
        }
        return byte_order;
 }
 
 static
-struct declaration *ctf_declaration_integer_visit(int fd, int depth,
+struct declaration *ctf_declaration_integer_visit(FILE *fd, int depth,
                struct cds_list_head *expressions,
                struct ctf_trace *trace)
 {
-       struct node *expression;
-       uint64_t alignment, size;
+       struct ctf_node *expression;
+       uint64_t alignment = 1, size = 0;
        int byte_order = trace->byte_order;
        int signedness = 0;
        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) {
-               struct node *left, *right;
+               struct ctf_node *left, *right;
 
-               left = expression->u.ctf_expression.left;
-               right = expression->u.ctf_expression.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);
                assert(left->u.unary_expression.type == UNARY_STRING);
                if (!strcmp(left->u.unary_expression.u.string, "signed")) {
                        signedness = get_boolean(fd, depth, right);
                        if (signedness < 0)
                                return NULL;
                } else if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
-                       byte_order = get_byte_order(fd, depth, right);
+                       byte_order = get_byte_order(fd, depth, right, trace);
                        if (byte_order < 0)
                                return NULL;
                } else if (!strcmp(left->u.unary_expression.u.string, "size")) {
                        if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                               fprintf(stderr, "[error] %s: size: expecting unsigned constant\n",
+                               fprintf(fd, "[error] %s: size: expecting unsigned constant\n",
                                        __func__);
                                return NULL;
                        }
@@ -932,21 +1204,137 @@ struct declaration *ctf_declaration_integer_visit(int fd, int depth,
                        has_size = 1;
                } else if (!strcmp(left->u.unary_expression.u.string, "align")) {
                        if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                               fprintf(stderr, "[error] %s: align: expecting unsigned constant\n",
+                               fprintf(fd, "[error] %s: align: expecting unsigned constant\n",
                                        __func__);
                                return NULL;
                        }
                        alignment = right->u.unary_expression.u.unsigned_constant;
+                       /* Make sure alignment is a power of two */
+                       if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
+                               fprintf(fd, "[error] %s: align: expecting power of two\n",
+                                       __func__);
+                               return NULL;
+                       }
                        has_alignment = 1;
-               } else {
-                       fprintf(stderr, "[error] %s: unknown attribute name %s\n",
-                               __func__, left->u.unary_expression.u.string);
-                       return NULL;
-               }
-       }
-       if (!has_size) {
-               fprintf(stderr, "[error] %s: missing size attribute\n", __func__);
-               return NULL;
+               } else if (!strcmp(left->u.unary_expression.u.string, "base")) {
+                       switch (right->u.unary_expression.type) {
+                       case UNARY_UNSIGNED_CONSTANT:
+                               switch (right->u.unary_expression.u.unsigned_constant) {
+                               case 2: 
+                               case 8:
+                               case 10:
+                               case 16:
+                                       base = right->u.unary_expression.u.unsigned_constant;
+                                       break;
+                               default:
+                                       fprintf(fd, "[error] %s: base not supported (%" PRIu64 ")\n",
+                                               __func__, right->u.unary_expression.u.unsigned_constant);
+                               return NULL;
+                               }
+                               break;
+                       case UNARY_STRING:
+                       {
+                               char *s_right = concatenate_unary_strings(&expression->u.ctf_expression.right);
+                               if (!s_right) {
+                                       fprintf(fd, "[error] %s: unexpected unary expression for integer base\n", __func__);
+                                       g_free(s_right);
+                                       return NULL;
+                               }
+                               if (!strcmp(s_right, "decimal") || !strcmp(s_right, "dec") || !strcmp(s_right, "d")
+                                   || !strcmp(s_right, "i") || !strcmp(s_right, "u")) {
+                                       base = 10;
+                               } else if (!strcmp(s_right, "hexadecimal") || !strcmp(s_right, "hex")
+                                   || !strcmp(s_right, "x") || !strcmp(s_right, "X")
+                                   || !strcmp(s_right, "p")) {
+                                       base = 16;
+                               } else if (!strcmp(s_right, "octal") || !strcmp(s_right, "oct")
+                                   || !strcmp(s_right, "o")) {
+                                       base = 8;
+                               } else if (!strcmp(s_right, "binary") || !strcmp(s_right, "b")) {
+                                       base = 2;
+                               } else {
+                                       fprintf(fd, "[error] %s: unexpected expression for integer base (%s)\n", __func__, s_right);
+                                       g_free(s_right);
+                                       return NULL;
+                               }
+
+                               g_free(s_right);
+                               break;
+                       }
+                       default:
+                               fprintf(fd, "[error] %s: base: expecting unsigned constant or unary string\n",
+                                       __func__);
+                               return NULL;
+                       }
+               } else if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
+                       char *s_right;
+
+                       if (right->u.unary_expression.type != UNARY_STRING) {
+                               fprintf(fd, "[error] %s: encoding: expecting unary string\n",
+                                       __func__);
+                               return NULL;
+                       }
+                       s_right = concatenate_unary_strings(&expression->u.ctf_expression.right);
+                       if (!s_right) {
+                               fprintf(fd, "[error] %s: unexpected unary expression for integer base\n", __func__);
+                               g_free(s_right);
+                               return NULL;
+                       }
+                       if (!strcmp(s_right, "UTF8")
+                           || !strcmp(s_right, "utf8")
+                           || !strcmp(s_right, "utf-8")
+                           || !strcmp(s_right, "UTF-8"))
+                               encoding = CTF_STRING_UTF8;
+                       else if (!strcmp(s_right, "ASCII")
+                           || !strcmp(s_right, "ascii"))
+                               encoding = CTF_STRING_ASCII;
+                       else if (!strcmp(s_right, "none"))
+                               encoding = CTF_STRING_NONE;
+                       else {
+                               fprintf(fd, "[error] %s: unknown string encoding \"%s\"\n", __func__, s_right);
+                               g_free(s_right);
+                               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, "[warning] %s: unknown attribute name %s\n",
+                               __func__, left->u.unary_expression.u.string);
+                       /* Fall-through after warning */
+               }
+       }
+       if (!has_size) {
+               fprintf(fd, "[error] %s: missing size attribute\n", __func__);
+               return NULL;
        }
        if (!has_alignment) {
                if (size % CHAR_BIT) {
@@ -958,33 +1346,35 @@ struct declaration *ctf_declaration_integer_visit(int fd, int depth,
                }
        }
        integer_declaration = integer_declaration_new(size,
-                               byte_order, signedness, alignment);
+                               byte_order, signedness, alignment,
+                               base, encoding, clock);
        return &integer_declaration->p;
 }
 
 static
-struct declaration *ctf_declaration_floating_point_visit(int fd, int depth,
+struct declaration *ctf_declaration_floating_point_visit(FILE *fd, int depth,
                struct cds_list_head *expressions,
                struct ctf_trace *trace)
 {
-       struct node *expression;
-       uint64_t alignment, exp_dig, mant_dig, byte_order = trace->byte_order;
+       struct ctf_node *expression;
+       uint64_t alignment = 1, exp_dig = 0, mant_dig = 0,
+               byte_order = trace->byte_order;
        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) {
-               struct node *left, *right;
+               struct ctf_node *left, *right;
 
-               left = expression->u.ctf_expression.left;
-               right = expression->u.ctf_expression.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);
                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);
+                       byte_order = get_byte_order(fd, depth, right, trace);
                        if (byte_order < 0)
                                return NULL;
                } else if (!strcmp(left->u.unary_expression.u.string, "exp_dig")) {
                        if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                               fprintf(stderr, "[error] %s: exp_dig: expecting unsigned constant\n",
+                               fprintf(fd, "[error] %s: exp_dig: expecting unsigned constant\n",
                                        __func__);
                                return NULL;
                        }
@@ -992,7 +1382,7 @@ struct declaration *ctf_declaration_floating_point_visit(int fd, int depth,
                        has_exp_dig = 1;
                } else if (!strcmp(left->u.unary_expression.u.string, "mant_dig")) {
                        if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                               fprintf(stderr, "[error] %s: mant_dig: expecting unsigned constant\n",
+                               fprintf(fd, "[error] %s: mant_dig: expecting unsigned constant\n",
                                        __func__);
                                return NULL;
                        }
@@ -1000,24 +1390,30 @@ struct declaration *ctf_declaration_floating_point_visit(int fd, int depth,
                        has_mant_dig = 1;
                } else if (!strcmp(left->u.unary_expression.u.string, "align")) {
                        if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                               fprintf(stderr, "[error] %s: align: expecting unsigned constant\n",
+                               fprintf(fd, "[error] %s: align: expecting unsigned constant\n",
                                        __func__);
                                return NULL;
                        }
                        alignment = right->u.unary_expression.u.unsigned_constant;
+                       /* Make sure alignment is a power of two */
+                       if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
+                               fprintf(fd, "[error] %s: align: expecting power of two\n",
+                                       __func__);
+                               return NULL;
+                       }
                        has_alignment = 1;
                } else {
-                       fprintf(stderr, "[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) {
-               fprintf(stderr, "[error] %s: missing mant_dig attribute\n", __func__);
+               fprintf(fd, "[error] %s: missing mant_dig attribute\n", __func__);
                return NULL;
        }
        if (!has_exp_dig) {
-               fprintf(stderr, "[error] %s: missing exp_dig attribute\n", __func__);
+               fprintf(fd, "[error] %s: missing exp_dig attribute\n", __func__);
                return NULL;
        }
        if (!has_alignment) {
@@ -1035,32 +1431,32 @@ struct declaration *ctf_declaration_floating_point_visit(int fd, int depth,
 }
 
 static
-struct declaration *ctf_declaration_string_visit(int fd, int depth,
+struct declaration *ctf_declaration_string_visit(FILE *fd, int depth,
                struct cds_list_head *expressions,
                struct ctf_trace *trace)
 {
-       struct node *expression;
+       struct ctf_node *expression;
        const char *encoding_c = NULL;
        enum ctf_string_encoding encoding = CTF_STRING_UTF8;
        struct declaration_string *string_declaration;
 
        cds_list_for_each_entry(expression, expressions, siblings) {
-               struct node *left, *right;
+               struct ctf_node *left, *right;
 
-               left = expression->u.ctf_expression.left;
-               right = expression->u.ctf_expression.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);
                assert(left->u.unary_expression.type == UNARY_STRING);
                if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
-                       if (right->u.unary_expression.type != UNARY_UNSIGNED_STRING) {
-                               fprintf(stderr, "[error] %s: encoding: expecting string\n",
+                       if (right->u.unary_expression.type != UNARY_STRING) {
+                               fprintf(fd, "[error] %s: encoding: expecting string\n",
                                        __func__);
                                return NULL;
                        }
                        encoding_c = right->u.unary_expression.u.string;
                } else {
-                       fprintf(stderr, "[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"))
@@ -1070,55 +1466,77 @@ struct declaration *ctf_declaration_string_visit(int fd, int depth,
 }
 
 
-/*
- * Also add named variant, struct or enum to the current declaration scope.
- */
 static
-struct declaration *ctf_declaration_specifier_visit(FILE *fd,
-               int depth, struct cds_list_head *head,
+struct declaration *ctf_type_specifier_list_visit(FILE *fd,
+               int depth, struct ctf_node *type_specifier_list,
                struct declaration_scope *declaration_scope,
                struct ctf_trace *trace)
 {
-       struct declaration *declaration;
-       struct node *first;
+       struct ctf_node *first;
+       struct ctf_node *node;
+
+       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);
+
+       assert(first->type == NODE_TYPE_SPECIFIER);
 
-       first = _cds_list_first_entry(head, struct node, siblings);
+       node = first->u.type_specifier.node;
 
-       switch (first->type) {
-       case NODE_STRUCT:
+       switch (first->u.type_specifier.type) {
+       case TYPESPEC_FLOATING_POINT:
+               return ctf_declaration_floating_point_visit(fd, depth,
+                       &node->u.floating_point.expressions, trace);
+       case TYPESPEC_INTEGER:
+               return ctf_declaration_integer_visit(fd, depth,
+                       &node->u.integer.expressions, trace);
+       case TYPESPEC_STRING:
+               return ctf_declaration_string_visit(fd, depth,
+                       &node->u.string.expressions, trace);
+       case TYPESPEC_STRUCT:
                return ctf_declaration_struct_visit(fd, depth,
-                       first->u._struct.name,
-                       &first->u._struct.declaration_list,
-                       first->u._struct.has_body,
+                       node->u._struct.name,
+                       &node->u._struct.declaration_list,
+                       node->u._struct.has_body,
+                       &node->u._struct.min_align,
                        declaration_scope,
                        trace);
-       case NODE_VARIANT:
+       case TYPESPEC_VARIANT:
                return ctf_declaration_variant_visit(fd, depth,
-                       first->u.variant.name,
-                       &first->u.variant.declaration_list,
-                       first->u.variant.has_body,
+                       node->u.variant.name,
+                       node->u.variant.choice,
+                       &node->u.variant.declaration_list,
+                       node->u.variant.has_body,
                        declaration_scope,
                        trace);
-       case NODE_ENUM:
+       case TYPESPEC_ENUM:
                return ctf_declaration_enum_visit(fd, depth,
-                       first->u._enum.enum_id,
-                       &first->u._enum.container_type,
-                       &first->u._enum.enumerator_list,
-                       first->u._enum.has_body,
+                       node->u._enum.enum_id,
+                       node->u._enum.container_type,
+                       &node->u._enum.enumerator_list,
+                       node->u._enum.has_body,
                        declaration_scope,
                        trace);
-       case NODE_INTEGER:
-               return ctf_declaration_integer_visit(fd, depth,
-                       &first->u.integer.expressions, trace);
-       case NODE_FLOATING_POINT:
-               return ctf_declaration_floating_point_visit(fd, depth,
-                       &first->u.floating_point.expressions, trace);
-       case NODE_STRING:
-               return ctf_declaration_string_visit(fd, depth,
-                       &first->u.string.expressions, trace);
-       case NODE_TYPE_SPECIFIER:
+
+       case TYPESPEC_VOID:
+       case TYPESPEC_CHAR:
+       case TYPESPEC_SHORT:
+       case TYPESPEC_INT:
+       case TYPESPEC_LONG:
+       case TYPESPEC_FLOAT:
+       case TYPESPEC_DOUBLE:
+       case TYPESPEC_SIGNED:
+       case TYPESPEC_UNSIGNED:
+       case TYPESPEC_BOOL:
+       case TYPESPEC_COMPLEX:
+       case TYPESPEC_IMAGINARY:
+       case TYPESPEC_CONST:
+       case TYPESPEC_ID_TYPE:
                return ctf_declaration_type_specifier_visit(fd, depth,
-                               head, declaration_scope, trace);
+                       type_specifier_list, declaration_scope);
+       default:
+               fprintf(fd, "[error] %s: unexpected node type %d\n", __func__, (int) first->u.type_specifier.type);
+               return NULL;
        }
 }
 
@@ -1130,16 +1548,18 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
        switch (node->type) {
        case NODE_TYPEDEF:
                ret = ctf_typedef_visit(fd, depth + 1,
-                                       &node->u._typedef.declaration_specifier,
+                                       event->declaration_scope,
+                                       node->u._typedef.type_specifier_list,
                                        &node->u._typedef.type_declarators,
-                                       event->declaration_scope);
+                                       trace);
                if (ret)
                        return ret;
                break;
        case NODE_TYPEALIAS:
                ret = ctf_typealias_visit(fd, depth + 1,
-                               &node->u.typealias.target, &node->u.typealias.alias
-                               event->declaration_scope);
+                               event->declaration_scope,
+                               node->u.typealias.target, node->u.typealias.alias,
+                               trace);
                if (ret)
                        return ret;
                break;
@@ -1151,66 +1571,115 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
                if (!strcmp(left, "name")) {
                        char *right;
 
-                       if (CTF_EVENT_FIELD_IS_SET(event, name))
-                               return -EPERM;
+                       if (CTF_EVENT_FIELD_IS_SET(event, name)) {
+                               fprintf(fd, "[error] %s: name already declared in event declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
                        right = concatenate_unary_strings(&node->u.ctf_expression.right);
                        if (!right) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for event name\n", __func__);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: unexpected unary expression for event name\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
                        }
                        event->name = g_quark_from_string(right);
                        g_free(right);
                        CTF_EVENT_SET_FIELD(event, name);
                } else if (!strcmp(left, "id")) {
-                       if (CTF_EVENT_FIELD_IS_SET(event, id))
-                               return -EPERM;
+                       if (CTF_EVENT_FIELD_IS_SET(event, id)) {
+                               fprintf(fd, "[error] %s: id already declared in event declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &event->id);
                        if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for event id\n", __func__);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: unexpected unary expression for event id\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_EVENT_SET_FIELD(event, id);
                } else if (!strcmp(left, "stream_id")) {
-                       if (CTF_EVENT_FIELD_IS_SET(event, stream_id))
-                               return -EPERM;
+                       if (CTF_EVENT_FIELD_IS_SET(event, stream_id)) {
+                               fprintf(fd, "[error] %s: stream_id already declared in event declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &event->stream_id);
                        if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for event stream_id\n", __func__);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: unexpected unary expression for event stream_id\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
                        }
                        event->stream = trace_stream_lookup(trace, event->stream_id);
                        if (!event->stream) {
-                               fprintf(stderr, "[error] %s: stream id %" PRIu64 " cannot be found\n", __func__, event->stream_id);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: stream id %" PRIu64 " cannot be found\n", __func__, event->stream_id);
+                               ret = -EINVAL;
+                               goto error;
                        }
                        CTF_EVENT_SET_FIELD(event, stream_id);
                } else if (!strcmp(left, "context")) {
                        struct declaration *declaration;
 
-                       if (!event->definition_scope)
-                               return -EPERM;
-                       declaration = ctf_declaration_specifier_visit(fd, depth,
-                                       &node->u.ctf_expression.right,
+                       if (event->context_decl) {
+                               fprintf(fd, "[error] %s: context already declared in event declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
                                        event->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->type->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        event->context_decl = container_of(declaration, struct declaration_struct, p);
                } else if (!strcmp(left, "fields")) {
                        struct declaration *declaration;
 
-                       if (!event->definition_scope)
-                               return -EPERM;
-                       declaration = ctf_declaration_specifier_visit(fd, depth,
-                                       &node->u.ctf_expression.right,
+                       if (event->fields_decl) {
+                               fprintf(fd, "[error] %s: fields already declared in event declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
                                        event->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->type->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               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, "[warning] %s: attribute \"%s\" is unknown in event declaration.\n", __func__, left);
+                       /* Fall-through after warning */
                }
+error:
                g_free(left);
                break;
        }
@@ -1219,7 +1688,7 @@ int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
        /* TODO: declaration specifier should be added. */
        }
 
-       return 0;
+       return ret;
 }
 
 static
@@ -1229,10 +1698,10 @@ int ctf_event_visit(FILE *fd, int depth, struct ctf_node *node,
        int ret = 0;
        struct ctf_node *iter;
        struct ctf_event *event;
-       struct definition_scope *parent_def_scope;
 
        event = g_new0(struct ctf_event, 1);
        event->declaration_scope = new_declaration_scope(parent_declaration_scope);
+       event->loglevel = -1;
        cds_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
                ret = ctf_event_declaration_visit(fd, depth + 1, iter, event, trace);
                if (ret)
@@ -1240,49 +1709,47 @@ int ctf_event_visit(FILE *fd, int depth, struct ctf_node *node,
        }
        if (!CTF_EVENT_FIELD_IS_SET(event, name)) {
                ret = -EPERM;
-               goto error;
-       }
-       if (!CTF_EVENT_FIELD_IS_SET(event, id)) {
-               ret = -EPERM;
+               fprintf(fd, "[error] %s: missing name field in event declaration\n", __func__);
                goto error;
        }
        if (!CTF_EVENT_FIELD_IS_SET(event, stream_id)) {
+               /* Allow missing stream_id if there is only a single stream */
+               switch (trace->streams->len) {
+               case 0: /* Create stream if there was none. */
+                       ret = ctf_stream_visit(fd, depth, NULL, trace->root_declaration_scope, trace);
+                       if (ret)
+                               goto error;
+                       /* Fall-through */
+               case 1:
+                       event->stream_id = 0;
+                       event->stream = trace_stream_lookup(trace, event->stream_id);
+                       break;
+               default:
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing stream_id field in event declaration\n", __func__);
+                       goto error;
+               }
+       }
+       /* Allow only one event without id per stream */
+       if (!CTF_EVENT_FIELD_IS_SET(event, id)
+           && event->stream->events_by_id->len != 0) {
                ret = -EPERM;
+               fprintf(fd, "[error] %s: missing id field in event declaration\n", __func__);
                goto error;
        }
        if (event->stream->events_by_id->len <= event->id)
                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);
-       parent_def_scope = stream->definition_scope;
-       if (event->context_decl) {
-               event->context =
-                       event->context_decl->definition_new(event->context_decl,
-                               parent_def_scope, 0, 0);
-               set_dynamic_definition_scope(&event->context->p,
-                                            event->context->scope,
-                                            "event.context");
-               parent_def_scope = event->context->scope;
-               declaration_unref(event->context_decl);
-       }
-       if (event->fields_decl) {
-               event->fields =
-                       event->fields_decl->definition_new(event->fields_decl,
-                               parent_def_scope, 0, 0);
-               set_dynamic_definition_scope(&event->fields->p,
-                                            event->fields->scope,
-                                            "event.fields");
-               parent_def_scope = event->fields->scope;
-               declaration_unref(event->fields_decl);
-       }
        return 0;
 
 error:
-       declaration_unref(event->fields_decl);
-       declaration_unref(event->context_decl);
-       free_definition_scope(event->definition_scope);
+       if (event->fields_decl)
+               declaration_unref(&event->fields_decl->p);
+       if (event->context_decl)
+               declaration_unref(&event->context_decl->p);
        free_declaration_scope(event->declaration_scope);
        g_free(event);
        return ret;
@@ -1290,23 +1757,25 @@ error:
 
  
 static
-int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_stream *stream, struct ctf_trace *trace)
+int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_stream_class *stream, struct ctf_trace *trace)
 {
        int ret = 0;
 
        switch (node->type) {
        case NODE_TYPEDEF:
                ret = ctf_typedef_visit(fd, depth + 1,
-                                       &node->u._typedef.declaration_specifier,
+                                       stream->declaration_scope,
+                                       node->u._typedef.type_specifier_list,
                                        &node->u._typedef.type_declarators,
-                                       stream->declaration_scope);
+                                       trace);
                if (ret)
                        return ret;
                break;
        case NODE_TYPEALIAS:
                ret = ctf_typealias_visit(fd, depth + 1,
-                               &node->u.typealias.target, &node->u.typealias.alias
-                               stream->declaration_scope);
+                               stream->declaration_scope,
+                               node->u.typealias.target, node->u.typealias.alias,
+                               trace);
                if (ret)
                        return ret;
                break;
@@ -1315,49 +1784,88 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
                char *left;
 
                left = concatenate_unary_strings(&node->u.ctf_expression.left);
-               if (!strcmp(left, "stream_id")) {
-                       if (CTF_EVENT_FIELD_IS_SET(event, stream_id))
-                               return -EPERM;
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &event->stream_id);
+               if (!strcmp(left, "id")) {
+                       if (CTF_STREAM_FIELD_IS_SET(stream, stream_id)) {
+                               fprintf(fd, "[error] %s: id already declared in stream declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &stream->stream_id);
                        if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for event stream_id\n", __func__);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: unexpected unary expression for stream id\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
                        }
-                       CTF_EVENT_SET_FIELD(event, stream_id);
+                       CTF_STREAM_SET_FIELD(stream, stream_id);
                } else if (!strcmp(left, "event.header")) {
                        struct declaration *declaration;
 
-                       declaration = ctf_declaration_specifier_visit(fd, depth,
-                                       &node->u.ctf_expression.right,
-                                       stream->declaration_scope, stream->definition_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->type->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (stream->event_header_decl) {
+                               fprintf(fd, "[error] %s: event.header already declared in stream declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
+                                       stream->declaration_scope, trace);
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        stream->event_header_decl = container_of(declaration, struct declaration_struct, p);
                } else if (!strcmp(left, "event.context")) {
                        struct declaration *declaration;
 
-                       declaration = ctf_declaration_specifier_visit(fd, depth,
-                                       &node->u.ctf_expression.right,
+                       if (stream->event_context_decl) {
+                               fprintf(fd, "[error] %s: event.context already declared in stream declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->type->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        stream->event_context_decl = container_of(declaration, struct declaration_struct, p);
                } else if (!strcmp(left, "packet.context")) {
                        struct declaration *declaration;
 
-                       declaration = ctf_declaration_specifier_visit(fd, depth,
-                                       &node->u.ctf_expression.right,
+                       if (stream->packet_context_decl) {
+                               fprintf(fd, "[error] %s: packet.context already declared in stream declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
                                        stream->declaration_scope, trace);
-                       if (!declaration)
-                               return -EPERM;
-                       if (declaration->type->id != CTF_TYPE_STRUCT)
-                               return -EPERM;
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
                        stream->packet_context_decl = container_of(declaration, struct declaration_struct, p);
+               } else {
+                       fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in stream declaration.\n", __func__, left);
+                       /* Fall-through after warning */
                }
+
+error:
                g_free(left);
                break;
        }
@@ -1366,7 +1874,7 @@ int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, str
        /* TODO: declaration specifier should be added. */
        }
 
-       return 0;
+       return ret;
 }
 
 static
@@ -1375,68 +1883,54 @@ int ctf_stream_visit(FILE *fd, int depth, struct ctf_node *node,
 {
        int ret = 0;
        struct ctf_node *iter;
-       struct ctf_stream *stream;
-       struct definition_scope *parent_def_scope;
+       struct ctf_stream_class *stream;
 
-       stream = g_new0(struct ctf_stream, 1);
+       stream = g_new0(struct ctf_stream_class, 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_int_hash, g_int_equal);
-       cds_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;
+       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) {
+                       ret = ctf_stream_declaration_visit(fd, depth + 1, iter, stream, trace);
+                       if (ret)
+                               goto error;
+               }
        }
-       if (!CTF_EVENT_FIELD_IS_SET(stream, stream_id)) {
-               ret = -EPERM;
-               goto error;
+       if (CTF_STREAM_FIELD_IS_SET(stream, stream_id)) {
+               /* check that packet header has stream_id field. */
+               if (!trace->packet_header_decl
+                   || struct_declaration_lookup_field_index(trace->packet_header_decl, g_quark_from_static_string("stream_id")) < 0) {
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing stream_id field in packet header declaration, but stream_id attribute is declared for stream.\n", __func__);
+                       goto error;
+               }
+       } else {
+               /* Allow only one id-less stream */
+               if (trace->streams->len != 0) {
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing id field in stream declaration\n", __func__);
+                       goto error;
+               }
+               stream->stream_id = 0;
        }
        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;
-
-       parent_def_scope = NULL;
-       if (stream->packet_context_decl) {
-               stream->packet_context =
-                       stream->packet_context_decl->definition_new(stream->packet_context_decl,
-                               parent_def_scope, 0, 0);
-               set_dynamic_definition_scope(&stream->packet_context->p,
-                                            stream->packet_context->scope,
-                                            "stream.packet.context");
-               parent_def_scope = stream->packet_context->scope;
-               declaration_unref(stream->packet_context_decl);
-       }
-       if (stream->event_header_decl) {
-               stream->event_header =
-                       stream->event_header_decl->definition_new(stream->event_header_decl,
-                               parent_def_scope, 0, 0);
-               set_dynamic_definition_scope(&stream->event_header->p,
-                                            stream->event_header->scope,
-                                            "stream.event.header");
-               parent_def_scope = stream->event_header->scope;
-               declaration_unref(stream->event_header_decl);
-       }
-       if (stream->event_context_decl) {
-               stream->event_context =
-                       stream->event_context_decl->definition_new(stream->event_context_decl,
-                               parent_def_scope, 0, 0);
-               set_dynamic_definition_scope(&stream->event_context->p,
-                                            stream->event_context->scope,
-                                            "stream.event.context");
-               parent_def_scope = stream->event_context->scope;
-               declaration_unref(stream->event_context_decl);
-       }
-       stream->definition_scope = parent_def_scope;
+       stream->trace = trace;
 
        return 0;
 
 error:
-       declaration_unref(stream->event_header);
-       declaration_unref(stream->event_context);
-       declaration_unref(stream->packet_context);
+       if (stream->event_header_decl)
+               declaration_unref(&stream->event_header_decl->p);
+       if (stream->event_context_decl)
+               declaration_unref(&stream->event_context_decl->p);
+       if (stream->packet_context_decl)
+               declaration_unref(&stream->packet_context_decl->p);
+       g_ptr_array_free(stream->streams, TRUE);
        g_ptr_array_free(stream->events_by_id, TRUE);
-       g_hash_table_free(stream->event_quark_to_id);
-       free_definition_scope(stream->definition_scope);
+       g_hash_table_destroy(stream->event_quark_to_id);
        free_declaration_scope(stream->declaration_scope);
        g_free(stream);
        return ret;
@@ -1450,16 +1944,18 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
        switch (node->type) {
        case NODE_TYPEDEF:
                ret = ctf_typedef_visit(fd, depth + 1,
-                                       &node->u._typedef.declaration_specifier,
+                                       trace->declaration_scope,
+                                       node->u._typedef.type_specifier_list,
                                        &node->u._typedef.type_declarators,
-                                       trace->declaration_scope);
+                                       trace);
                if (ret)
                        return ret;
                break;
        case NODE_TYPEALIAS:
                ret = ctf_typealias_visit(fd, depth + 1,
-                               &node->u.typealias.target, &node->u.typealias.alias
-                               trace->declaration_scope);
+                               trace->declaration_scope,
+                               node->u.typealias.target, node->u.typealias.alias,
+                               trace);
                if (ret)
                        return ret;
                break;
@@ -1469,42 +1965,104 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
 
                left = concatenate_unary_strings(&node->u.ctf_expression.left);
                if (!strcmp(left, "major")) {
-                       if (CTF_EVENT_FIELD_IS_SET(trace, major))
-                               return -EPERM;
+                       if (CTF_TRACE_FIELD_IS_SET(trace, major)) {
+                               fprintf(fd, "[error] %s: major already declared in trace declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       }
                        ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->major);
                        if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for trace major number\n", __func__);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: unexpected unary expression for trace major number\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
                        }
-                       CTF_EVENT_SET_FIELD(trace, major);
+                       CTF_TRACE_SET_FIELD(trace, major);
                } else if (!strcmp(left, "minor")) {
-                       if (CTF_EVENT_FIELD_IS_SET(trace, minor))
-                               return -EPERM;
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->minor);
-                       if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for trace minor number\n", __func__);
-                               return -EINVAL;
+                       if (CTF_TRACE_FIELD_IS_SET(trace, minor)) {
+                               fprintf(fd, "[error] %s: minor already declared in trace declaration\n", __func__);
+                               ret = -EPERM;
+                               goto error;
                        }
-                       CTF_EVENT_SET_FIELD(trace, minor);
-               } else if (!strcmp(left, "word_size")) {
-                       if (CTF_EVENT_FIELD_IS_SET(trace, word_size))
-                               return -EPERM;
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->word_size);
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->minor);
                        if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for trace word_size\n", __func__);
-                               return -EINVAL;
+                               fprintf(fd, "[error] %s: unexpected unary expression for trace minor number\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
                        }
-                       CTF_EVENT_SET_FIELD(trace, word_size);
+                       CTF_TRACE_SET_FIELD(trace, minor);
                } else if (!strcmp(left, "uuid")) {
-                       if (CTF_EVENT_FIELD_IS_SET(trace, uuid))
-                               return -EPERM;
-                       ret = get_unary_uuid(&node->u.ctf_expression.right, &trace->uuid);
+                       uuid_t uuid;
+
+                       ret = get_unary_uuid(&node->u.ctf_expression.right, &uuid);
                        if (ret) {
-                               fprintf(stderr, "[error] %s: unexpected unary expression for trace uuid\n", __func__);
+                               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)) {
+                               fprintf(fd, "[error] %s: uuid mismatch\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       } else {
+                               memcpy(trace->uuid, uuid, sizeof(uuid));
+                       }
+                       CTF_TRACE_SET_FIELD(trace, uuid);
+               } else if (!strcmp(left, "byte_order")) {
+                       struct ctf_node *right;
+                       int byte_order;
+
+                       right = _cds_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;
+
+                       if (CTF_TRACE_FIELD_IS_SET(trace, byte_order)
+                               && byte_order != trace->byte_order) {
+                               fprintf(fd, "[error] %s: endianness mismatch\n", __func__);
+                               ret = -EPERM;
+                               goto error;
+                       } else {
+                               if (byte_order != trace->byte_order) {
+                                       trace->byte_order = byte_order;
+                                       /*
+                                        * We need to restart
+                                        * construction of the
+                                        * intermediate representation.
+                                        */
+                                       trace->field_mask = 0;
+                                       CTF_TRACE_SET_FIELD(trace, byte_order);
+                                       ret = -EINTR;
+                                       goto error;
+                               }
+                       }
+                       CTF_TRACE_SET_FIELD(trace, byte_order);
+               } else if (!strcmp(left, "packet.header")) {
+                       struct declaration *declaration;
+
+                       if (trace->packet_header_decl) {
+                               fprintf(fd, "[error] %s: packet.header already declared in trace declaration\n", __func__);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       declaration = ctf_type_specifier_list_visit(fd, depth,
+                                       _cds_list_first_entry(&node->u.ctf_expression.right,
+                                               struct ctf_node, siblings),
+                                       trace->declaration_scope, trace);
+                       if (!declaration) {
+                               ret = -EPERM;
+                               goto error;
                        }
-                       CTF_EVENT_SET_FIELD(trace, uuid);
+                       if (declaration->id != CTF_TYPE_STRUCT) {
+                               ret = -EPERM;
+                               goto error;
+                       }
+                       trace->packet_header_decl = container_of(declaration, struct declaration_struct, p);
+               } else {
+                       fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in trace declaration.\n", __func__, left);
                }
+
+error:
                g_free(left);
                break;
        }
@@ -1513,7 +2071,7 @@ int ctf_trace_declaration_visit(FILE *fd, int depth, struct ctf_node *node, stru
        /* TODO: declaration specifier should be added. */
        }
 
-       return 0;
+       return ret;
 }
 
 static
@@ -1525,94 +2083,505 @@ int ctf_trace_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace
        if (trace->declaration_scope)
                return -EEXIST;
        trace->declaration_scope = new_declaration_scope(trace->root_declaration_scope);
-       trace->definition_scope = new_dynamic_definition_scope(trace->root_definition_scope);
        trace->streams = g_ptr_array_new();
        cds_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;
        }
-       if (!CTF_EVENT_FIELD_IS_SET(trace, major)) {
+       if (!CTF_TRACE_FIELD_IS_SET(trace, major)) {
                ret = -EPERM;
+               fprintf(fd, "[error] %s: missing major field in trace declaration\n", __func__);
                goto error;
        }
-       if (!CTF_EVENT_FIELD_IS_SET(trace, minor)) {
+       if (!CTF_TRACE_FIELD_IS_SET(trace, minor)) {
                ret = -EPERM;
+               fprintf(fd, "[error] %s: missing minor field in trace declaration\n", __func__);
                goto error;
        }
-       if (!CTF_EVENT_FIELD_IS_SET(trace, uuid)) {
+       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_EVENT_FIELD_IS_SET(trace, word_size)) {
+       if (!CTF_TRACE_FIELD_IS_SET(trace, byte_order)) {
                ret = -EPERM;
+               fprintf(fd, "[error] %s: missing byte_order field in trace declaration\n", __func__);
                goto error;
        }
+
+       if (!CTF_TRACE_FIELD_IS_SET(trace, byte_order)) {
+               /* check that the packet header contains a "magic" field */
+               if (!trace->packet_header_decl
+                   || struct_declaration_lookup_field_index(trace->packet_header_decl, g_quark_from_static_string("magic")) < 0) {
+                       ret = -EPERM;
+                       fprintf(fd, "[error] %s: missing both byte_order and packet header magic number in trace declaration\n", __func__);
+                       goto error;
+               }
+       }
        return 0;
 
 error:
+       if (trace->packet_header_decl) {
+               declaration_unref(&trace->packet_header_decl->p);
+               trace->packet_header_decl = NULL;
+       }
        g_ptr_array_free(trace->streams, TRUE);
-       free_definition_scope(stream->definition_scope);
-       free_declaration_scope(stream->declaration_scope);
+       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_EVENT_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 (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;
+                       }
+               } 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 = _cds_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);
+       cds_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 (!CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+               ret = -EPERM;
+               fprintf(fd, "[error] %s: missing namefield in clock declaration\n", __func__);
+               goto error;
+       }
+       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 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, "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, "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 {
+                       printf_verbose("%s: attribute \"%s\" is unknown in environment declaration.\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';
+       cds_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)
+{
+       int ret = 0;
+
+       switch (node->type) {
+       case NODE_TYPEDEF:
+               ret = ctf_typedef_visit(fd, depth + 1,
+                                       trace->root_declaration_scope,
+                                       node->u._typedef.type_specifier_list,
+                                       &node->u._typedef.type_declarators,
+                                       trace);
+               if (ret)
+                       return ret;
+               break;
+       case NODE_TYPEALIAS:
+               ret = ctf_typealias_visit(fd, depth + 1,
+                               trace->root_declaration_scope,
+                               node->u.typealias.target, node->u.typealias.alias,
+                               trace);
+               if (ret)
+                       return ret;
+               break;
+       case NODE_TYPE_SPECIFIER_LIST:
+       {
+               struct declaration *declaration;
+
+               /*
+                * Just add the type specifier to the root scope
+                * declaration scope. Release local reference.
+                */
+               declaration = ctf_type_specifier_list_visit(fd, depth + 1,
+                       node, trace->root_declaration_scope, trace);
+               if (!declaration)
+                       return -ENOMEM;
+               declaration_unref(declaration);
+               break;
+       }
+       default:
+               return -EPERM;
+       }
+
+       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._typedef,
-                                       siblings) {
-                       ret = ctf_typedef_visit(fd, depth + 1,
-                                               &iter->u._typedef.declaration_specifier,
-                                               &iter->u._typedef.type_declarators,
-                                               trace->root_declaration_scope);
-                       if (ret)
-                               return ret;
+               if (!env_clock_done) {
+                       /*
+                        * declarations need to query clock hash table,
+                        * so clock need to be treated first.
+                        */
+                       cds_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;
                }
-               cds_list_for_each_entry(iter, &node->u.root.typealias,
+               cds_list_for_each_entry(iter, &node->u.root.declaration_list,
                                        siblings) {
-                       ret = ctf_typealias_visit(fd, depth + 1,
-                                       &iter->u.typealias.target, &iter->u.typealias.alias
-                                       trace->root_declaration_scope);
-                       if (ret)
-                               return ret;
-               }
-               cds_list_for_each_entry(iter, &node->u.root.declaration_specifier, siblings) {
-                       ret = ctf_declaration_specifier_visit(fd, depth, iter,
-                                       trace->root_declaration_scope, trace);
-                       if (ret)
-                               return ret;
+                       ret = ctf_root_declaration_visit(fd, depth + 1, iter, trace);
+                       if (ret) {
+                               fprintf(fd, "[error] %s: root declaration error\n", __func__);
+                               goto error;
+                       }
                }
                cds_list_for_each_entry(iter, &node->u.root.trace, siblings) {
                        ret = ctf_trace_visit(fd, depth + 1, iter, trace);
-                       if (ret)
-                               return ret;
+                       if (ret == -EINTR) {
+                               free_declaration_scope(trace->root_declaration_scope);
+                               /*
+                                * Need to restart creation of type
+                                * definitions, aliases and
+                                * trace header declarations.
+                                */
+                               goto retry;
+                       }
+                       if (ret) {
+                               fprintf(fd, "[error] %s: trace declaration error\n", __func__);
+                               goto error;
+                       }
+               }
+               if (!trace->streams) {
+                       fprintf(fd, "[error] %s: missing trace declaration\n", __func__);
+                       ret = -EINVAL;
+                       goto error;
+               }
+               cds_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;
+                       }
                }
                cds_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)
-                               return ret;
+                       if (ret) {
+                               fprintf(fd, "[error] %s: stream declaration error\n", __func__);
+                               goto error;
+                       }
                }
                cds_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)
-                               return ret;
+                       if (ret) {
+                               fprintf(fd, "[error] %s: event declaration error\n", __func__);
+                               goto error;
+                       }
                }
                break;
        case NODE_UNKNOWN:
        default:
-               fprintf(stderr, "[error] %s: unknown node type %d\n", __func__,
+               fprintf(fd, "[error] %s: unknown node type %d\n", __func__,
                        (int) node->type);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto error;
        }
+       printf_verbose("done.\n");
+       return ret;
+
+error:
+       free_declaration_scope(trace->root_declaration_scope);
+       g_hash_table_destroy(trace->clocks);
        return ret;
 }
This page took 0.092424 seconds and 4 git commands to generate.