From 748b5f7b257748a094096ef2beeb2eb941324978 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 6 Apr 2020 16:47:08 -0400 Subject: [PATCH] common: introduce lttng_event_expr_to_bytecode MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Jérémie Galarneau Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479 --- src/common/Makefile.am | 1 + src/common/event-expr-to-bytecode.c | 224 +++++++++++++++++++++++ src/common/event-expr-to-bytecode.h | 20 ++ tests/unit/Makefile.am | 6 + tests/unit/test_event_expr_to_bytecode.c | 90 +++++++++ 5 files changed, 341 insertions(+) create mode 100644 src/common/event-expr-to-bytecode.c create mode 100644 src/common/event-expr-to-bytecode.h create mode 100644 tests/unit/test_event_expr_to_bytecode.c diff --git a/src/common/Makefile.am b/src/common/Makefile.am index cfb935c5a..c8707f48e 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -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 index 000000000..abc713fb3 --- /dev/null +++ b/src/common/event-expr-to-bytecode.c @@ -0,0 +1,224 @@ +/* + * Copyright 2020 EfficiOS, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include "event-expr-to-bytecode.h" + +#include +#include +#include +#include + +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 index 000000000..9d7d57aea --- /dev/null +++ b/src/common/event-expr-to-bytecode.h @@ -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 + +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 */ diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 5963292bc..01b298152 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -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 index 000000000..dd26e66e6 --- /dev/null +++ b/tests/unit/test_event_expr_to_bytecode.c @@ -0,0 +1,90 @@ +/* + * Copyright 2020 EfficiOS, Inc. + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#include +#include +#include +#include + +#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(); +} -- 2.34.1