common: introduce lttng_event_expr_to_bytecode
authorSimon Marchi <simon.marchi@efficios.com>
Mon, 6 Apr 2020 20:47:08 +0000 (16:47 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 9 Mar 2021 04:51:11 +0000 (23:51 -0500)
This function converts an event expression object in the appropriate
bytecode to capture the value described by that event expression.

Change-Id: I81c8f4ad40312e0d9f1a805a7e965a9d513cdde8
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479

src/common/Makefile.am
src/common/event-expr-to-bytecode.c [new file with mode: 0644]
src/common/event-expr-to-bytecode.h [new file with mode: 0644]
tests/unit/Makefile.am
tests/unit/test_event_expr_to_bytecode.c [new file with mode: 0644]

index cfb935c5ad2b2dc6d43c088478f95fdbc8002f43..c8707f48e814d3dd729fd74dd4dd5c5490b02257 100644 (file)
@@ -59,6 +59,7 @@ libcommon_la_SOURCES = \
        error.c error.h \
        evaluation.c \
        event.c \
+       event-expr-to-bytecode.c event-expr-to-bytecode.h \
        event-rule/event-rule.c \
        event-rule/kprobe.c \
        event-rule/syscall.c \
diff --git a/src/common/event-expr-to-bytecode.c b/src/common/event-expr-to-bytecode.c
new file mode 100644 (file)
index 0000000..abc713f
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2020 EfficiOS, Inc.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include "event-expr-to-bytecode.h"
+
+#include <stdio.h>
+#include <lttng/event-expr.h>
+#include <common/bytecode/bytecode.h>
+#include <common/error.h>
+
+static
+int event_expr_to_bytecode_recursive(const struct lttng_event_expr *expr,
+               struct lttng_bytecode_alloc **bytecode,
+               struct lttng_bytecode_alloc **bytecode_reloc)
+{
+       int status;
+       enum lttng_event_expr_status event_expr_status;
+
+       switch (lttng_event_expr_get_type(expr)) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+       {
+               const char *name;
+
+               status = bytecode_push_get_payload_root(bytecode);
+               if (status) {
+                       ERR("Failed to get payload root from bytecode");
+                       goto end;
+               }
+
+               name = lttng_event_expr_event_payload_field_get_name(expr);
+               if (!name) {
+                       ERR("Failed to get payload field name from event expression");
+                       status = -1;
+                       goto end;
+               }
+
+               status = bytecode_push_get_symbol(bytecode, bytecode_reloc, name);
+               if (status) {
+                       ERR("Failed to push 'get symbol %s' in bytecode", name);
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+       {
+               const char *name;
+
+               status = bytecode_push_get_context_root(bytecode);
+               if (status) {
+                       ERR("Failed to get context root from bytecode");
+                       goto end;
+               }
+
+               name = lttng_event_expr_channel_context_field_get_name(expr);
+               if (!name) {
+                       ERR("Failed to get channel context field name from event expression");
+                       status = -1;
+                       goto end;
+               }
+
+               status = bytecode_push_get_symbol(bytecode, bytecode_reloc, name);
+               if (status) {
+                       ERR("Failed to push 'get symbol %s' in bytecode", name);
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               int ret;
+               char *name = NULL;
+               const char *provider_name, *type_name;
+
+               status = bytecode_push_get_app_context_root(bytecode);
+               if (status) {
+                       ERR("Failed to get application context root from bytecode");
+                       goto end;
+               }
+
+               provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
+                               expr);
+               if (!provider_name) {
+                       ERR("Failed to get application context provider name from event expression");
+                       status = -1;
+                       goto end;
+               }
+
+               type_name = lttng_event_expr_app_specific_context_field_get_type_name(
+                               expr);
+               if (!type_name) {
+                       ERR("Failed to get application context type name from event expression");
+                       status = -1;
+                       goto end;
+               }
+
+               /*
+                * Reconstitute the app context field name from its two parts.
+                */
+               ret = asprintf(&name, "%s:%s", provider_name, type_name);
+               if (ret < 0) {
+                       PERROR("Failed to format application specific context: provider_name = '%s', type_name = '%s'",
+                                       provider_name, type_name);
+                       status = -1;
+                       goto end;
+               }
+
+               status = bytecode_push_get_symbol(
+                               bytecode, bytecode_reloc, name);
+               free(name);
+               if (status) {
+                       ERR("Failed to push 'get symbol %s' in bytecode", name);
+                       goto end;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               unsigned int index;
+               const struct lttng_event_expr *parent;
+
+               parent = lttng_event_expr_array_field_element_get_parent_expr(
+                               expr);
+               if (!parent) {
+                       ERR("Failed to get parent expression from array event expression");
+                       status = -1;
+                       goto end;
+               }
+
+               status = event_expr_to_bytecode_recursive(
+                               parent, bytecode, bytecode_reloc);
+               if (status) {
+                       goto end;
+               }
+
+               event_expr_status = lttng_event_expr_array_field_element_get_index(
+                               expr, &index);
+               if (event_expr_status != LTTNG_EVENT_EXPR_STATUS_OK) {
+                       ERR("Failed to get array field element index from event expression");
+                       status = -1;
+                       goto end;
+               }
+
+               status = bytecode_push_get_index_u64(bytecode, index);
+               if (status) {
+                       ERR("Failed to push 'get index %u' in bytecode", index);
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       status = 0;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+int lttng_event_expr_to_bytecode(const struct lttng_event_expr *expr,
+               struct lttng_bytecode **bytecode_out)
+{
+       int status;
+       struct return_op ret_insn;
+       struct lttng_bytecode_alloc *bytecode = NULL;
+       struct lttng_bytecode_alloc *bytecode_reloc = NULL;
+
+       status = bytecode_init(&bytecode);
+       if (status) {
+               ERR("Failed to initialize bytecode");
+               goto end;
+       }
+
+       status = bytecode_init(&bytecode_reloc);
+       if (status) {
+               ERR("Failed to initialize relocation bytecode");
+               goto end;
+       }
+
+       status = event_expr_to_bytecode_recursive(
+                       expr, &bytecode, &bytecode_reloc);
+       if (status) {
+               /* Errors already logged. */
+               goto end;
+       }
+
+       ret_insn.op = BYTECODE_OP_RETURN;
+       bytecode_push(&bytecode, &ret_insn, 1, sizeof(ret_insn));
+
+       /* Append symbol table to bytecode. */
+       bytecode->b.reloc_table_offset = bytecode_get_len(&bytecode->b);
+       status = bytecode_push(&bytecode, bytecode_reloc->b.data, 1,
+                       bytecode_get_len(&bytecode_reloc->b));
+       if (status) {
+               ERR("Failed to push symbol table to bytecode");
+               goto end;
+       }
+
+       /* Copy the `lttng_bytecode` out of the `lttng_bytecode_alloc`.  */
+       *bytecode_out = lttng_bytecode_copy(&bytecode->b);
+       if (!*bytecode_out) {
+               status = -1;
+               goto end;
+       }
+
+end:
+       if (bytecode) {
+               free(bytecode);
+       }
+
+       if (bytecode_reloc) {
+               free(bytecode_reloc);
+       }
+
+       return status;
+}
diff --git a/src/common/event-expr-to-bytecode.h b/src/common/event-expr-to-bytecode.h
new file mode 100644 (file)
index 0000000..9d7d57a
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SRC_COMMON_EVENT_EXPR_TO_BYTECODE_H
+#define SRC_COMMON_EVENT_EXPR_TO_BYTECODE_H
+
+/*
+ * Copyright 2020 EfficiOS, Inc.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <common/macros.h>
+
+struct lttng_bytecode;
+struct lttng_event_expr;
+
+LTTNG_HIDDEN
+int lttng_event_expr_to_bytecode (const struct lttng_event_expr *expr,
+               struct lttng_bytecode **bytecode_out);
+
+#endif /* SRC_COMMON_EVENT_EXPR_TO_BYTECODE_H */
index 5963292bc3d996002d462bb44289f05971443169..01b2981524bdebb271c9a867d03946c087e85b06 100644 (file)
@@ -25,6 +25,7 @@ TESTS = test_kernel_data \
        test_fd_tracker \
        test_uuid \
        test_buffer_view \
+       test_event_expr_to_bytecode \
        test_payload \
        test_unix_socket \
        test_kernel_probe
@@ -51,6 +52,7 @@ noinst_PROGRAMS = test_uri test_session test_kernel_data \
                   test_unix_socket \
                   test_kernel_probe \
                   test_condition \
+                 test_event_expr_to_bytecode \
                   test_event_rule 
 
 if HAVE_LIBLTTNG_UST_CTL
@@ -238,3 +240,7 @@ test_unix_socket_LDADD = $(LIBTAP) $(LIBSESSIOND_COMM) $(LIBCOMMON)
 # Kernel probe location api test
 test_kernel_probe_SOURCES = test_kernel_probe.c
 test_kernel_probe_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBLTTNG_CTL) $(DL_LIBS)
+#
+# Event expression to bytecode test
+test_event_expr_to_bytecode_SOURCES = test_event_expr_to_bytecode.c
+test_event_expr_to_bytecode_LDADD = $(LIBTAP) $(LIBLTTNG_CTL) $(LIBCOMMON)
diff --git a/tests/unit/test_event_expr_to_bytecode.c b/tests/unit/test_event_expr_to_bytecode.c
new file mode 100644 (file)
index 0000000..dd26e66
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2020 EfficiOS, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <lttng/event-expr.h>
+#include <common/event-expr-to-bytecode.h>
+#include <common/bytecode/bytecode.h>
+#include <tap/tap.h>
+
+#define NR_TESTS 4
+
+static
+void test_event_payload_field(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_event_payload_field_create("tourlou");
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "event payload field");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+static
+void test_channel_context_field(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_channel_context_field_create("tourlou");
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "channel context field");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+static
+void test_app_specific_context_field(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_app_specific_context_field_create("Bob", "Leponge");
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "app-specific context field");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+static
+void test_array_field_element(void)
+{
+       struct lttng_event_expr *event_expr;
+       struct lttng_bytecode *bytecode = NULL;
+       int ret;
+
+       event_expr = lttng_event_expr_event_payload_field_create("allo");
+       event_expr = lttng_event_expr_array_field_element_create(event_expr, 168);
+       ret = lttng_event_expr_to_bytecode(event_expr, &bytecode);
+
+       ok(ret == 0, "array field element");
+
+       lttng_event_expr_destroy(event_expr);
+       free(bytecode);
+}
+
+int main(void)
+{
+       plan_tests(NR_TESTS);
+
+       test_event_payload_field();
+       test_channel_context_field();
+       test_app_specific_context_field();
+       test_array_field_element();
+
+       return exit_status();
+}
This page took 0.042647 seconds and 4 git commands to generate.