+ /*
+ * For named enum (without body), lookup in
+ * declaration scope. Don't take reference on enum
+ * declaration: ref is only taken upon definition.
+ */
+ if (!has_body) {
+ assert(name);
+ enum_declaration =
+ lookup_enum_declaration(g_quark_from_string(name),
+ declaration_scope);
+ return &enum_declaration->p;
+ } else {
+ /* For unnamed enum, create type */
+ /* For named enum (with body), create type and add to declaration scope */
+ if (name) {
+ if (lookup_enum_declaration(g_quark_from_string(name),
+ declaration_scope)) {
+
+ fprintf(fd, "[error] %s: enum %s already declared in scope\n", __func__, name);
+ return NULL;
+ }
+ }
+ 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;
+ }
+ } else {
+ declaration = ctf_type_declarator_visit(fd, depth,
+ container_type,
+ &dummy_id, NULL,
+ declaration_scope,
+ NULL, trace);
+ }
+ 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;
+ }
+ integer_declaration = container_of(declaration, struct declaration_integer, p);
+ enum_declaration = enum_declaration_new(integer_declaration);
+ declaration_unref(&integer_declaration->p); /* leave ref to enum */
+ cds_list_for_each_entry(iter, enumerator_list, siblings) {
+ ret = ctf_enumerator_list_visit(fd, depth + 1, iter, enum_declaration);
+ if (ret)
+ goto error;
+ }
+ if (name) {
+ ret = register_enum_declaration(g_quark_from_string(name),
+ enum_declaration,
+ declaration_scope);
+ assert(!ret);
+ }
+ return &enum_declaration->p;
+ }
+error:
+ enum_declaration->p.declaration_free(&enum_declaration->p);
+ return NULL;
+}
+
+static
+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;
+ char *str_c;
+ int ret;
+ GQuark id_q;
+
+ 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);
+ id_q = g_quark_from_string(str_c);
+ g_free(str_c);
+ declaration = lookup_declaration(id_q, declaration_scope);
+ return declaration;
+}
+
+/*
+ * Returns 0/1 boolean, or < 0 on error.
+ */
+static
+int get_boolean(FILE *fd, int depth, struct ctf_node *unary_expression)
+{
+ if (unary_expression->type != NODE_UNARY_EXPRESSION) {
+ fprintf(fd, "[error] %s: expecting unary expression\n",
+ __func__);
+ return -EINVAL;
+ }
+ switch (unary_expression->u.unary_expression.type) {
+ case UNARY_UNSIGNED_CONSTANT:
+ if (unary_expression->u.unary_expression.u.unsigned_constant == 0)
+ return 0;
+ else
+ return 1;
+ case UNARY_SIGNED_CONSTANT:
+ if (unary_expression->u.unary_expression.u.signed_constant == 0)
+ return 0;
+ else
+ return 1;
+ case UNARY_STRING:
+ if (!strcmp(unary_expression->u.unary_expression.u.string, "true"))
+ return 1;
+ else if (!strcmp(unary_expression->u.unary_expression.u.string, "TRUE"))
+ return 1;
+ else if (!strcmp(unary_expression->u.unary_expression.u.string, "false"))
+ return 0;
+ else if (!strcmp(unary_expression->u.unary_expression.u.string, "FALSE"))
+ return 0;
+ else {
+ fprintf(fd, "[error] %s: unexpected string \"%s\"\n",
+ __func__, unary_expression->u.unary_expression.u.string);
+ return -EINVAL;
+ }
+ break;
+ default:
+ fprintf(fd, "[error] %s: unexpected unary expression type\n",
+ __func__);
+ return -EINVAL;
+ }
+
+}
+
+static
+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(fd, "[error] %s: byte_order: expecting string\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (!strcmp(unary_expression->u.unary_expression.u.string, "native"))
+ byte_order = trace->byte_order;
+ else if (!strcmp(unary_expression->u.unary_expression.u.string, "network"))
+ byte_order = BIG_ENDIAN;
+ else 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
+struct declaration *ctf_declaration_integer_visit(FILE *fd, int depth,
+ struct cds_list_head *expressions,
+ struct ctf_trace *trace)
+{
+ 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 ctf_node *left, *right;
+
+ left = _cds_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
+ right = _cds_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
+ 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, 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(fd, "[error] %s: size: expecting unsigned constant\n",
+ __func__);
+ return NULL;
+ }
+ size = right->u.unary_expression.u.unsigned_constant;
+ has_size = 1;
+ } else if (!strcmp(left->u.unary_expression.u.string, "align")) {
+ if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+ 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 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) {
+ /* bit-packed alignment */
+ alignment = 1;
+ } else {
+ /* byte-packed alignment */
+ alignment = CHAR_BIT;
+ }
+ }
+ integer_declaration = integer_declaration_new(size,
+ byte_order, signedness, alignment,
+ base, encoding, clock);
+ return &integer_declaration->p;
+}
+
+static
+struct declaration *ctf_declaration_floating_point_visit(FILE *fd, int depth,
+ struct cds_list_head *expressions,
+ struct ctf_trace *trace)
+{
+ 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 ctf_node *left, *right;
+
+ left = _cds_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
+ right = _cds_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
+ assert(left->u.unary_expression.type == UNARY_STRING);
+ if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
+ byte_order = get_byte_order(fd, depth, right, trace);
+ 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(fd, "[error] %s: exp_dig: expecting unsigned constant\n",
+ __func__);
+ return NULL;
+ }
+ exp_dig = right->u.unary_expression.u.unsigned_constant;
+ 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(fd, "[error] %s: mant_dig: expecting unsigned constant\n",
+ __func__);
+ return NULL;
+ }
+ mant_dig = right->u.unary_expression.u.unsigned_constant;
+ has_mant_dig = 1;
+ } else if (!strcmp(left->u.unary_expression.u.string, "align")) {
+ if (right->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+ 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(fd, "[warning] %s: unknown attribute name %s\n",
+ __func__, left->u.unary_expression.u.string);
+ /* Fall-through after warning */
+ }
+ }
+ if (!has_mant_dig) {
+ fprintf(fd, "[error] %s: missing mant_dig attribute\n", __func__);
+ return NULL;
+ }
+ if (!has_exp_dig) {
+ fprintf(fd, "[error] %s: missing exp_dig attribute\n", __func__);
+ return NULL;
+ }
+ if (!has_alignment) {
+ if ((mant_dig + exp_dig) % CHAR_BIT) {
+ /* bit-packed alignment */
+ alignment = 1;
+ } else {
+ /* byte-packed alignment */
+ alignment = CHAR_BIT;
+ }
+ }
+ float_declaration = float_declaration_new(mant_dig, exp_dig,
+ byte_order, alignment);
+ return &float_declaration->p;
+}
+
+static
+struct declaration *ctf_declaration_string_visit(FILE *fd, int depth,
+ struct cds_list_head *expressions,
+ struct ctf_trace *trace)
+{
+ 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 ctf_node *left, *right;
+
+ left = _cds_list_first_entry(&expression->u.ctf_expression.left, struct ctf_node, siblings);
+ right = _cds_list_first_entry(&expression->u.ctf_expression.right, struct ctf_node, siblings);
+ assert(left->u.unary_expression.type == UNARY_STRING);
+ if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
+ if (right->u.unary_expression.type != UNARY_STRING) {
+ fprintf(fd, "[error] %s: encoding: expecting string\n",
+ __func__);
+ return NULL;
+ }
+ encoding_c = right->u.unary_expression.u.string;
+ } else {
+ fprintf(fd, "[warning] %s: unknown attribute name %s\n",
+ __func__, left->u.unary_expression.u.string);
+ /* Fall-through after warning */
+ }
+ }
+ if (encoding_c && !strcmp(encoding_c, "ASCII"))
+ encoding = CTF_STRING_ASCII;
+ string_declaration = string_declaration_new(encoding);
+ return &string_declaration->p;
+}
+
+
+static
+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 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);
+
+ node = first->u.type_specifier.node;
+
+ 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,
+ node->u._struct.name,
+ &node->u._struct.declaration_list,
+ node->u._struct.has_body,
+ &node->u._struct.min_align,
+ declaration_scope,
+ trace);
+ case TYPESPEC_VARIANT:
+ return ctf_declaration_variant_visit(fd, depth,
+ node->u.variant.name,
+ node->u.variant.choice,
+ &node->u.variant.declaration_list,
+ node->u.variant.has_body,
+ declaration_scope,
+ trace);
+ case TYPESPEC_ENUM:
+ return ctf_declaration_enum_visit(fd, depth,
+ node->u._enum.enum_id,
+ node->u._enum.container_type,
+ &node->u._enum.enumerator_list,
+ node->u._enum.has_body,
+ declaration_scope,
+ trace);
+
+ 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,
+ type_specifier_list, declaration_scope);
+ default:
+ fprintf(fd, "[error] %s: unexpected node type %d\n", __func__, (int) first->u.type_specifier.type);
+ return NULL;
+ }
+}
+
+static
+int ctf_event_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_event *event, struct ctf_trace *trace)
+{
+ int ret = 0;
+
+ switch (node->type) {
+ case NODE_TYPEDEF:
+ ret = ctf_typedef_visit(fd, depth + 1,
+ event->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,
+ event->declaration_scope,
+ node->u.typealias.target, node->u.typealias.alias,
+ trace);
+ if (ret)
+ return ret;
+ break;
+ case NODE_CTF_EXPRESSION:
+ {
+ char *left;
+
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ if (!strcmp(left, "name")) {
+ char *right;
+
+ 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(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)) {
+ 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(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)) {
+ 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(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(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->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) {
+ 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->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) {
+ 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;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_event_visit(FILE *fd, int depth, struct ctf_node *node,
+ struct declaration_scope *parent_declaration_scope, struct ctf_trace *trace)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ struct ctf_event *event;
+
+ 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)
+ goto error;
+ }
+ if (!CTF_EVENT_FIELD_IS_SET(event, name)) {
+ 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,
+ &event->id);
+ return 0;
+
+error:
+ 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;
+}
+
+
+static
+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,
+ stream->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,
+ stream->declaration_scope,
+ node->u.typealias.target, node->u.typealias.alias,
+ trace);
+ if (ret)
+ return ret;
+ break;
+ case NODE_CTF_EXPRESSION:
+ {
+ char *left;
+
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ 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(fd, "[error] %s: unexpected unary expression for stream id\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_STREAM_SET_FIELD(stream, stream_id);
+ } else if (!strcmp(left, "event.header")) {
+ struct declaration *declaration;
+
+ 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;
+
+ 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) {
+ 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;
+
+ 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) {
+ 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;