+ 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;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_stream_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_stream_class *stream;
+
+ 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_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_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;
+ stream->trace = trace;
+
+ return 0;
+
+error:
+ 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_destroy(stream->event_quark_to_id);
+ free_declaration_scope(stream->declaration_scope);
+ g_free(stream);
+ return ret;
+}
+
+static
+int ctf_trace_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->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->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, "major")) {
+ 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(fd, "[error] %s: unexpected unary expression for trace major number\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_TRACE_SET_FIELD(trace, major);
+ } else if (!strcmp(left, "minor")) {
+ if (CTF_TRACE_FIELD_IS_SET(trace, minor)) {
+ fprintf(fd, "[error] %s: minor already declared in trace declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &trace->minor);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for trace minor number\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_TRACE_SET_FIELD(trace, minor);
+ } else if (!strcmp(left, "uuid")) {
+ uuid_t uuid;
+
+ ret = get_unary_uuid(&node->u.ctf_expression.right, &uuid);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for trace uuid\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ if (CTF_TRACE_FIELD_IS_SET(trace, uuid)
+ && uuid_compare(uuid, trace->uuid)) {
+ 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;
+ }
+ 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;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_trace_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+
+ if (trace->declaration_scope)
+ return -EEXIST;
+ trace->declaration_scope = new_declaration_scope(trace->root_declaration_scope);
+ trace->streams = g_ptr_array_new();
+ cds_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
+ ret = ctf_trace_declaration_visit(fd, depth + 1, iter, trace);
+ if (ret)
+ goto error;
+ }
+ 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_TRACE_FIELD_IS_SET(trace, minor)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing minor field in trace declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_TRACE_FIELD_IS_SET(trace, uuid)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing uuid field in trace declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_TRACE_FIELD_IS_SET(trace, byte_order)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing byte_order field in trace declaration\n", __func__);
+ 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_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);