ir: Implement a field type visitor to resolve dynamic scopes
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 11 May 2015 21:35:28 +0000 (17:35 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 12 May 2015 18:05:20 +0000 (14:05 -0400)
Implement a visitor looking for sequences' length field and variants'
tag names and resolve them to their proper type field in the trace.

Validate that sequence lengths are unsigned integers and variant
tags are enumerations and that both respect CTF's lexical and dynamic
scoping rules.

Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
formats/ctf/ir/Makefile.am
formats/ctf/ir/visitor.c [new file with mode: 0644]
include/Makefile.am
include/babeltrace/ctf-ir/visitor-internal.h [new file with mode: 0644]

index 299c17ff6b9ca3b51d588330c37606f70e27e9ef..31a71ce423f4325a9aa0722b8dac430119b81b13 100644 (file)
@@ -11,7 +11,8 @@ libctf_ir_la_SOURCES = \
        stream.c \
        stream-class.c \
        trace.c \
-       utils.c
+       utils.c \
+       visitor.c
 
 libctf_ir_la_LIBADD = \
        $(top_builddir)/lib/libbabeltrace.la
diff --git a/formats/ctf/ir/visitor.c b/formats/ctf/ir/visitor.c
new file mode 100644 (file)
index 0000000..5838ddd
--- /dev/null
@@ -0,0 +1,885 @@
+/*
+ * visitor.c
+ *
+ * Babeltrace CTF IR - Trace Visitor
+ *
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/event.h>
+#include <babeltrace/ctf-ir/stream-class.h>
+#include <babeltrace/ctf-ir/visitor-internal.h>
+#include <babeltrace/ctf-ir/event-types-internal.h>
+#include <babeltrace/ctf-ir/event-internal.h>
+#include <babeltrace/babeltrace-internal.h>
+
+/* TSDL dynamic scope prefixes defined in CTF Section 7.3.2 */
+static const char * const absolute_path_prefixes[] = {
+       [CTF_NODE_ENV] = "env.",
+       [CTF_NODE_TRACE_PACKET_HEADER] = "trace.packet.header.",
+       [CTF_NODE_STREAM_PACKET_CONTEXT] = "stream.packet.context.",
+       [CTF_NODE_STREAM_EVENT_HEADER] = "stream.event.header.",
+       [CTF_NODE_STREAM_EVENT_CONTEXT] = "stream.event.context.",
+       [CTF_NODE_EVENT_CONTEXT] = "event.context.",
+       [CTF_NODE_EVENT_FIELDS] = "event.fields.",
+};
+
+const int absolute_path_prefix_token_counts[] = {
+       [CTF_NODE_ENV] = 1,
+       [CTF_NODE_TRACE_PACKET_HEADER] = 3,
+       [CTF_NODE_STREAM_PACKET_CONTEXT] = 3,
+       [CTF_NODE_STREAM_EVENT_HEADER] = 3,
+       [CTF_NODE_STREAM_EVENT_CONTEXT] = 3,
+       [CTF_NODE_EVENT_CONTEXT] = 2,
+       [CTF_NODE_EVENT_FIELDS] = 2,
+};
+
+static const char * const type_names[] = {
+       [CTF_TYPE_UNKNOWN] = "unknown",
+       [CTF_TYPE_INTEGER] = "integer",
+       [CTF_TYPE_FLOAT] = "float",
+       [CTF_TYPE_ENUM] = "enumeration",
+       [CTF_TYPE_STRING] = "string",
+       [CTF_TYPE_STRUCT] = "structure",
+       [CTF_TYPE_UNTAGGED_VARIANT] = "untagged variant",
+       [CTF_TYPE_VARIANT] = "variant",
+       [CTF_TYPE_ARRAY] = "array",
+       [CTF_TYPE_SEQUENCE] = "sequence",
+};
+
+static
+int field_type_visit(struct bt_ctf_field_type *type,
+               struct ctf_type_visitor_context *context,
+               ctf_type_visitor_func func);
+
+static
+int field_type_recursive_visit(struct bt_ctf_field_type *type,
+               struct ctf_type_visitor_context *context,
+               ctf_type_visitor_func func);
+
+static inline
+int get_type_field_count(struct bt_ctf_field_type *type)
+{
+       int field_count = -1;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
+
+       if (type_id == CTF_TYPE_STRUCT) {
+               field_count = bt_ctf_field_type_structure_get_field_count(type);
+       } else if (type_id == CTF_TYPE_VARIANT) {
+               field_count = bt_ctf_field_type_variant_get_field_count(type);
+       }
+       return field_count;
+}
+
+static inline
+struct bt_ctf_field_type *get_type_field(struct bt_ctf_field_type *type, int i)
+{
+       struct bt_ctf_field_type *field = NULL;
+       const char *unused_name;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
+
+       if (type_id == CTF_TYPE_STRUCT) {
+               bt_ctf_field_type_structure_get_field(type, &unused_name,
+                       &field, i);
+       } else if (type_id == CTF_TYPE_VARIANT) {
+               bt_ctf_field_type_variant_get_field(type,
+                       &unused_name, &field, i);
+       }
+
+       return field;
+}
+
+static inline
+int get_type_field_index(struct bt_ctf_field_type *type, const char *name)
+{
+       int field_index = -1;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
+
+       if (type_id == CTF_TYPE_STRUCT) {
+               field_index = bt_ctf_field_type_structure_get_field_name_index(
+                       type, name);
+       } else if (type_id == CTF_TYPE_VARIANT) {
+               field_index = bt_ctf_field_type_variant_get_field_name_index(
+                       type, name);
+       }
+
+       return field_index;
+}
+
+BT_HIDDEN
+ctf_type_stack *ctf_type_stack_create(void)
+{
+       return g_ptr_array_new();
+}
+
+BT_HIDDEN
+void ctf_type_stack_destroy(
+               ctf_type_stack *stack)
+{
+       g_ptr_array_free(stack, TRUE);
+}
+
+BT_HIDDEN
+int ctf_type_stack_push(ctf_type_stack *stack,
+               struct ctf_type_stack_frame *entry)
+{
+       int ret = 0;
+
+       if (!stack || !entry) {
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_add(stack, entry);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct ctf_type_stack_frame *ctf_type_stack_peek(ctf_type_stack *stack)
+{
+       struct ctf_type_stack_frame *entry = NULL;
+
+       if (!stack || stack->len == 0) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, stack->len - 1);
+end:
+       return entry;
+}
+
+BT_HIDDEN
+struct ctf_type_stack_frame *ctf_type_stack_pop(ctf_type_stack *stack)
+{
+       struct ctf_type_stack_frame *entry = NULL;
+
+       entry = ctf_type_stack_peek(stack);
+       if (entry) {
+               g_ptr_array_set_size(stack, stack->len - 1);
+       }
+       return entry;
+}
+
+static
+int field_type_visit(struct bt_ctf_field_type *type,
+               struct ctf_type_visitor_context *context,
+               ctf_type_visitor_func func)
+{
+       int ret;
+       enum ctf_type_id type_id;
+       struct ctf_type_stack_frame *frame = NULL;
+
+       ret = func(type, context);
+       if (ret) {
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_get_type_id(type);
+       if (type_id == CTF_TYPE_SEQUENCE || type_id == CTF_TYPE_ARRAY) {
+               struct bt_ctf_field_type *element =
+                       type_id == CTF_TYPE_SEQUENCE ?
+                       bt_ctf_field_type_sequence_get_element_type(type) :
+                       bt_ctf_field_type_array_get_element_type(type);
+
+               ret = field_type_recursive_visit(element, context, func);
+               bt_ctf_field_type_put(element);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       if (type_id != CTF_TYPE_STRUCT &&
+               type_id != CTF_TYPE_VARIANT) {
+               /* No need to create a new stack frame */
+               goto end;
+       }
+
+       frame = g_new0(struct ctf_type_stack_frame, 1);
+       if (!frame) {
+               ret = -1;
+               goto end;
+       }
+
+       frame->type = type;
+       ret = ctf_type_stack_push(context->stack, frame);
+       if (ret) {
+               g_free(frame);
+               goto end;
+       }
+end:
+       return ret;
+}
+
+static
+int field_type_recursive_visit(struct bt_ctf_field_type *type,
+               struct ctf_type_visitor_context *context,
+               ctf_type_visitor_func func)
+{
+       int ret = 0;
+       struct ctf_type_stack_frame *stack_marker = NULL;
+
+       ret = field_type_visit(type, context, func);
+       if (ret) {
+               goto end;
+       }
+
+       stack_marker = ctf_type_stack_peek(context->stack);
+       if (!stack_marker || stack_marker->type != type) {
+               /* No need for a recursive visit */
+               goto end;
+       }
+
+       while (true) {
+               struct bt_ctf_field_type *field;
+               struct ctf_type_stack_frame *entry =
+                       ctf_type_stack_peek(context->stack);
+               int field_count = get_type_field_count(entry->type);
+
+               if (field_count <= 0) {
+                       /*
+                        * Propagate error if one was given, else return
+                        * -1 since empty structures or variants are invalid
+                        * at this point.
+                        */
+                       ret = field_count < 0 ? field_count : -1;
+                       goto end;
+               }
+
+               if (entry->index == field_count) {
+                       /* This level has been completely visited */
+                       entry = ctf_type_stack_pop(context->stack);
+                       if (entry) {
+                               g_free(entry);
+                       }
+
+                       if (entry == stack_marker) {
+                               /* Completed visit */
+                               break;
+                       } else {
+                               continue;
+                       }
+               }
+
+               field = get_type_field(entry->type, entry->index);
+               /* Will push a new stack frame if field is struct or variant */
+               ret = field_type_visit(field, context, func);
+               bt_ctf_field_type_put(field);
+               if (ret) {
+                       goto end;
+               }
+
+               entry->index++;
+       }
+end:
+       return ret;
+}
+
+static
+int bt_ctf_event_class_visit(struct bt_ctf_event_class *event_class,
+               struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class,
+               ctf_type_visitor_func func)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *type;
+       struct ctf_type_visitor_context context = { 0 };
+
+       if (!event_class || !func) {
+               ret = -1;
+               goto end;
+       }
+
+       context.trace = trace;
+       context.stream_class = stream_class;
+       context.event_class = event_class;
+       context.stack = ctf_type_stack_create();
+       if (!context.stack) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Visit event context */
+       context.root_node = CTF_NODE_EVENT_CONTEXT;
+       type = bt_ctf_event_class_get_context_type(event_class);
+       if (type) {
+               ret = field_type_recursive_visit(type, &context, func);
+               bt_ctf_field_type_put(type);
+               type = NULL;
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Visit event payload */
+       context.root_node = CTF_NODE_EVENT_FIELDS;
+       type = bt_ctf_event_class_get_payload_type(event_class);
+       if (type) {
+               ret = field_type_recursive_visit(type, &context, func);
+               bt_ctf_field_type_put(type);
+               type = NULL;
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       if (context.stack) {
+               ctf_type_stack_destroy(context.stack);
+       }
+       return ret;
+}
+
+static
+int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_trace *trace,
+               ctf_type_visitor_func func)
+{
+       int i, ret = 0, event_count;
+       struct bt_ctf_field_type *type;
+       struct ctf_type_visitor_context context = { 0 };
+
+       if (!stream_class || !func) {
+               ret = -1;
+               goto end;
+       }
+
+       context.trace = trace;
+       context.stream_class = stream_class;
+       context.stack = ctf_type_stack_create();
+       if (!context.stack) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Visit stream packet context header */
+       context.root_node = CTF_NODE_STREAM_PACKET_CONTEXT;
+       type = bt_ctf_stream_class_get_packet_context_type(stream_class);
+       if (type) {
+               ret = field_type_recursive_visit(type, &context, func);
+               bt_ctf_field_type_put(type);
+               type = NULL;
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Visit stream event header */
+       context.root_node = CTF_NODE_STREAM_EVENT_HEADER;
+       type = bt_ctf_stream_class_get_event_header_type(stream_class);
+       if (type) {
+               ret = field_type_recursive_visit(type, &context, func);
+               bt_ctf_field_type_put(type);
+               type = NULL;
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Visit stream event context */
+       context.root_node = CTF_NODE_STREAM_EVENT_CONTEXT;
+       type = bt_ctf_stream_class_get_event_context_type(stream_class);
+       if (type) {
+               ret = field_type_recursive_visit(type, &context, func);
+               bt_ctf_field_type_put(type);
+               type = NULL;
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Visit event classes */
+       event_count = bt_ctf_stream_class_get_event_class_count(stream_class);
+       if (event_count < 0) {
+               ret = event_count;
+               goto end;
+       }
+       for (i = 0; i < event_count; i++) {
+               struct bt_ctf_event_class *event_class =
+                       bt_ctf_stream_class_get_event_class(stream_class, i);
+
+               ret = bt_ctf_event_class_visit(event_class, trace,
+                       stream_class, func);
+               bt_ctf_event_class_put(event_class);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       if (context.stack) {
+               ctf_type_stack_destroy(context.stack);
+       }
+       return ret;
+}
+
+static
+int set_field_path_relative(struct ctf_type_visitor_context *context,
+               struct bt_ctf_field_path *field_path,
+               GList **path_tokens, struct bt_ctf_field_type **resolved_field)
+{
+       int ret = 0;
+       GArray *root_path;
+       struct bt_ctf_field_type *field = NULL;
+       struct ctf_type_stack_frame *frame =
+               ctf_type_stack_peek(context->stack);
+       size_t token_count = g_list_length(*path_tokens), i;
+
+       if (!frame) {
+               ret = -1;
+               goto end;
+       }
+
+       field = frame->type;
+       bt_ctf_field_type_get(field);
+       for (i = 0; i < token_count; i++) {
+               struct bt_ctf_field_type *next_field = NULL;
+               int field_index = get_type_field_index(field,
+                       (*path_tokens)->data);
+
+               if (field_index < 0) {
+                       /* Field name not found, abort */
+                       printf_verbose("Could not resolve field \"%s\"\n",
+                               (char *) (*path_tokens)->data);
+                       ret = -1;
+                       goto end;
+               }
+
+               if (field_index >= frame->index) {
+                       printf_verbose("Invalid relative path refers to a member after the current one\n");
+                       ret = -1;
+                       goto end;
+               }
+
+               next_field = get_type_field(field, field_index);
+               if (!next_field) {
+                       ret = -1;
+                       goto end;
+               }
+
+               bt_ctf_field_type_put(field);
+               field = next_field;
+               g_array_append_val(field_path->path_indexes, field_index);
+
+               /*
+                * Free token and remove from list. This function does not
+                * assume the ownership of path_tokens; it is therefore _not_
+                * a leak to leave elements in this list. The caller should
+                * clean-up what is left (in case of error).
+                */
+               free((*path_tokens)->data);
+               *path_tokens = g_list_delete_link(*path_tokens, *path_tokens);
+       }
+
+       root_path = g_array_sized_new(FALSE, FALSE,
+               sizeof(int), context->stack->len - 1);
+       if (!root_path) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Set the current root node as the resolved type's root */
+       field_path->root = context->root_node;
+       /*
+        * Prepend the current fields' path to the relative path that
+        * was found by walking the stack.
+        */
+       for (i = 0; i < context->stack->len - 1; i++) {
+               int index;
+               struct ctf_type_stack_frame *frame =
+                       g_ptr_array_index(context->stack, i);
+
+               /* Decrement "index" since it points to the next field */
+               index = frame->index - 1;
+               g_array_append_val(root_path, index);
+       }
+       g_array_prepend_vals(field_path->path_indexes, root_path->data,
+               root_path->len);
+       g_array_free(root_path, TRUE);
+end:
+       if (field) {
+               bt_ctf_field_type_put(field);
+               *resolved_field = field;
+       }
+
+       return ret;
+}
+
+static
+int set_field_path_absolute(struct ctf_type_visitor_context *context,
+               struct bt_ctf_field_path *field_path,
+               GList **path_tokens, struct bt_ctf_field_type **resolved_field)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field = NULL;
+       size_t token_count = g_list_length(*path_tokens), i;
+
+       if (field_path->root > context->root_node) {
+               /*
+                * The target path's root is lower in the dynamic scope
+                * hierarchy than the current field being visited. This
+                * is invalid since it would not be possible to have read
+                * the target before the current field.
+                */
+               ret = -1;
+               printf_verbose("The target path's root is lower in the dynamic scope than the current field.\n");
+               goto end;
+       }
+
+       /* Set the appropriate root field */
+       switch (field_path->root) {
+       case CTF_NODE_TRACE_PACKET_HEADER:
+               field = bt_ctf_trace_get_packet_header_type(context->trace);
+               break;
+       case CTF_NODE_STREAM_PACKET_CONTEXT:
+               field = bt_ctf_stream_class_get_packet_context_type(
+                       context->stream_class);
+               break;
+       case CTF_NODE_STREAM_EVENT_HEADER:
+               field = bt_ctf_stream_class_get_event_header_type(
+                       context->stream_class);
+               break;
+       case CTF_NODE_STREAM_EVENT_CONTEXT:
+               field = bt_ctf_stream_class_get_event_context_type(
+                       context->stream_class);
+               break;
+       case CTF_NODE_EVENT_CONTEXT:
+               field = bt_ctf_event_class_get_context_type(
+                       context->event_class);
+               break;
+       case CTF_NODE_EVENT_FIELDS:
+               field = bt_ctf_event_class_get_payload_type(
+                       context->event_class);
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+
+       if (!field) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < token_count; i++) {
+               int field_index = get_type_field_index(field,
+                       (*path_tokens)->data);
+               struct bt_ctf_field_type *next_field = NULL;
+
+               if (field_index < 0) {
+                       /* Field name not found, abort */
+                       printf_verbose("Could not resolve field \"%s\"\n",
+                               (char *) (*path_tokens)->data);
+                       ret = -1;
+                       goto end;
+               }
+
+               next_field = get_type_field(field, field_index);
+               if (!next_field) {
+                       ret = -1;
+                       goto end;
+               }
+
+               bt_ctf_field_type_put(field);
+               field = next_field;
+               g_array_append_val(field_path->path_indexes, field_index);
+
+               /*
+                * Free token and remove from list. This function does not
+                * assume the ownership of path_tokens; it is therefore _not_
+                * a leak to leave elements in this list. The caller should
+                * clean-up what is left (in case of error).
+                */
+               free((*path_tokens)->data);
+               *path_tokens = g_list_delete_link(*path_tokens, *path_tokens);
+       }
+end:
+       if (field) {
+               bt_ctf_field_type_put(field);
+               *resolved_field = field;
+       }
+       return ret;
+}
+
+static
+int get_field_path(struct ctf_type_visitor_context *context,
+               const char *path, struct bt_ctf_field_path **field_path,
+               struct bt_ctf_field_type **resolved_field)
+{
+       int i, ret = 0;
+       GList *path_tokens = NULL;
+       char *name_copy, *save_ptr, *token;
+
+       /* Tokenize path to a list of strings */
+       name_copy = strdup(path);
+       if (!name_copy) {
+               goto error;
+       }
+
+       token = strtok_r(name_copy, ".", &save_ptr);
+       while (token) {
+               char *token_string = strdup(token);
+
+               if (!token_string) {
+                       ret = -1;
+                       goto error;
+               }
+               path_tokens = g_list_append(path_tokens, token_string);
+               token = strtok_r(NULL, ".", &save_ptr);
+       }
+
+       *field_path = bt_ctf_field_path_create();
+       if (!*field_path) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Check if the path is absolute */
+       for (i = 0; i < sizeof(absolute_path_prefixes) / sizeof(char *); i++) {
+               int j;
+
+               /*
+                * Chech if "path" starts with a known absolute path prefix.
+                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
+                */
+               if (strncmp(path, absolute_path_prefixes[i],
+                       strlen(absolute_path_prefixes[i]))) {
+                       /* Wrong prefix, try the next one */
+                       continue;
+               }
+
+               /*
+                * Remove the first n tokens of this prefix.
+                * e.g. trace.packet.header: remove the first 3 tokens.
+                */
+               for (j = 0; j < absolute_path_prefix_token_counts[i]; j++) {
+                       free(path_tokens->data);
+                       path_tokens = g_list_delete_link(
+                               path_tokens, path_tokens);
+               }
+
+               /* i maps to enum bt_ctf_node constants */
+               (*field_path)->root = (enum bt_ctf_node) i;
+               break;
+       }
+
+       if ((*field_path)->root == CTF_NODE_UNKNOWN) {
+               /* Relative path */
+               ret = set_field_path_relative(context,
+                       *field_path, &path_tokens, resolved_field);
+               if (ret) {
+                       goto error;
+               }
+       } else {
+               /* Absolute path */
+               ret = set_field_path_absolute(context,
+                       *field_path, &path_tokens, resolved_field);
+               if (ret) {
+                       goto error;
+               }
+       }
+end:
+       if (name_copy) {
+               g_free(name_copy);
+       }
+       if (path_tokens) {
+               g_list_free_full(path_tokens, free);
+       }
+       return ret;
+error:
+       if (*field_path) {
+               bt_ctf_field_path_destroy(*field_path);
+               *field_path = NULL;
+       }
+       goto end;
+}
+
+void print_path(const char *field_name,
+               struct bt_ctf_field_type *resolved_type,
+               struct bt_ctf_field_path *field_path)
+{
+       int i;
+
+       printf_verbose("Resolved field \"%s\" as type \"%s\", ",
+               field_name,
+               type_names[bt_ctf_field_type_get_type_id(resolved_type)]);
+       printf_verbose("path: %s",
+               absolute_path_prefixes[field_path->root]);
+
+       for (i = 0; i < field_path->path_indexes->len; i++) {
+               printf_verbose(" %d",
+                       g_array_index(field_path->path_indexes, int, i));
+       }
+       printf_verbose("\n");
+}
+
+static
+int type_resolve_func(struct bt_ctf_field_type *type,
+               struct ctf_type_visitor_context *context)
+{
+       int ret = 0;
+       enum ctf_type_id type_id = bt_ctf_field_type_get_type_id(type);
+       const char *field_name = NULL;
+       struct bt_ctf_field_path *field_path = NULL;
+       struct bt_ctf_field_type *resolved_type = NULL;
+
+       if (type_id != CTF_TYPE_SEQUENCE &&
+               type_id != CTF_TYPE_VARIANT) {
+               goto end;
+       }
+
+       field_name = type_id == CTF_TYPE_SEQUENCE ?
+               bt_ctf_field_type_sequence_get_length_field_name(type) :
+               bt_ctf_field_type_variant_get_tag_name(type);
+       if (!field_name) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = get_field_path(context, field_name,
+               &field_path, &resolved_type);
+       if (ret) {
+               goto end;
+       }
+
+       assert(field_path && resolved_type);
+
+       /* Print path if in verbose mode */
+       print_path(field_name, resolved_type, field_path);
+
+       /* Set type's path */
+       if (type_id == CTF_TYPE_VARIANT) {
+               if (bt_ctf_field_type_get_type_id(resolved_type) !=
+                       CTF_TYPE_ENUM) {
+                       printf_verbose("Invalid variant tag \"%s\"; expected enum\n", field_name);
+                       ret = -1;
+                       goto end;
+               }
+               ret = bt_ctf_field_type_variant_set_tag(type, resolved_type);
+               if (ret) {
+                       goto end;
+               }
+
+               ret = bt_ctf_field_type_variant_set_tag_field_path(type,
+                       field_path);
+               if (ret) {
+                       goto end;
+               }
+       } else {
+               /* Sequence */
+               if (bt_ctf_field_type_get_type_id(resolved_type) !=
+                       CTF_TYPE_INTEGER) {
+                       printf_verbose("Invalid sequence length field \"%s\"; expected integer\n", field_name);
+                       ret = -1;
+                       goto end;
+               }
+
+               if (bt_ctf_field_type_integer_get_signed(resolved_type) != 0) {
+                       printf_verbose("Invalid sequence length field \"%s\"; integer should be unsigned\n", field_name);
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = bt_ctf_field_type_sequence_set_length_field_path(type,
+                       field_path);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
+               ctf_type_visitor_func func)
+{
+       int i, stream_count, ret = 0;
+       struct bt_ctf_field_type *type = NULL;
+       struct ctf_type_visitor_context visitor_ctx = { 0 };
+
+       if (!trace || !func) {
+               ret = -1;
+               goto end;
+       }
+
+       visitor_ctx.trace = trace;
+       visitor_ctx.stack = ctf_type_stack_create();
+       if (!visitor_ctx.stack) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Visit trace packet header */
+       type = bt_ctf_trace_get_packet_header_type(trace);
+       if (type) {
+               visitor_ctx.root_node = CTF_NODE_TRACE_PACKET_HEADER;
+               ret = field_type_recursive_visit(type, &visitor_ctx, func);
+               visitor_ctx.root_node = CTF_NODE_UNKNOWN;
+               bt_ctf_field_type_put(type);
+               type = NULL;
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       stream_count = bt_ctf_trace_get_stream_class_count(trace);
+       for (i = 0; i < stream_count; i++) {
+               struct bt_ctf_stream_class *stream_class =
+                       bt_ctf_trace_get_stream_class(trace, i);
+
+               /* Visit streams */
+               ret = bt_ctf_stream_class_visit(stream_class, trace,
+                       func);
+               bt_ctf_stream_class_put(stream_class);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       if (visitor_ctx.stack) {
+               ctf_type_stack_destroy(visitor_ctx.stack);
+       }
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_resolve_types(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_visit(trace, type_resolve_func);
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_resolve_types(struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_trace *trace)
+{
+       return bt_ctf_stream_class_visit(stream_class, trace,
+               type_resolve_func);
+}
+
+BT_HIDDEN
+int bt_ctf_event_class_resolve_types(struct bt_ctf_event_class *event_class,
+               struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_event_class_visit(event_class, trace, stream_class,
+               type_resolve_func);
+}
index 17d4faae664b9a6c3f17000570b564df4b12a2d3..35a52f96ce68fcaacb80c593e5c7dcb4730e58c8 100644 (file)
@@ -61,6 +61,7 @@ noinst_HEADERS = \
        babeltrace/ctf-ir/stream-class-internal.h \
        babeltrace/ctf-ir/stream-internal.h \
        babeltrace/ctf-ir/trace-internal.h \
+       babeltrace/ctf-ir/visitor-internal.h \
        babeltrace/ctf-writer/functor-internal.h \
        babeltrace/trace-handle-internal.h \
        babeltrace/compat/uuid.h \
diff --git a/include/babeltrace/ctf-ir/visitor-internal.h b/include/babeltrace/ctf-ir/visitor-internal.h
new file mode 100644 (file)
index 0000000..8243dfe
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef BABELTRACE_CTF_IR_VISITOR_INTERNAL_H
+#define BABELTRACE_CTF_IR_VISITOR_INTERNAL_H
+
+/*
+ * BabelTrace - CTF IR: Visitor internal
+ *
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-ir/event-types.h>
+#include <babeltrace/ctf-ir/event-types-internal.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <glib.h>
+
+struct ctf_type_stack_frame {
+       struct bt_ctf_field_type *type;
+       int index;
+};
+
+typedef GPtrArray ctf_type_stack;
+
+struct ctf_type_visitor_context {
+       struct bt_ctf_trace *trace;
+       struct bt_ctf_stream_class *stream_class;
+       struct bt_ctf_event_class *event_class;
+       /* Root node being visited */
+       enum bt_ctf_node root_node;
+       ctf_type_stack *stack;
+};
+
+typedef int (*ctf_type_visitor_func)(struct bt_ctf_field_type *,
+       struct ctf_type_visitor_context *);
+
+BT_HIDDEN
+ctf_type_stack *ctf_type_stack_create(void);
+
+BT_HIDDEN
+void ctf_type_stack_destroy(ctf_type_stack *stack);
+
+BT_HIDDEN
+int ctf_type_stack_push(ctf_type_stack *stack,
+               struct ctf_type_stack_frame *entry);
+
+BT_HIDDEN
+struct ctf_type_stack_frame *ctf_type_stack_peek(
+               ctf_type_stack *stack);
+
+BT_HIDDEN
+struct ctf_type_stack_frame *ctf_type_stack_pop(ctf_type_stack *stack);
+
+BT_HIDDEN
+int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
+               ctf_type_visitor_func func);
+
+BT_HIDDEN
+int bt_ctf_trace_resolve_types(struct bt_ctf_trace *trace);
+
+BT_HIDDEN
+int bt_ctf_stream_class_resolve_types(struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_trace *trace);
+
+BT_HIDDEN
+int bt_ctf_event_class_resolve_types(struct bt_ctf_event_class *event_class,
+               struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class);
+
+#endif /* BABELTRACE_CTF_IR_VISITOR_INTERNAL_H */
This page took 0.034312 seconds and 4 git commands to generate.