From 808cb744a46310d2e5fbbe9ab025cd427bcfc0a8 Mon Sep 17 00:00:00 2001 From: Jonathan Rajotte Date: Mon, 24 Aug 2020 15:50:49 -0400 Subject: [PATCH] Introduce kernel-probe locations MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Kernel probe can be configured by two type of location. The first one is via address: lttng_kernel_probe_location_address_create. The second one is using a symbol name combined with an offset. Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: Icd280e7a8403c761987472f0a416ef5188a2068d --- .gitignore | 1 + include/Makefile.am | 4 +- include/lttng/kernel-probe-internal.h | 94 +++++ include/lttng/kernel-probe.h | 87 ++++ src/common/Makefile.am | 1 + src/common/kernel-probe.c | 564 ++++++++++++++++++++++++++ tests/unit/Makefile.am | 10 +- tests/unit/test_kernel_probe.c | 169 ++++++++ 8 files changed, 927 insertions(+), 3 deletions(-) create mode 100644 include/lttng/kernel-probe-internal.h create mode 100644 include/lttng/kernel-probe.h create mode 100644 src/common/kernel-probe.c create mode 100644 tests/unit/test_kernel_probe.c diff --git a/.gitignore b/.gitignore index 49aa0d1c1..f23a72b9c 100644 --- a/.gitignore +++ b/.gitignore @@ -142,6 +142,7 @@ health_check /tests/perf/test_perf_raw /tests/unit/test_string_utils /tests/unit/test_buffer_view +/tests/unit/test_kernel_probe /tests/utils/testapp/gen-ust-nevents-str/gen-ust-nevents-str /tests/utils/testapp/userspace-probe-elf-binary/userspace-probe-elf-binary /tests/utils/testapp/userspace-probe-elf-cxx-binary/userspace-probe-elf-cxx-binary diff --git a/include/Makefile.am b/include/Makefile.am index baad620dd..cd2877193 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -117,7 +117,8 @@ lttnginclude_HEADERS = \ lttng/destruction-handle.h \ lttng/clear.h \ lttng/clear-handle.h \ - lttng/tracker.h + lttng/tracker.h \ + lttng/kernel-probe.h lttngactioninclude_HEADERS= \ lttng/action/action.h \ @@ -171,5 +172,6 @@ noinst_HEADERS = \ lttng/userspace-probe-internal.h \ lttng/session-internal.h \ lttng/session-descriptor-internal.h \ + lttng/kernel-probe-internal.h \ version.h \ version.i diff --git a/include/lttng/kernel-probe-internal.h b/include/lttng/kernel-probe-internal.h new file mode 100644 index 000000000..680f3afab --- /dev/null +++ b/include/lttng/kernel-probe-internal.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_KERNEL_PROBE_INTERNAL_H +#define LTTNG_KERNEL_PROBE_INTERNAL_H + +#include +#include +#include +#include +#include +#include + +struct lttng_payload; +struct lttng_payload_view; +struct lttng_dynamic_buffer; + +typedef bool (*kernel_probe_location_equal_cb)( + const struct lttng_kernel_probe_location *a, + const struct lttng_kernel_probe_location *b); +typedef int (*kernel_probe_location_serialize_cb)( + const struct lttng_kernel_probe_location *kernel_probe_location, + struct lttng_payload *payload); +typedef bool (*kernel_probe_location_equal_cb)( + const struct lttng_kernel_probe_location *a, + const struct lttng_kernel_probe_location *b); +typedef ssize_t (*kernel_probe_location_create_from_payload_cb)( + struct lttng_payload_view *view, + struct lttng_kernel_probe_location **kernel_probe_location); + +struct lttng_kernel_probe_location_comm { + /* enum lttng_kernel_probe_location_type */ + int8_t type; + /* + * Payload is composed of, in that order, + * - type-specific payload + */ + char payload[]; +} LTTNG_PACKED; + +struct lttng_kernel_probe_location_symbol_comm { + /* Includes the trailing \0. */ + uint32_t symbol_len; + /* The offset from the symbol. */ + uint64_t offset; + /* + * Payload is composed of, in that order, + * - symbol name (with trailing \0). + */ + char payload[]; +} LTTNG_PACKED; + +struct lttng_kernel_probe_location_address_comm { + uint64_t address; +} LTTNG_PACKED; + +/* Common ancestor of all kernel probe locations. */ +struct lttng_kernel_probe_location { + enum lttng_kernel_probe_location_type type; + kernel_probe_location_equal_cb equal; + kernel_probe_location_serialize_cb serialize; +}; + +struct lttng_kernel_probe_location_symbol { + struct lttng_kernel_probe_location parent; + char *symbol_name; + uint64_t offset; +}; + +struct lttng_kernel_probe_location_address { + struct lttng_kernel_probe_location parent; + uint64_t address; +}; + +LTTNG_HIDDEN +int lttng_kernel_probe_location_serialize( + const struct lttng_kernel_probe_location *location, + struct lttng_payload *payload); + +LTTNG_HIDDEN +ssize_t lttng_kernel_probe_location_create_from_payload( + struct lttng_payload_view *view, + struct lttng_kernel_probe_location **probe_location); + +LTTNG_HIDDEN +bool lttng_kernel_probe_location_is_equal( + const struct lttng_kernel_probe_location *a, + const struct lttng_kernel_probe_location *b); + +#endif /* LTTNG_KERNEL_PROBE_INTERNAL_H */ diff --git a/include/lttng/kernel-probe.h b/include/lttng/kernel-probe.h new file mode 100644 index 000000000..4536fd5ef --- /dev/null +++ b/include/lttng/kernel-probe.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_KERNEL_PROBE_H +#define LTTNG_KERNEL_PROBE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct lttng_kernel_probe_location; + +enum lttng_kernel_probe_location_status { + LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK = 0, + /* Invalid parameters provided. */ + LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID = -1, +}; + +enum lttng_kernel_probe_location_type { + LTTNG_KERNEL_PROBE_LOCATION_TYPE_UNKNOWN = -1, + /* Location derived from a symbol and an offset. */ + LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET = 0, + /* Location derived from an address. */ + LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS = 1, +}; + +/* + * Get the type of the kernel probe location. + */ +extern enum lttng_kernel_probe_location_type +lttng_kernel_probe_location_get_type( + const struct lttng_kernel_probe_location *location); + +/* + * Destroy the kernel probe location. + */ +extern void lttng_kernel_probe_location_destroy( + struct lttng_kernel_probe_location *location); + +/* + * Create a symbol derived probe location. + * On failure, NULL is returned. + */ +extern struct lttng_kernel_probe_location * +lttng_kernel_probe_location_symbol_create(const char *symbol_name, + uint64_t offset); + +/* + * Get the symbol name of a symbol derived probe location. + */ +extern const char *lttng_kernel_probe_location_symbol_get_name( + const struct lttng_kernel_probe_location *location); + +/* + * Get the offset of a symbol derived location. + */ +extern enum lttng_kernel_probe_location_status +lttng_kernel_probe_location_symbol_get_offset( + const struct lttng_kernel_probe_location *location, + uint64_t *offset); + +/* + * Create an address derived probe location. + * On failure, NULL is returned. + */ +extern struct lttng_kernel_probe_location * +lttng_kernel_probe_location_address_create(uint64_t address); + +/* + * Get the address of an address derived probe location. + */ +extern enum lttng_kernel_probe_location_status +lttng_kernel_probe_location_address_get_address( + const struct lttng_kernel_probe_location *location, + uint64_t *offset); + +#ifdef __cplusplus +} +#endif + +#endif /* LTTNG_KERNEL_PROBE_H */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 6ee43e48f..0905e899f 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -52,6 +52,7 @@ libcommon_la_SOURCES = \ fd-handle.c fd-handle.h \ fs-handle.c fs-handle.h fs-handle-internal.h \ futex.c futex.h \ + kernel-probe.c \ location.c \ mi-lttng.c mi-lttng.h \ notification.c \ diff --git a/src/common/kernel-probe.c b/src/common/kernel-probe.c new file mode 100644 index 000000000..1934a76b1 --- /dev/null +++ b/src/common/kernel-probe.c @@ -0,0 +1,564 @@ +/* + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include "lttng/lttng-error.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +int lttng_kernel_probe_location_address_serialize( + const struct lttng_kernel_probe_location *location, + struct lttng_payload *payload); + +static +int lttng_kernel_probe_location_symbol_serialize( + const struct lttng_kernel_probe_location *location, + struct lttng_payload *payload); + +static +bool lttng_kernel_probe_location_address_is_equal( + const struct lttng_kernel_probe_location *a, + const struct lttng_kernel_probe_location *b); + +static +bool lttng_kernel_probe_location_symbol_is_equal( + const struct lttng_kernel_probe_location *a, + const struct lttng_kernel_probe_location *b); + +enum lttng_kernel_probe_location_type lttng_kernel_probe_location_get_type( + const struct lttng_kernel_probe_location *location) +{ + return location ? location->type : + LTTNG_KERNEL_PROBE_LOCATION_TYPE_UNKNOWN; +} + +static +void lttng_kernel_probe_location_address_destroy( + struct lttng_kernel_probe_location *location) +{ + assert(location); + free(location); +} + +static +void lttng_kernel_probe_location_symbol_destroy( + struct lttng_kernel_probe_location *location) +{ + struct lttng_kernel_probe_location_symbol *location_symbol = NULL; + + assert(location); + + location_symbol = container_of(location, + struct lttng_kernel_probe_location_symbol, + parent); + + assert(location_symbol); + + free(location_symbol->symbol_name); + free(location); +} + +void lttng_kernel_probe_location_destroy( + struct lttng_kernel_probe_location *location) +{ + if (!location) { + return; + } + + switch (location->type) { + case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS: + lttng_kernel_probe_location_address_destroy(location); + break; + case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET: + lttng_kernel_probe_location_symbol_destroy(location); + break; + default: + abort(); + } +} + +struct lttng_kernel_probe_location * +lttng_kernel_probe_location_address_create(uint64_t address) +{ + struct lttng_kernel_probe_location *ret = NULL; + struct lttng_kernel_probe_location_address *location; + + location = zmalloc(sizeof(*location)); + if (!location) { + PERROR("Error allocating userspace probe location"); + goto end; + } + + location->address = address; + + ret = &location->parent; + ret->type = LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS; + ret->equal = lttng_kernel_probe_location_address_is_equal; + ret->serialize = lttng_kernel_probe_location_address_serialize; + +end: + return ret; +} + +struct lttng_kernel_probe_location * +lttng_kernel_probe_location_symbol_create(const char *symbol_name, + uint64_t offset) +{ + char *symbol_name_copy = NULL; + struct lttng_kernel_probe_location *ret = NULL; + struct lttng_kernel_probe_location_symbol *location; + + if (!symbol_name || strlen(symbol_name) >= LTTNG_SYMBOL_NAME_LEN) { + goto error; + } + + symbol_name_copy = strdup(symbol_name); + if (!symbol_name_copy) { + PERROR("Failed to copy symbol name '%s'", symbol_name); + goto error; + } + + location = zmalloc(sizeof(*location)); + if (!location) { + PERROR("Failed to allocate kernel symbol probe location"); + goto error; + } + + location->symbol_name = symbol_name_copy; + location->offset = offset; + + ret = &location->parent; + ret->type = LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET; + ret->equal = lttng_kernel_probe_location_symbol_is_equal; + ret->serialize = lttng_kernel_probe_location_symbol_serialize; + goto end; + +error: + free(symbol_name_copy); +end: + return ret; +} + +enum lttng_kernel_probe_location_status +lttng_kernel_probe_location_address_get_address( + const struct lttng_kernel_probe_location *location, + uint64_t *offset) +{ + enum lttng_kernel_probe_location_status ret = + LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK; + struct lttng_kernel_probe_location_address *address_location; + + assert(offset); + + if (!location || lttng_kernel_probe_location_get_type(location) != + LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS) { + ERR("Invalid argument(s) passed to '%s'", __FUNCTION__); + ret = LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID; + goto end; + } + + address_location = container_of(location, + struct lttng_kernel_probe_location_address, parent); + *offset = address_location->address; +end: + return ret; +} + +const char *lttng_kernel_probe_location_symbol_get_name( + const struct lttng_kernel_probe_location *location) +{ + const char *ret = NULL; + struct lttng_kernel_probe_location_symbol *symbol_location; + + if (!location || lttng_kernel_probe_location_get_type(location) != + LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET) { + ERR("Invalid argument(s) passed to '%s'", __FUNCTION__); + goto end; + } + + symbol_location = container_of(location, + struct lttng_kernel_probe_location_symbol, parent); + ret = symbol_location->symbol_name; +end: + return ret; +} + +enum lttng_kernel_probe_location_status +lttng_kernel_probe_location_symbol_get_offset( + const struct lttng_kernel_probe_location *location, + uint64_t *offset) +{ + enum lttng_kernel_probe_location_status ret = + LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK; + struct lttng_kernel_probe_location_symbol *symbol_location; + + assert(offset); + + if (!location || lttng_kernel_probe_location_get_type(location) != + LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET) { + ERR("Invalid argument(s) passed to '%s'", __FUNCTION__); + ret = LTTNG_KERNEL_PROBE_LOCATION_STATUS_INVALID; + goto end; + } + + symbol_location = container_of(location, + struct lttng_kernel_probe_location_symbol, parent); + *offset = symbol_location->offset; +end: + return ret; +} + +static +int lttng_kernel_probe_location_symbol_serialize( + const struct lttng_kernel_probe_location *location, + struct lttng_payload *payload) +{ + int ret; + size_t symbol_name_len; + size_t original_payload_size; + struct lttng_kernel_probe_location_symbol *location_symbol; + struct lttng_kernel_probe_location_symbol_comm location_symbol_comm; + + if (!location || !payload) { + ERR("Invalid argument(s) passed to '%s'", __FUNCTION__); + ret = -LTTNG_ERR_INVALID; + goto end; + } + + assert(lttng_kernel_probe_location_get_type(location) == + LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET); + + original_payload_size = payload->buffer.size; + location_symbol = container_of(location, + struct lttng_kernel_probe_location_symbol, parent); + + if (!location_symbol->symbol_name) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + symbol_name_len = strlen(location_symbol->symbol_name); + if (symbol_name_len == 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + location_symbol_comm.symbol_len = symbol_name_len + 1; + location_symbol_comm.offset = location_symbol->offset; + + ret = lttng_dynamic_buffer_append(&payload->buffer, + &location_symbol_comm, sizeof(location_symbol_comm)); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret = lttng_dynamic_buffer_append(&payload->buffer, + location_symbol->symbol_name, + location_symbol_comm.symbol_len); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret = (int) (payload->buffer.size - original_payload_size); +end: + return ret; +} + +static +int lttng_kernel_probe_location_address_serialize( + const struct lttng_kernel_probe_location *location, + struct lttng_payload *payload) +{ + int ret; + size_t original_payload_size; + struct lttng_kernel_probe_location_address *location_address; + struct lttng_kernel_probe_location_address_comm location_address_comm; + + assert(location); + assert(lttng_kernel_probe_location_get_type(location) == + LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS); + + original_payload_size = payload->buffer.size; + location_address = container_of(location, + struct lttng_kernel_probe_location_address, + parent); + + location_address_comm.address = location_address->address; + + ret = lttng_dynamic_buffer_append(&payload->buffer, + &location_address_comm, + sizeof(location_address_comm)); + if (ret) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret = (int) (payload->buffer.size - original_payload_size); +end: + return ret; +} + +LTTNG_HIDDEN +int lttng_kernel_probe_location_serialize( + const struct lttng_kernel_probe_location *location, + struct lttng_payload *payload) +{ + int ret; + size_t original_payload_size; + struct lttng_kernel_probe_location_comm location_generic_comm = {}; + + if (!location || !payload) { + ERR("Invalid argument(s) passed to '%s'", __FUNCTION__); + ret = -LTTNG_ERR_INVALID; + goto end; + } + + original_payload_size = payload->buffer.size; + location_generic_comm.type = (int8_t) location->type; + ret = lttng_dynamic_buffer_append(&payload->buffer, + &location_generic_comm, + sizeof(location_generic_comm)); + if (ret) { + goto end; + } + + ret = location->serialize(location, payload); + if (ret < 0) { + goto end; + } + + ret = (int) (payload->buffer.size - original_payload_size); +end: + return ret; +} + +static +int lttng_kernel_probe_location_symbol_create_from_payload( + struct lttng_payload_view *view, + struct lttng_kernel_probe_location **location) +{ + struct lttng_kernel_probe_location_symbol_comm *location_symbol_comm; + const char *symbol_name_src; + ssize_t ret = 0; + size_t expected_size; + + assert(location); + + if (view->buffer.size < sizeof(*location_symbol_comm)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + location_symbol_comm = + (typeof(location_symbol_comm)) view->buffer.data; + + expected_size = sizeof(*location_symbol_comm) + + location_symbol_comm->symbol_len; + + if (view->buffer.size < expected_size) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + symbol_name_src = view->buffer.data + sizeof(*location_symbol_comm); + + if (!lttng_buffer_view_contains_string(&view->buffer, symbol_name_src, + location_symbol_comm->symbol_len)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + *location = lttng_kernel_probe_location_symbol_create( + symbol_name_src, location_symbol_comm->offset); + if (!(*location)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret = (ssize_t) expected_size; +end: + return ret; +} + +static +ssize_t lttng_kernel_probe_location_address_create_from_payload( + struct lttng_payload_view *view, + struct lttng_kernel_probe_location **location) +{ + struct lttng_kernel_probe_location_address_comm *location_address_comm; + ssize_t ret = 0; + size_t expected_size; + + assert(location); + + expected_size = sizeof(*location_address_comm); + + if (view->buffer.size < expected_size) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + location_address_comm = + (typeof(location_address_comm)) view->buffer.data; + + *location = lttng_kernel_probe_location_address_create(location_address_comm->address); + if (!(*location)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret = (size_t) expected_size; +end: + return ret; +} + +LTTNG_HIDDEN +ssize_t lttng_kernel_probe_location_create_from_payload( + struct lttng_payload_view *view, + struct lttng_kernel_probe_location **location) +{ + struct lttng_kernel_probe_location_comm *probe_location_comm; + enum lttng_kernel_probe_location_type type; + ssize_t consumed = 0; + ssize_t ret; + + assert(view); + assert(location); + + if (view->buffer.size <= sizeof(*probe_location_comm)) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + probe_location_comm = (typeof(probe_location_comm)) view->buffer.data; + type = (enum lttng_kernel_probe_location_type) probe_location_comm->type; + consumed += sizeof(*probe_location_comm); + + switch (type) { + case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET: + { + struct lttng_payload_view location_view = + lttng_payload_view_from_view( + view, consumed, -1); + + ret = lttng_kernel_probe_location_symbol_create_from_payload( + &location_view, location); + break; + } + case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS: + { + struct lttng_payload_view location_view = + lttng_payload_view_from_view(view, consumed, -1); + + ret = lttng_kernel_probe_location_address_create_from_payload( + &location_view, location); + break; + } + default: + ret = -LTTNG_ERR_INVALID; + break; + } + + if (ret < 0) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ret += consumed; + +end: + return ret; +} + +static +bool lttng_kernel_probe_location_address_is_equal( + const struct lttng_kernel_probe_location *_a, + const struct lttng_kernel_probe_location *_b) +{ + bool is_equal = false; + struct lttng_kernel_probe_location_address *a, *b; + + a = container_of(_a, struct lttng_kernel_probe_location_address, + parent); + b = container_of(_b, struct lttng_kernel_probe_location_address, + parent); + + if (a->address != b->address) { + goto end; + } + + is_equal = true; + +end: + return is_equal; +} + +static +bool lttng_kernel_probe_location_symbol_is_equal( + const struct lttng_kernel_probe_location *_a, + const struct lttng_kernel_probe_location *_b) +{ + bool is_equal = false; + struct lttng_kernel_probe_location_symbol *a, *b; + + a = container_of(_a, struct lttng_kernel_probe_location_symbol, + parent); + b = container_of(_b, struct lttng_kernel_probe_location_symbol, + parent); + + assert(a->symbol_name); + assert(b->symbol_name); + if (strcmp(a->symbol_name, b->symbol_name)) { + goto end; + } + + if (a->offset != b->offset) { + goto end; + } + + is_equal = true; + +end: + return is_equal; +} + +LTTNG_HIDDEN +bool lttng_kernel_probe_location_is_equal( + const struct lttng_kernel_probe_location *a, + const struct lttng_kernel_probe_location *b) +{ + bool is_equal = false; + + if (!a || !b) { + goto end; + } + + if (a == b) { + is_equal = true; + goto end; + } + + if (a->type != b->type) { + goto end; + } + + is_equal = a->equal ? a->equal(a, b) : true; +end: + return is_equal; +} diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 338772068..ae086ce90 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -24,7 +24,8 @@ TESTS = test_kernel_data \ test_uuid \ test_buffer_view \ test_payload \ - test_unix_socket + test_unix_socket \ + test_kernel_probe LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la @@ -45,7 +46,8 @@ noinst_PROGRAMS = test_uri test_session test_kernel_data \ test_fd_tracker test_uuid \ test_buffer_view \ test_payload \ - test_unix_socket + test_unix_socket \ + test_kernel_probe if HAVE_LIBLTTNG_UST_CTL noinst_PROGRAMS += test_ust_data @@ -214,3 +216,7 @@ test_payload_LDADD = $(LIBTAP) $(LIBSESSIOND_COMM) $(LIBCOMMON) # unix socket test test_unix_socket_SOURCES = test_unix_socket.c 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) diff --git a/tests/unit/test_kernel_probe.c b/tests/unit/test_kernel_probe.c new file mode 100644 index 000000000..33ac1daf4 --- /dev/null +++ b/tests/unit/test_kernel_probe.c @@ -0,0 +1,169 @@ +/* + * Unit tests for the kernel probe location API. + * + * Copyright (C) 2020 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* For error.h */ +int lttng_opt_quiet = 1; +int lttng_opt_verbose; +int lttng_opt_mi; + +#define NUM_TESTS 24 + +static void test_kernel_probe_location_address(void) +{ + struct lttng_kernel_probe_location *location = NULL; + struct lttng_kernel_probe_location *location_from_buffer = NULL; + enum lttng_kernel_probe_location_status status; + enum lttng_kernel_probe_location_type type; + uint64_t address = 50, _address; + struct lttng_payload payload; + + diag("Testing kernel probe location address"); + + lttng_payload_init(&payload); + + location = lttng_kernel_probe_location_address_create(address); + ok(location, "Location object"); + + type = lttng_kernel_probe_location_get_type(location); + ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS == type, + "Location type got %d expected %d", type, + LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS); + + status = lttng_kernel_probe_location_address_get_address( + location, &_address); + ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting address"); + ok(address == _address, + "Address is equal. Got %" PRIu64 " expected %" PRIu64, + _address, address); + + ok(lttng_kernel_probe_location_serialize(location, &payload) > 0, + "Serializing"); + { + struct lttng_payload_view view = + lttng_payload_view_from_payload( + &payload, 0, -1); + ok(lttng_kernel_probe_location_create_from_payload( + &view, &location_from_buffer) > 0, + "Deserializing"); + } + + type = lttng_kernel_probe_location_get_type(location_from_buffer); + ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS == type, + "Location from buffer type got %d expected %d", type, + LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS); + + status = lttng_kernel_probe_location_address_get_address( + location_from_buffer, &_address); + ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting address"); + ok(address == _address, + "Address from buffer is equal. Got %" PRIu64 + " expected %" PRIu64, + _address, address); + + ok(lttng_kernel_probe_location_is_equal(location, location_from_buffer), + "serialized and from buffer are equal"); + + lttng_payload_reset(&payload); + lttng_kernel_probe_location_destroy(location); + lttng_kernel_probe_location_destroy(location_from_buffer); +} + +static void test_kernel_probe_location_symbol(void) +{ + struct lttng_kernel_probe_location *location = NULL; + struct lttng_kernel_probe_location *location_from_buffer = NULL; + enum lttng_kernel_probe_location_status status; + enum lttng_kernel_probe_location_type type; + uint64_t offset = 50, _offset; + const char *symbol = "Une_bonne", *_symbol; + struct lttng_payload payload; + + diag("Testing kernel probe location symbol"); + + lttng_payload_init(&payload); + + location = lttng_kernel_probe_location_symbol_create(symbol, offset); + ok(location, "Location object"); + + type = lttng_kernel_probe_location_get_type(location); + ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET == type, + "Location type got %d expected %d", type, + LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET); + + _symbol = lttng_kernel_probe_location_symbol_get_name(location); + ok(_symbol, "Getting symbol name"); + ok(!strncmp(symbol, _symbol, strlen(symbol)), + "Symbol name is equal. Got %s, expected %s", _symbol, + symbol); + + status = lttng_kernel_probe_location_symbol_get_offset( + location, &_offset); + ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting offset"); + ok(offset == _offset, + "Offset is equal. Got %" PRIu64 " expected %" PRIu64, + _offset, offset); + + ok(lttng_kernel_probe_location_serialize(location, &payload) > 0, + "Serializing"); + { + struct lttng_payload_view view = + lttng_payload_view_from_payload( + &payload, 0, -1); + ok(lttng_kernel_probe_location_create_from_payload( + &view, &location_from_buffer) > 0, + "Deserializing"); + } + + type = lttng_kernel_probe_location_get_type(location_from_buffer); + ok(LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET == type, + "Location from buffer type got %d expected %d", type, + LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET); + + _symbol = lttng_kernel_probe_location_symbol_get_name( + location_from_buffer); + ok(_symbol, "Getting symbol name"); + ok(!strncmp(symbol, _symbol, strlen(symbol)), + "Symbol name is equal. Got %s, expected %s", _symbol, + symbol); + + status = lttng_kernel_probe_location_symbol_get_offset( + location_from_buffer, &_offset); + ok(status == LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK, "Getting offset"); + ok(offset == _offset, + "Offset is equal. Got %" PRIu64 " expected %" PRIu64, + _offset, offset); + + ok(lttng_kernel_probe_location_is_equal(location, location_from_buffer), + "serialized and from buffer are equal"); + + lttng_payload_reset(&payload); + lttng_kernel_probe_location_destroy(location); + lttng_kernel_probe_location_destroy(location_from_buffer); +} + +int main(int argc, const char *argv[]) +{ + plan_tests(NUM_TESTS); + test_kernel_probe_location_address(); + test_kernel_probe_location_symbol(); + return exit_status(); +} -- 2.34.1