--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * src/field-path-resolving.c
+ *
+ * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <lttng/events.h>
+#include <lttng/events-internal.h>
+
+#include "field-path-resolving.h"
+
+static int append_path_element(struct field_path *field_path, const char *name,
+ const struct lttng_kernel_event_field *field)
+{
+ struct field_path_node *field_path_node;
+
+ field_path_node = kzalloc(sizeof(*field_path_node), GFP_KERNEL);
+ if (!field_path_node)
+ return -ENOMEM;
+
+ field_path_node->field = field;
+ field_path_node->name = name;
+
+ list_add(&field_path_node->node, &field_path->path);
+ field_path->path_entry_count++;
+
+ return 0;
+}
+
+struct field_path *field_path_resolve(struct field_location_ctx *ctx,
+ const char *target_field_name)
+{
+ struct field_path *field_path = NULL;
+ struct field_location_stack_node *node;
+ bool field_found = false;
+ int ret;
+
+ field_path = kzalloc(sizeof(*field_path), GFP_KERNEL);
+ if (!field_path)
+ return NULL;
+
+ INIT_LIST_HEAD(&field_path->path);
+
+ /*
+ * The scope stack contains all the fields processed up until this
+ * point in the current scope and outter scopes.
+ *
+ * Iterate on the stack from the top until we find a integer field
+ * matching the target field name.
+ *
+ * Once found, continue the iteration but only record struct fields.
+ */
+
+ list_for_each_entry (node, &ctx->field_location_stack, node) {
+ if (!field_found) {
+ /* The location can't be a scope. */
+ if (node->type == SCOPE_STACK_NODE_TYPE_SCOPE) {
+ continue;
+ }
+
+ /* The location field must be a integer or an enum. */
+ if (node->field->type->type !=
+ lttng_kernel_type_integer &&
+ node->field->type->type != lttng_kernel_type_enum) {
+ continue;
+ }
+
+ /*
+ * If the target field name is NULL, use the first
+ * element encountered, else compare the field names.
+ */
+ if (target_field_name == NULL ||
+ strcmp(node->field_name, target_field_name) == 0) {
+ field_found = true;
+ ret = append_path_element(field_path,
+ node->field_name,
+ node->field);
+ if (ret)
+ goto err;
+ }
+ } else {
+ /*
+ * The actual location field was found, from this point
+ * on we record all surrounding scopes to create the
+ * full path.
+ */
+ if (node->type == SCOPE_STACK_NODE_TYPE_SCOPE) {
+ ret = append_path_element(
+ field_path, node->field_name, NULL);
+ if (ret)
+ goto err;
+ }
+ }
+ }
+
+ return field_path;
+
+err:
+ field_path_destroy(field_path);
+ return NULL;
+}
+
+void field_path_destroy(struct field_path *fp)
+{
+ struct field_path_node *node, *tmp;
+
+ if (!fp) {
+ return;
+ }
+
+ list_for_each_entry_safe (node, tmp, &fp->path, node) {
+ kfree(node);
+ }
+
+ kfree(fp);
+}
+
+int field_location_stack_push(struct field_location_ctx *ctx,
+ enum field_location_stack_node_type type,
+ const char *field_name,
+ const struct lttng_kernel_event_field *field)
+{
+ struct field_location_stack_node *field_location_stack_node;
+
+ field_location_stack_node =
+ kzalloc(sizeof(*field_location_stack_node), GFP_KERNEL);
+ if (!field_location_stack_node)
+ return -ENOMEM;
+
+ field_location_stack_node->type = type;
+ field_location_stack_node->field = field;
+ field_location_stack_node->field_name = field_name;
+
+ list_add(&field_location_stack_node->node, &ctx->field_location_stack);
+ ctx->field_location_stack_len++;
+
+ return 0;
+}
+
+static void field_location_stack_pop(struct field_location_ctx *ctx)
+{
+ struct field_location_stack_node *node;
+
+ node = list_first_entry(&ctx->field_location_stack,
+ struct field_location_stack_node, node);
+
+ list_del(&node->node);
+ kfree(node);
+ ctx->field_location_stack_len--;
+}
+
+void field_location_stack_pop_n_elem(struct field_location_ctx *ctx,
+ unsigned int number_to_pop)
+{
+ unsigned int i;
+
+ for (i = 0; i < number_to_pop; i++) {
+ field_location_stack_pop(ctx);
+ }
+}
+
+struct field_location_ctx *field_location_ctx_create(void)
+{
+ struct field_location_ctx *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ INIT_LIST_HEAD(&ctx->field_location_stack);
+
+ return ctx;
+}
+
+void field_location_ctx_destroy(struct field_location_ctx *ctx)
+{
+ struct field_location_stack_node *node, *tmp;
+
+ if (!ctx) {
+ return;
+ }
+
+ list_for_each_entry_safe (node, tmp, &ctx->field_location_stack, node) {
+ kfree(node);
+ }
+
+ kfree(ctx);
+}
--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
+ *
+ * src/field-path-resolving.h
+ *
+ * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ */
+
+#ifndef LTTNG_FIELD_PATH_RESOLVING_H
+#define LTTNG_FIELD_PATH_RESOLVING_H
+
+#include <wrapper/list.h>
+
+enum field_location_stack_node_type {
+ SCOPE_STACK_NODE_TYPE_FIELD,
+ SCOPE_STACK_NODE_TYPE_SCOPE,
+};
+
+struct field_location_stack_node {
+ struct list_head node;
+ enum field_location_stack_node_type type;
+ const char *field_name;
+ const struct lttng_kernel_event_field *field;
+};
+
+struct field_location_ctx {
+ struct list_head field_location_stack;
+ unsigned int field_location_stack_len;
+};
+
+struct field_path_node {
+ struct list_head node;
+ const char *name;
+ const struct lttng_kernel_event_field *field;
+};
+
+struct field_path {
+ unsigned int path_entry_count;
+ struct list_head path;
+};
+
+struct field_path *field_path_resolve(struct field_location_ctx *ctx,
+ const char *target_field_name);
+
+void field_path_destroy(struct field_path *fp);
+
+struct field_location_ctx *field_location_ctx_create(void);
+
+void field_location_ctx_destroy(struct field_location_ctx *ctx);
+
+int field_location_stack_push(struct field_location_ctx *ctx,
+ enum field_location_stack_node_type type,
+ const char *field_name,
+ const struct lttng_kernel_event_field *field);
+
+void field_location_stack_pop_n_elem(struct field_location_ctx *ctx,
+ unsigned int number);
+
+#endif /* LTTNG_FIELD_PATH_RESOLVING_H */