+ 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 bt_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,
+ _bt_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 bt_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,
+ _bt_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 if (!strcmp(left, "model.emf.uri")) {
+ char *right;
+
+ if (CTF_EVENT_FIELD_IS_SET(event, model_emf_uri)) {
+ fprintf(fd, "[error] %s: model.emf.uri 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 model.emf.uri\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ event->model_emf_uri = g_quark_from_string(right);
+ g_free(right);
+ CTF_EVENT_SET_FIELD(event, model_emf_uri);
+ } 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_declaration *event;
+ struct bt_ctf_event_decl *event_decl;
+
+ event_decl = g_new0(struct bt_ctf_event_decl, 1);
+ event = &event_decl->parent;
+ event->declaration_scope = bt_new_declaration_scope(parent_declaration_scope);
+ event->loglevel = -1;
+ bt_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
+ ret = ctf_event_declaration_visit(fd, depth + 1, iter, event, trace);
+ if (ret)
+ goto error;
+ }
+ 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);
+ g_ptr_array_add(trace->event_declarations, event_decl);
+ return 0;
+
+error:
+ if (event->fields_decl)
+ bt_declaration_unref(&event->fields_decl->p);
+ if (event->context_decl)
+ bt_declaration_unref(&event->context_decl->p);
+ bt_free_declaration_scope(event->declaration_scope);
+ g_free(event_decl);
+ return ret;
+}
+
+
+static
+int ctf_stream_declaration_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_stream_declaration *stream, struct ctf_trace *trace)
+{
+ int ret = 0;
+
+ 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 bt_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,
+ _bt_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 bt_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,
+ _bt_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 bt_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,
+ _bt_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_declaration *stream;
+
+ stream = g_new0(struct ctf_stream_declaration, 1);
+ stream->declaration_scope = bt_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) {
+ bt_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
+ ret = ctf_stream_declaration_visit(fd, depth + 1, iter, stream, trace);
+ if (ret)
+ goto error;
+ }
+ }
+ if (CTF_STREAM_FIELD_IS_SET(stream, stream_id)) {
+ /* check that packet header has stream_id field. */
+ if (!trace->packet_header_decl
+ || bt_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)
+ bt_declaration_unref(&stream->event_header_decl->p);
+ if (stream->event_context_decl)
+ bt_declaration_unref(&stream->event_context_decl->p);
+ if (stream->packet_context_decl)
+ bt_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);
+ bt_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")) {
+ unsigned char uuid[BABELTRACE_UUID_LEN];
+
+ 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)
+ && babeltrace_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 = _bt_list_first_entry(&node->u.ctf_expression.right, struct ctf_node, siblings);
+ byte_order = get_trace_byte_order(fd, depth, right);
+ if (byte_order < 0)
+ return -EINVAL;
+
+ 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 bt_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,
+ _bt_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 = bt_new_declaration_scope(trace->root_declaration_scope);
+ trace->streams = g_ptr_array_new();
+ trace->event_declarations = g_ptr_array_new();
+ bt_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
+ ret = ctf_trace_declaration_visit(fd, depth + 1, iter, trace);
+ if (ret)
+ goto error;
+ }
+ 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, 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
+ || bt_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) {
+ bt_declaration_unref(&trace->packet_header_decl->p);
+ trace->packet_header_decl = NULL;
+ }
+ g_ptr_array_free(trace->streams, TRUE);
+ g_ptr_array_free(trace->event_declarations, TRUE);
+ bt_free_declaration_scope(trace->declaration_scope);
+ trace->declaration_scope = NULL;
+ return ret;
+}
+
+static
+int ctf_clock_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
+ struct ctf_clock *clock, struct ctf_trace *trace)
+{
+ int ret = 0;
+
+ switch (node->type) {
+ case NODE_CTF_EXPRESSION:
+ {
+ char *left;
+
+ left = concatenate_unary_strings(&node->u.ctf_expression.left);
+ if (!strcmp(left, "name")) {
+ char *right;
+
+ if (CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+ fprintf(fd, "[error] %s: name already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ right = concatenate_unary_strings(&node->u.ctf_expression.right);
+ if (!right) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock name\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ clock->name = g_quark_from_string(right);
+ g_free(right);
+ CTF_CLOCK_SET_FIELD(clock, name);
+ } else if (!strcmp(left, "uuid")) {
+ char *right;
+
+ if (clock->uuid) {
+ fprintf(fd, "[error] %s: uuid already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ right = concatenate_unary_strings(&node->u.ctf_expression.right);
+ if (!right) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock uuid\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ clock->uuid = g_quark_from_string(right);
+ g_free(right);
+ } else if (!strcmp(left, "description")) {
+ char *right;
+
+ if (clock->description) {
+ fprintf(fd, "[warning] %s: duplicated clock description\n", __func__);
+ goto error; /* ret is 0, so not an actual error, just warn. */
+ }
+ right = concatenate_unary_strings(&node->u.ctf_expression.right);
+ if (!right) {
+ fprintf(fd, "[warning] %s: unexpected unary expression for clock description\n", __func__);
+ goto error; /* ret is 0, so not an actual error, just warn. */
+ }
+ clock->description = right;
+ } else if (!strcmp(left, "freq")) {
+ if (CTF_CLOCK_FIELD_IS_SET(clock, freq)) {
+ fprintf(fd, "[error] %s: freq already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->freq);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock freq\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_CLOCK_SET_FIELD(clock, freq);
+ } else if (!strcmp(left, "precision")) {
+ if (clock->precision) {
+ fprintf(fd, "[error] %s: precision already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->precision);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock precision\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else if (!strcmp(left, "offset_s")) {
+ if (clock->offset_s) {
+ fprintf(fd, "[error] %s: offset_s already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->offset_s);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock offset_s\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else if (!strcmp(left, "offset")) {
+ if (clock->offset) {
+ fprintf(fd, "[error] %s: offset already declared in clock declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &clock->offset);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for clock offset\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ } else if (!strcmp(left, "absolute")) {
+ struct ctf_node *right;
+
+ right = _bt_list_first_entry(&node->u.ctf_expression.right, struct ctf_node, siblings);
+ ret = get_boolean(fd, depth, right);
+ if (ret < 0) {
+ fprintf(fd, "[error] %s: unexpected \"absolute\" right member\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ clock->absolute = ret;
+ } else {
+ fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in clock declaration.\n", __func__, left);
+ }
+
+error:
+ g_free(left);
+ break;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_clock_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ struct ctf_clock *clock;
+
+ clock = g_new0(struct ctf_clock, 1);
+ /* Default clock frequency is set to 1000000000 */
+ clock->freq = 1000000000ULL;
+ bt_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
+ ret = ctf_clock_declaration_visit(fd, depth + 1, iter, clock, trace);
+ if (ret)
+ goto error;
+ }
+ if (opt_clock_force_correlate) {
+ /*
+ * User requested to forcibly correlate the clock
+ * sources, even if we have no correlation
+ * information.
+ */
+ if (!clock->absolute) {
+ fprintf(fd, "[warning] Forcibly correlating trace clock sources (--clock-force-correlate).\n");
+ }
+ clock->absolute = 1;
+ }
+ if (!CTF_CLOCK_FIELD_IS_SET(clock, name)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing name field in clock declaration\n", __func__);
+ goto error;
+ }
+ if (g_hash_table_size(trace->clocks) > 0) {
+ fprintf(fd, "[error] Only CTF traces with a single clock description are supported by this babeltrace version.\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ trace->single_clock = clock;
+ g_hash_table_insert(trace->clocks, (gpointer) (unsigned long) clock->name, clock);
+ return 0;
+
+error:
+ g_free(clock->description);
+ g_free(clock);
+ return ret;
+}
+
+static
+void ctf_clock_default(FILE *fd, int depth, struct ctf_trace *trace)
+{
+ struct ctf_clock *clock;
+
+ clock = g_new0(struct ctf_clock, 1);
+ clock->name = g_quark_from_string("monotonic");
+ clock->uuid = 0;
+ clock->description = g_strdup("Default clock");
+ /* Default clock frequency is set to 1000000000 */
+ clock->freq = 1000000000ULL;
+ if (opt_clock_force_correlate) {
+ /*
+ * User requested to forcibly correlate the clock
+ * sources, even if we have no correlatation
+ * information.
+ */
+ if (!clock->absolute) {
+ fprintf(fd, "[warning] Forcibly correlating trace clock sources (--clock-force-correlate).\n");
+ }
+ clock->absolute = 1;
+ } else {
+ clock->absolute = 0; /* Not an absolute reference across traces */
+ }
+
+ trace->single_clock = clock;
+ g_hash_table_insert(trace->clocks, (gpointer) (unsigned long) clock->name, clock);
+}
+
+static
+void clock_free(gpointer data)
+{
+ struct ctf_clock *clock = data;
+
+ g_free(clock->description);
+ g_free(clock);
+}
+
+static
+int ctf_callsite_declaration_visit(FILE *fd, int depth, struct ctf_node *node,
+ struct ctf_callsite *callsite, 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_CALLSITE_FIELD_IS_SET(callsite, name)) {
+ fprintf(fd, "[error] %s: name already declared in callsite 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 callsite name\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ callsite->name = g_quark_from_string(right);
+ g_free(right);
+ CTF_CALLSITE_SET_FIELD(callsite, name);
+ } else if (!strcmp(left, "func")) {
+ char *right;
+
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, func)) {
+ fprintf(fd, "[error] %s: func already declared in callsite 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 callsite func\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ callsite->func = right;
+ CTF_CALLSITE_SET_FIELD(callsite, func);
+ } else if (!strcmp(left, "file")) {
+ char *right;
+
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, file)) {
+ fprintf(fd, "[error] %s: file already declared in callsite 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 callsite file\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ callsite->file = right;
+ CTF_CALLSITE_SET_FIELD(callsite, file);
+ } else if (!strcmp(left, "line")) {
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, line)) {
+ fprintf(fd, "[error] %s: line already declared in callsite declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &callsite->line);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for callsite line\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_CALLSITE_SET_FIELD(callsite, line);
+ } else if (!strcmp(left, "ip")) {
+ if (CTF_CALLSITE_FIELD_IS_SET(callsite, ip)) {
+ fprintf(fd, "[error] %s: ip already declared in callsite declaration\n", __func__);
+ ret = -EPERM;
+ goto error;
+ }
+ ret = get_unary_unsigned(&node->u.ctf_expression.right, &callsite->ip);
+ if (ret) {
+ fprintf(fd, "[error] %s: unexpected unary expression for callsite ip\n", __func__);
+ ret = -EINVAL;
+ goto error;
+ }
+ CTF_CALLSITE_SET_FIELD(callsite, ip);
+ } else {
+ fprintf(fd, "[warning] %s: attribute \"%s\" is unknown in callsite declaration.\n", __func__, left);
+ }
+
+error:
+ g_free(left);
+ break;
+ }
+ default:
+ return -EPERM;
+ /* TODO: declaration specifier should be added. */
+ }
+
+ return ret;
+}
+
+static
+int ctf_callsite_visit(FILE *fd, int depth, struct ctf_node *node, struct ctf_trace *trace)
+{
+ int ret = 0;
+ struct ctf_node *iter;
+ struct ctf_callsite *callsite;
+ struct ctf_callsite_dups *cs_dups;
+
+ callsite = g_new0(struct ctf_callsite, 1);
+ bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+ ret = ctf_callsite_declaration_visit(fd, depth + 1, iter, callsite, trace);
+ if (ret)
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, name)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing name field in callsite declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, func)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing func field in callsite declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, file)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing file field in callsite declaration\n", __func__);
+ goto error;
+ }
+ if (!CTF_CALLSITE_FIELD_IS_SET(callsite, line)) {
+ ret = -EPERM;
+ fprintf(fd, "[error] %s: missing line field in callsite declaration\n", __func__);
+ goto error;
+ }
+
+ cs_dups = g_hash_table_lookup(trace->callsites,
+ (gpointer) (unsigned long) callsite->name);
+ if (!cs_dups) {
+ cs_dups = g_new0(struct ctf_callsite_dups, 1);
+ BT_INIT_LIST_HEAD(&cs_dups->head);
+ g_hash_table_insert(trace->callsites,
+ (gpointer) (unsigned long) callsite->name, cs_dups);
+ }
+ bt_list_add_tail(&callsite->node, &cs_dups->head);
+ return 0;
+
+error:
+ g_free(callsite->func);
+ g_free(callsite->file);
+ g_free(callsite);
+ return ret;
+}
+
+static
+void callsite_free(gpointer data)
+{
+ struct ctf_callsite_dups *cs_dups = data;
+ struct ctf_callsite *callsite, *cs_n;
+
+ bt_list_for_each_entry_safe(callsite, cs_n, &cs_dups->head, node) {
+ g_free(callsite->func);
+ g_free(callsite->file);
+ g_free(callsite);
+ }
+ g_free(cs_dups);
+}
+
+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);